Commit bdbc5b2626823c8715e310f09fd9b3bfd9751b05
1 parent
e52f0b7d
1. 阿里云 sms client 增加查询模板的封装
2. 重构阿里云 sms client 客户端,增加 invoke 基础方法
Showing
8 changed files
with
161 additions
and
22 deletions
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java
| ... | ... | @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.sms.core.client; |
| 3 | 3 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 4 | 4 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 5 | 5 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 6 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; | |
| 6 | 7 | |
| 7 | 8 | import java.util.List; |
| 8 | 9 | |
| ... | ... | @@ -41,4 +42,12 @@ public interface SmsClient { |
| 41 | 42 | */ |
| 42 | 43 | List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable; |
| 43 | 44 | |
| 45 | + /** | |
| 46 | + * 查询指定的短信模板 | |
| 47 | + * | |
| 48 | + * @param apiTemplateId 短信 API 的模板编号 | |
| 49 | + * @return 短信模板 | |
| 50 | + */ | |
| 51 | + SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId); | |
| 52 | + | |
| 44 | 53 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.framework.sms.core.client.dto; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 短信模板 Response DTO | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +@Data | |
| 12 | +public class SmsTemplateRespDTO { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 模板编号 | |
| 16 | + */ | |
| 17 | + private String id; | |
| 18 | + /** | |
| 19 | + * 短信内容 | |
| 20 | + */ | |
| 21 | + private String content; | |
| 22 | + /** | |
| 23 | + * 审核状态 | |
| 24 | + * | |
| 25 | + * 枚举 {@link SmsTemplateAuditStatusEnum} | |
| 26 | + */ | |
| 27 | + private Integer auditStatus; | |
| 28 | + /** | |
| 29 | + * 审核未通过的理由 | |
| 30 | + */ | |
| 31 | + private String auditReason; | |
| 32 | + | |
| 33 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; |
| 6 | 6 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 7 | 7 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 8 | 8 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 9 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; | |
| 9 | 10 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 10 | 11 | import lombok.extern.slf4j.Slf4j; |
| 11 | 12 | |
| ... | ... | @@ -77,7 +78,7 @@ public abstract class AbstractSmsClient implements SmsClient { |
| 77 | 78 | result = doSendSms(logId, mobile, apiTemplateId, templateParams); |
| 78 | 79 | } catch (Throwable ex) { |
| 79 | 80 | // 打印异常日志 |
| 80 | - log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", | |
| 81 | + log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", | |
| 81 | 82 | logId, mobile, apiTemplateId, templateParams, ex); |
| 82 | 83 | // 封装返回 |
| 83 | 84 | return SmsCommonResult.error(ex); |
| ... | ... | @@ -101,4 +102,21 @@ public abstract class AbstractSmsClient implements SmsClient { |
| 101 | 102 | |
| 102 | 103 | protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable; |
| 103 | 104 | |
| 105 | + @Override | |
| 106 | + public SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId) { | |
| 107 | + // 执行短信发送 | |
| 108 | + SmsCommonResult<SmsTemplateRespDTO> result; | |
| 109 | + try { | |
| 110 | + result = doGetSmsTemplate(apiTemplateId); | |
| 111 | + } catch (Throwable ex) { | |
| 112 | + // 打印异常日志 | |
| 113 | + log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex); | |
| 114 | + // 封装返回 | |
| 115 | + return SmsCommonResult.error(ex); | |
| 116 | + } | |
| 117 | + return result; | |
| 118 | + } | |
| 119 | + | |
| 120 | + protected abstract SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable; | |
| 121 | + | |
| 104 | 122 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java
| 1 | 1 | package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.lang.Assert; |
| 4 | +import cn.hutool.core.util.ReflectUtil; | |
| 4 | 5 | import cn.hutool.core.util.StrUtil; |
| 5 | 6 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 6 | 7 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 7 | 8 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 8 | 9 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 10 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; | |
| 9 | 11 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; |
| 12 | +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; | |
| 10 | 13 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 11 | 14 | import cn.iocoder.dashboard.util.collection.MapUtils; |
| 12 | 15 | import cn.iocoder.dashboard.util.json.JsonUtils; |
| 16 | +import com.aliyuncs.AcsRequest; | |
| 17 | +import com.aliyuncs.AcsResponse; | |
| 13 | 18 | import com.aliyuncs.DefaultAcsClient; |
| 14 | 19 | import com.aliyuncs.IAcsClient; |
| 20 | +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; | |
| 15 | 21 | import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; |
| 16 | -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; | |
| 17 | 22 | import com.aliyuncs.exceptions.ClientException; |
| 18 | -import com.aliyuncs.http.MethodType; | |
| 19 | 23 | import com.aliyuncs.profile.DefaultProfile; |
| 20 | 24 | import com.aliyuncs.profile.IClientProfile; |
| 21 | 25 | import com.fasterxml.jackson.annotation.JsonFormat; |
| ... | ... | @@ -25,6 +29,8 @@ import lombok.extern.slf4j.Slf4j; |
| 25 | 29 | |
| 26 | 30 | import java.util.Date; |
| 27 | 31 | import java.util.List; |
| 32 | +import java.util.Objects; | |
| 33 | +import java.util.function.Function; | |
| 28 | 34 | import java.util.stream.Collectors; |
| 29 | 35 | |
| 30 | 36 | import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| ... | ... | @@ -66,25 +72,13 @@ public class AliyunSmsClient extends AbstractSmsClient { |
| 66 | 72 | String apiTemplateId, List<KeyValue<String, Object>> templateParams) { |
| 67 | 73 | // 构建参数 |
| 68 | 74 | SendSmsRequest request = new SendSmsRequest(); |
| 69 | - request.setSysMethod(MethodType.POST); | |
| 70 | 75 | request.setPhoneNumbers(mobile); |
| 71 | 76 | request.setSignName(properties.getSignature()); |
| 72 | 77 | request.setTemplateCode(apiTemplateId); |
| 73 | 78 | request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); |
| 74 | 79 | request.setOutId(String.valueOf(sendLogId)); |
| 75 | - | |
| 76 | - try { | |
| 77 | - // 执行发送 | |
| 78 | - SendSmsResponse sendResult = acsClient.getAcsResponse(request); | |
| 79 | - // 解析结果 | |
| 80 | - SmsSendRespDTO data = null; | |
| 81 | - if (sendResult.getBizId() != null) { | |
| 82 | - data = new SmsSendRespDTO().setSerialNo(sendResult.getBizId()); | |
| 83 | - } | |
| 84 | - return SmsCommonResult.build(sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), data, codeMapping); | |
| 85 | - } catch (ClientException ex) { | |
| 86 | - return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); | |
| 87 | - } | |
| 80 | + // 执行请求 | |
| 81 | + return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); | |
| 88 | 82 | } |
| 89 | 83 | |
| 90 | 84 | private static String formatResultMsg(ClientException ex) { |
| ... | ... | @@ -107,6 +101,48 @@ public class AliyunSmsClient extends AbstractSmsClient { |
| 107 | 101 | }).collect(Collectors.toList()); |
| 108 | 102 | } |
| 109 | 103 | |
| 104 | + @Override | |
| 105 | + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) { | |
| 106 | + // 构建参数 | |
| 107 | + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); | |
| 108 | + request.setTemplateCode(apiTemplateId); | |
| 109 | + // 执行请求 | |
| 110 | + return invoke(request, response -> { | |
| 111 | + SmsTemplateRespDTO data = new SmsTemplateRespDTO(); | |
| 112 | + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); | |
| 113 | + data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason()); | |
| 114 | + return data; | |
| 115 | + }); | |
| 116 | + } | |
| 117 | + | |
| 118 | + private Integer convertSmsTemplateAuditStatus(Integer templateStatus) { | |
| 119 | + switch (templateStatus) { | |
| 120 | + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); | |
| 121 | + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); | |
| 122 | + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); | |
| 123 | + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); | |
| 124 | + } | |
| 125 | + } | |
| 126 | + | |
| 127 | + private <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> consumer) { | |
| 128 | + try { | |
| 129 | + // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 | |
| 130 | + T sendResult = acsClient.getAcsResponse(request); | |
| 131 | + String code = (String) ReflectUtil.getFieldValue(sendResult, "code"); | |
| 132 | + String message = (String) ReflectUtil.getFieldValue(sendResult, "message"); | |
| 133 | + String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId"); | |
| 134 | + // 解析结果 | |
| 135 | + R data = null; | |
| 136 | + if (Objects.equals(code, "OK")) { // 请求成功的情况下 | |
| 137 | + data = consumer.apply(sendResult); | |
| 138 | + } | |
| 139 | + // 拼接结果 | |
| 140 | + return SmsCommonResult.build(code, message, requestId, data, codeMapping); | |
| 141 | + } catch (ClientException ex) { | |
| 142 | + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + | |
| 110 | 146 | /** |
| 111 | 147 | * 短信接收状态 |
| 112 | 148 | * | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java
| ... | ... | @@ -21,6 +21,7 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping { |
| 21 | 21 | case "isp.RAM_PERMISSION_DENY": return SMS_CHANNEL_PERMISSION_DENY; |
| 22 | 22 | case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR; |
| 23 | 23 | case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_LIMIT_CONTROL; |
| 24 | + case "isv.SMS_TEMPLATE_ILLEGAL": return SMS_TEMPLATE_NOT_EXISTS; | |
| 24 | 25 | } |
| 25 | 26 | return SMS_UNKNOWN; |
| 26 | 27 | } | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java
| ... | ... | @@ -8,6 +8,7 @@ import cn.iocoder.dashboard.common.core.KeyValue; |
| 8 | 8 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 9 | 9 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 10 | 10 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 11 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; | |
| 11 | 12 | import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; |
| 12 | 13 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 13 | 14 | import cn.iocoder.dashboard.util.json.JsonUtils; |
| ... | ... | @@ -114,6 +115,11 @@ public class YunpianSmsClient extends AbstractSmsClient { |
| 114 | 115 | }).collect(Collectors.toList()); |
| 115 | 116 | } |
| 116 | 117 | |
| 118 | + @Override | |
| 119 | + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable { | |
| 120 | + return null; | |
| 121 | + } | |
| 122 | + | |
| 117 | 123 | /** |
| 118 | 124 | * 短信接收状态 |
| 119 | 125 | * | ... | ... |
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.framework.sms.core.enums; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 短信模板的审核状态枚举 | |
| 8 | + * | |
| 9 | + * @author 芋道源码 | |
| 10 | + */ | |
| 11 | +@AllArgsConstructor | |
| 12 | +@Getter | |
| 13 | +public enum SmsTemplateAuditStatusEnum { | |
| 14 | + | |
| 15 | + CHECKING(1), | |
| 16 | + SUCCESS(2), | |
| 17 | + FAIL(3); | |
| 18 | + | |
| 19 | + private final Integer status; | |
| 20 | + | |
| 21 | +} | ... | ... |
src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java
| ... | ... | @@ -3,8 +3,10 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; |
| 3 | 3 | import cn.iocoder.dashboard.common.core.KeyValue; |
| 4 | 4 | import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; |
| 5 | 5 | import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; |
| 6 | +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; | |
| 6 | 7 | import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; |
| 7 | 8 | import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; |
| 9 | +import org.junit.jupiter.api.BeforeAll; | |
| 8 | 10 | import org.junit.jupiter.api.Test; |
| 9 | 11 | |
| 10 | 12 | import java.util.ArrayList; |
| ... | ... | @@ -15,8 +17,10 @@ import java.util.List; |
| 15 | 17 | */ |
| 16 | 18 | public class AliyunSmsClientIntegrationTest { |
| 17 | 19 | |
| 18 | - @Test | |
| 19 | - public void testSend() { | |
| 20 | + private static AliyunSmsClient smsClient; | |
| 21 | + | |
| 22 | + @BeforeAll | |
| 23 | + public static void before() { | |
| 20 | 24 | // 创建配置类 |
| 21 | 25 | SmsChannelProperties properties = new SmsChannelProperties(); |
| 22 | 26 | properties.setId(1L); |
| ... | ... | @@ -25,14 +29,25 @@ public class AliyunSmsClientIntegrationTest { |
| 25 | 29 | properties.setApiKey(System.getenv("ALIYUN_ACCESS_KEY")); |
| 26 | 30 | properties.setApiSecret(System.getenv("ALIYUN_SECRET_KEY")); |
| 27 | 31 | // 创建客户端 |
| 28 | - AliyunSmsClient smsClient = new AliyunSmsClient(properties); | |
| 32 | + smsClient = new AliyunSmsClient(properties); | |
| 29 | 33 | smsClient.init(); |
| 30 | - // 发送短信 | |
| 34 | + } | |
| 35 | + | |
| 36 | + @Test | |
| 37 | + public void testSendSms() { | |
| 31 | 38 | List<KeyValue<String, Object>> templateParams = new ArrayList<>(); |
| 32 | 39 | templateParams.add(new KeyValue<>("code", "1024")); |
| 33 | 40 | // templateParams.put("operation", "嘿嘿"); |
| 34 | 41 | // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); |
| 35 | - SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", "SMS_207945135", templateParams); | |
| 42 | + SmsCommonResult<SmsSendRespDTO> result = smsClient.sendSms(1L, "15601691399", | |
| 43 | + "SMS_207945135", templateParams); | |
| 44 | + System.out.println(result); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Test | |
| 48 | + public void testGetSmsTemplate() { | |
| 49 | + String apiTemplateId = "SMS_2079451351"; | |
| 50 | + SmsCommonResult<SmsTemplateRespDTO> result = smsClient.getSmsTemplate(apiTemplateId); | |
| 36 | 51 | System.out.println(result); |
| 37 | 52 | } |
| 38 | 53 | ... | ... |