Commit bdbc5b2626823c8715e310f09fd9b3bfd9751b05

Authored by YunaiV
1 parent e52f0b7d

1. 阿里云 sms client 增加查询模板的封装

2. 重构阿里云 sms client 客户端,增加 invoke 基础方法
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  
... ...