Commit be20178f1207c76391dc45aebea0c001842e93ce

Authored by dhb52
2 parents edea17e7 41c324ac

Merge remote-tracking branch 'upstream/master'

Showing 27 changed files with 312 additions and 840 deletions
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsClient.java
@@ -31,8 +31,8 @@ public interface SmsClient { @@ -31,8 +31,8 @@ public interface SmsClient {
31 * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 31 * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
32 * @return 短信发送结果 32 * @return 短信发送结果
33 */ 33 */
34 - SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId,  
35 - List<KeyValue<String, Object>> templateParams); 34 + SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId,
  35 + List<KeyValue<String, Object>> templateParams) throws Throwable;
36 36
37 /** 37 /**
38 * 解析接收短信的接收结果 38 * 解析接收短信的接收结果
@@ -49,6 +49,6 @@ public interface SmsClient { @@ -49,6 +49,6 @@ public interface SmsClient {
49 * @param apiTemplateId 短信 API 的模板编号 49 * @param apiTemplateId 短信 API 的模板编号
50 * @return 短信模板 50 * @return 短信模板
51 */ 51 */
52 - SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId); 52 + SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable;
53 53
54 } 54 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
4 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
5 -  
6 -import java.util.function.Function;  
7 -  
8 -/**  
9 - * 将 API 的错误码,转换为通用的错误码  
10 - *  
11 - * @see SmsCommonResult  
12 - * @see SmsFrameworkErrorCodeConstants  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -public interface SmsCodeMapping extends Function<String, ErrorCode> {  
17 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCommonResult.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client;  
2 -  
3 -import cn.hutool.core.exceptions.ExceptionUtil;  
4 -import cn.hutool.core.lang.Assert;  
5 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
6 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
7 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
8 -import lombok.Data;  
9 -import lombok.EqualsAndHashCode;  
10 -import lombok.ToString;  
11 -  
12 -/**  
13 - * 短信的 CommonResult 拓展类  
14 - *  
15 - * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段  
16 - *  
17 - * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段  
18 - *  
19 - * @author 芋道源码  
20 - */  
21 -@Data  
22 -@EqualsAndHashCode(callSuper = true)  
23 -@ToString(callSuper = true)  
24 -public class SmsCommonResult<T> extends CommonResult<T> {  
25 -  
26 - /**  
27 - * API 返回错误码  
28 - *  
29 - * 由于第三方的错误码可能是字符串,所以使用 String 类型  
30 - */  
31 - private String apiCode;  
32 - /**  
33 - * API 返回提示  
34 - */  
35 - private String apiMsg;  
36 -  
37 - /**  
38 - * API 请求编号  
39 - */  
40 - private String apiRequestId;  
41 -  
42 - private SmsCommonResult() {  
43 - }  
44 -  
45 - public static <T> SmsCommonResult<T> build(String apiCode, String apiMsg, String apiRequestId,  
46 - T data, SmsCodeMapping codeMapping) {  
47 - Assert.notNull(codeMapping, "参数 codeMapping 不能为空");  
48 - SmsCommonResult<T> result = new SmsCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId);  
49 - result.setData(data);  
50 - // 翻译错误码  
51 - if (codeMapping != null) {  
52 - ErrorCode errorCode = codeMapping.apply(apiCode);  
53 - if (errorCode == null) {  
54 - errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;  
55 - }  
56 - result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg());  
57 - }  
58 - return result;  
59 - }  
60 -  
61 - public static <T> SmsCommonResult<T> error(Throwable ex) {  
62 - SmsCommonResult<T> result = new SmsCommonResult<>();  
63 - result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode());  
64 - result.setMsg(ExceptionUtil.getRootCauseMessage(ex));  
65 - return result;  
66 - }  
67 -  
68 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/dto/SmsSendRespDTO.java
@@ -11,8 +11,33 @@ import lombok.Data; @@ -11,8 +11,33 @@ import lombok.Data;
11 public class SmsSendRespDTO { 11 public class SmsSendRespDTO {
12 12
13 /** 13 /**
  14 + * 是否成功
  15 + */
  16 + private Boolean success;
  17 +
  18 + /**
  19 + * API 请求编号
  20 + */
  21 + private String apiRequestId;
  22 +
  23 + // ==================== 成功时字段 ====================
  24 +
  25 + /**
14 * 短信 API 发送返回的序号 26 * 短信 API 发送返回的序号
15 */ 27 */
16 private String serialNo; 28 private String serialNo;
17 29
  30 + // ==================== 失败时字段 ====================
  31 +
  32 + /**
  33 + * API 返回错误码
  34 + *
  35 + * 由于第三方的错误码可能是字符串,所以使用 String 类型
  36 + */
  37 + private String apiCode;
  38 + /**
  39 + * API 返回提示
  40 + */
  41 + private String apiMsg;
  42 +
18 } 43 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/AbstractSmsClient.java
1 package cn.iocoder.yudao.framework.sms.core.client.impl; 1 package cn.iocoder.yudao.framework.sms.core.client.impl;
2 2
3 -import cn.iocoder.yudao.framework.common.core.KeyValue;  
4 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 3 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
5 -import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;  
6 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
7 -import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;  
8 -import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;  
9 -import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;  
10 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; 4 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
11 import lombok.extern.slf4j.Slf4j; 5 import lombok.extern.slf4j.Slf4j;
12 6
13 -import java.util.List;  
14 -  
15 /** 7 /**
16 * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码 8 * 短信客户端的抽象类,提供模板方法,减少子类的冗余代码
17 * 9 *
@@ -25,14 +17,9 @@ public abstract class AbstractSmsClient implements SmsClient { @@ -25,14 +17,9 @@ public abstract class AbstractSmsClient implements SmsClient {
25 * 短信渠道配置 17 * 短信渠道配置
26 */ 18 */
27 protected volatile SmsChannelProperties properties; 19 protected volatile SmsChannelProperties properties;
28 - /**  
29 - * 错误码枚举类  
30 - */  
31 - protected final SmsCodeMapping codeMapping;  
32 20
33 - public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) {  
34 - this.properties = prepareProperties(properties);  
35 - this.codeMapping = codeMapping; 21 + public AbstractSmsClient(SmsChannelProperties properties) {
  22 + this.properties = properties;
36 } 23 }
37 24
38 /** 25 /**
@@ -54,74 +41,13 @@ public abstract class AbstractSmsClient implements SmsClient { @@ -54,74 +41,13 @@ public abstract class AbstractSmsClient implements SmsClient {
54 return; 41 return;
55 } 42 }
56 log.info("[refresh][配置({})发生变化,重新初始化]", properties); 43 log.info("[refresh][配置({})发生变化,重新初始化]", properties);
57 - this.properties = prepareProperties(properties);  
58 // 初始化 44 // 初始化
59 this.init(); 45 this.init();
60 } 46 }
61 47
62 - /**  
63 - * 在赋值给{@link this#properties}前,子类可根据需要预处理短信渠道配置  
64 - *  
65 - * @param properties 数据库中存储的短信渠道配置  
66 - * @return 满足子类实现的短信渠道配置  
67 - */  
68 - protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {  
69 - return properties;  
70 - }  
71 -  
72 @Override 48 @Override
73 public Long getId() { 49 public Long getId() {
74 return properties.getId(); 50 return properties.getId();
75 } 51 }
76 52
77 - @Override  
78 - public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile,  
79 - String apiTemplateId, List<KeyValue<String, Object>> templateParams) {  
80 - // 执行短信发送  
81 - SmsCommonResult<SmsSendRespDTO> result;  
82 - try {  
83 - result = doSendSms(logId, mobile, apiTemplateId, templateParams);  
84 - } catch (Throwable ex) {  
85 - // 打印异常日志  
86 - log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",  
87 - logId, mobile, apiTemplateId, templateParams, ex);  
88 - // 封装返回  
89 - return SmsCommonResult.error(ex);  
90 - }  
91 - return result;  
92 - }  
93 -  
94 - protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,  
95 - String apiTemplateId, List<KeyValue<String, Object>> templateParams)  
96 - throws Throwable;  
97 -  
98 - @Override  
99 - public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {  
100 - try {  
101 - return doParseSmsReceiveStatus(text);  
102 - } catch (Throwable ex) {  
103 - log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex);  
104 - throw ex;  
105 - }  
106 - }  
107 -  
108 - protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;  
109 -  
110 - @Override  
111 - public SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId) {  
112 - // 执行短信发送  
113 - SmsCommonResult<SmsTemplateRespDTO> result;  
114 - try {  
115 - result = doGetSmsTemplate(apiTemplateId);  
116 - } catch (Throwable ex) {  
117 - // 打印异常日志  
118 - log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex);  
119 - // 封装返回  
120 - return SmsCommonResult.error(ex);  
121 - }  
122 - return result;  
123 - }  
124 -  
125 - protected abstract SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable;  
126 -  
127 } 53 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java
1 package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; 1 package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
2 2
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 -import cn.hutool.core.util.ReflectUtil;  
5 -import cn.hutool.core.util.StrUtil;  
6 import cn.iocoder.yudao.framework.common.core.KeyValue; 4 import cn.iocoder.yudao.framework.common.core.KeyValue;
7 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; 5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 7 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
11 import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; 10 import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
12 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; 11 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
13 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; 12 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
14 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
15 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
16 -import com.aliyuncs.AcsRequest;  
17 -import com.aliyuncs.AcsResponse;  
18 import com.aliyuncs.DefaultAcsClient; 13 import com.aliyuncs.DefaultAcsClient;
19 import com.aliyuncs.IAcsClient; 14 import com.aliyuncs.IAcsClient;
20 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; 15 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
  16 +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
21 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; 17 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
22 -import com.aliyuncs.exceptions.ClientException; 18 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
23 import com.aliyuncs.profile.DefaultProfile; 19 import com.aliyuncs.profile.DefaultProfile;
24 import com.aliyuncs.profile.IClientProfile; 20 import com.aliyuncs.profile.IClientProfile;
25 import com.fasterxml.jackson.annotation.JsonFormat; 21 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -31,9 +27,8 @@ import lombok.extern.slf4j.Slf4j; @@ -31,9 +27,8 @@ import lombok.extern.slf4j.Slf4j;
31 import java.time.LocalDateTime; 27 import java.time.LocalDateTime;
32 import java.util.List; 28 import java.util.List;
33 import java.util.Objects; 29 import java.util.Objects;
34 -import java.util.function.Function;  
35 -import java.util.stream.Collectors;  
36 30
  31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
37 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 32 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
38 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; 33 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
39 34
@@ -47,6 +42,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE @@ -47,6 +42,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE
47 public class AliyunSmsClient extends AbstractSmsClient { 42 public class AliyunSmsClient extends AbstractSmsClient {
48 43
49 /** 44 /**
  45 + * 调用成功 code
  46 + */
  47 + public static final String API_CODE_SUCCESS = "OK";
  48 +
  49 + /**
50 * REGION, 使用杭州 50 * REGION, 使用杭州
51 */ 51 */
52 private static final String ENDPOINT = "cn-hangzhou"; 52 private static final String ENDPOINT = "cn-hangzhou";
@@ -57,7 +57,7 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -57,7 +57,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
57 private volatile IAcsClient client; 57 private volatile IAcsClient client;
58 58
59 public AliyunSmsClient(SmsChannelProperties properties) { 59 public AliyunSmsClient(SmsChannelProperties properties) {
60 - super(properties, new AliyunSmsCodeMapping()); 60 + super(properties);
61 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); 61 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
62 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); 62 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
63 } 63 }
@@ -69,9 +69,9 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -69,9 +69,9 @@ public class AliyunSmsClient extends AbstractSmsClient {
69 } 69 }
70 70
71 @Override 71 @Override
72 - protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,  
73 - String apiTemplateId, List<KeyValue<String, Object>> templateParams) {  
74 - // 构建参数 72 + public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
  73 + List<KeyValue<String, Object>> templateParams) throws Throwable {
  74 + // 构建请求
75 SendSmsRequest request = new SendSmsRequest(); 75 SendSmsRequest request = new SendSmsRequest();
76 request.setPhoneNumbers(mobile); 76 request.setPhoneNumbers(mobile);
77 request.setSignName(properties.getSignature()); 77 request.setSignName(properties.getSignature());
@@ -79,34 +79,32 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -79,34 +79,32 @@ public class AliyunSmsClient extends AbstractSmsClient {
79 request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); 79 request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
80 request.setOutId(String.valueOf(sendLogId)); 80 request.setOutId(String.valueOf(sendLogId));
81 // 执行请求 81 // 执行请求
82 - return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); 82 + SendSmsResponse response = client.getAcsResponse(request);
  83 + return new SmsSendRespDTO().setSuccess(Objects.equals(response.getCode(), API_CODE_SUCCESS)).setSerialNo(response.getBizId())
  84 + .setApiRequestId(response.getRequestId()).setApiCode(response.getCode()).setApiMsg(response.getMessage());
83 } 85 }
84 86
85 @Override 87 @Override
86 - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { 88 + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
87 List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); 89 List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
88 - return statuses.stream().map(status -> {  
89 - SmsReceiveRespDTO resp = new SmsReceiveRespDTO();  
90 - resp.setSuccess(status.getSuccess());  
91 - resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg());  
92 - resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime());  
93 - resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()));  
94 - return resp;  
95 - }).collect(Collectors.toList()); 90 + return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(status.getSuccess())
  91 + .setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg())
  92 + .setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime())
  93 + .setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())));
96 } 94 }
97 95
98 @Override 96 @Override
99 - protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {  
100 - // 构建参数 97 + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
  98 + // 构建请求
101 QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); 99 QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
102 request.setTemplateCode(apiTemplateId); 100 request.setTemplateCode(apiTemplateId);
103 // 执行请求 101 // 执行请求
104 - return invoke(request, response -> {  
105 - SmsTemplateRespDTO data = new SmsTemplateRespDTO();  
106 - data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());  
107 - data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());  
108 - return data;  
109 - }); 102 + QuerySmsTemplateResponse response = client.getAcsResponse(request);
  103 + if (response.getTemplateStatus() == null) {
  104 + return null;
  105 + }
  106 + return new SmsTemplateRespDTO().setId(response.getTemplateCode()).setContent(response.getTemplateContent())
  107 + .setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
110 } 108 }
111 109
112 @VisibleForTesting 110 @VisibleForTesting
@@ -119,37 +117,10 @@ public class AliyunSmsClient extends AbstractSmsClient { @@ -119,37 +117,10 @@ public class AliyunSmsClient extends AbstractSmsClient {
119 } 117 }
120 } 118 }
121 119
122 - @VisibleForTesting  
123 - <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) {  
124 - try {  
125 - // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射  
126 - T sendResult = client.getAcsResponse(request);  
127 - String code = (String) ReflectUtil.getFieldValue(sendResult, "code");  
128 - String message = (String) ReflectUtil.getFieldValue(sendResult, "message");  
129 - String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId");  
130 - // 解析结果  
131 - R data = null;  
132 - if (Objects.equals(code, "OK")) { // 请求成功的情况下  
133 - data = responseConsumer.apply(sendResult);  
134 - }  
135 - // 拼接结果  
136 - return SmsCommonResult.build(code, message, requestId, data, codeMapping);  
137 - } catch (ClientException ex) {  
138 - return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping);  
139 - }  
140 - }  
141 -  
142 - private static String formatResultMsg(ClientException ex) {  
143 - if (StrUtil.isEmpty(ex.getErrorDescription())) {  
144 - return ex.getErrMsg();  
145 - }  
146 - return ex.getErrMsg() + " => " + ex.getErrorDescription();  
147 - }  
148 -  
149 /** 120 /**
150 * 短信接收状态 121 * 短信接收状态
151 * 122 *
152 - * 参见 https://help.aliyun.com/document_detail/101867.html 文档 123 + * 参见 <a href="https://help.aliyun.com/document_detail/101867.html">文档</a>
153 * 124 *
154 * @author 芋道源码 125 * @author 芋道源码
155 */ 126 */
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
4 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
5 -import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;  
6 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
7 -  
8 -/**  
9 - * 阿里云的 SmsCodeMapping 实现类  
10 - *  
11 - * 参见 https://help.aliyun.com/document_detail/101346.htm 文档  
12 - *  
13 - * @author 芋道源码  
14 - */  
15 -public class AliyunSmsCodeMapping implements SmsCodeMapping {  
16 -  
17 - @Override  
18 - public ErrorCode apply(String apiCode) {  
19 - switch (apiCode) {  
20 - case "OK": return GlobalErrorCodeConstants.SUCCESS;  
21 - case "isv.ACCOUNT_NOT_EXISTS":  
22 - case "isv.ACCOUNT_ABNORMAL":  
23 - case "MissingAccessKeyId": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;  
24 - case "isp.RAM_PERMISSION_DENY": return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;  
25 - case "isv.INVALID_JSON_PARAM":  
26 - case "isv.INVALID_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;  
27 - case "isv.BUSINESS_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;  
28 - case "isv.DAY_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL;  
29 - case "isv.SMS_CONTENT_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;  
30 - case "isv.SMS_TEMPLATE_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;  
31 - case "isv.SMS_SIGNATURE_ILLEGAL":  
32 - case "isv.SIGN_NAME_ILLEGAL":  
33 - case "isv.SMS_SIGN_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;  
34 - case "isv.AMOUNT_NOT_ENOUGH":  
35 - case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;  
36 - case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID;  
37 - case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;  
38 - default: return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;  
39 - }  
40 - }  
41 -  
42 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.debug;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
4 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
5 -import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;  
6 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
7 -  
8 -import java.util.Objects;  
9 -  
10 -/**  
11 - * 钉钉的 SmsCodeMapping 实现类  
12 - *  
13 - * @author 芋道源码  
14 - */  
15 -public class DebugDingTalkCodeMapping implements SmsCodeMapping {  
16 -  
17 - @Override  
18 - public ErrorCode apply(String apiCode) {  
19 - return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;  
20 - }  
21 -  
22 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java
@@ -8,19 +8,19 @@ import cn.hutool.crypto.digest.DigestUtil; @@ -8,19 +8,19 @@ import cn.hutool.crypto.digest.DigestUtil;
8 import cn.hutool.crypto.digest.HmacAlgorithm; 8 import cn.hutool.crypto.digest.HmacAlgorithm;
9 import cn.hutool.http.HttpUtil; 9 import cn.hutool.http.HttpUtil;
10 import cn.iocoder.yudao.framework.common.core.KeyValue; 10 import cn.iocoder.yudao.framework.common.core.KeyValue;
11 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; 11 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  12 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
12 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 13 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
13 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 14 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
14 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 15 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
15 import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; 16 import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
16 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; 17 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
17 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; 18 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
18 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
19 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
20 19
21 import java.util.HashMap; 20 import java.util.HashMap;
22 import java.util.List; 21 import java.util.List;
23 import java.util.Map; 22 import java.util.Map;
  23 +import java.util.Objects;
24 24
25 /** 25 /**
26 * 基于钉钉 WebHook 实现的调试的短信客户端实现类 26 * 基于钉钉 WebHook 实现的调试的短信客户端实现类
@@ -32,7 +32,7 @@ import java.util.Map; @@ -32,7 +32,7 @@ import java.util.Map;
32 public class DebugDingTalkSmsClient extends AbstractSmsClient { 32 public class DebugDingTalkSmsClient extends AbstractSmsClient {
33 33
34 public DebugDingTalkSmsClient(SmsChannelProperties properties) { 34 public DebugDingTalkSmsClient(SmsChannelProperties properties) {
35 - super(properties, new DebugDingTalkCodeMapping()); 35 + super(properties);
36 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); 36 Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
37 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); 37 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
38 } 38 }
@@ -42,8 +42,8 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { @@ -42,8 +42,8 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
42 } 42 }
43 43
44 @Override 44 @Override
45 - protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,  
46 - String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable { 45 + public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
  46 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
47 // 构建请求 47 // 构建请求
48 String url = buildUrl("robot/send"); 48 String url = buildUrl("robot/send");
49 Map<String, Object> params = new HashMap<>(); 49 Map<String, Object> params = new HashMap<>();
@@ -55,14 +55,15 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { @@ -55,14 +55,15 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
55 String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); 55 String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
56 // 解析结果 56 // 解析结果
57 Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class); 57 Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
58 - return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"),  
59 - null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping); 58 + String errorCode = MapUtil.getStr(responseObj, "errcode");
  59 + return new SmsSendRespDTO().setSuccess(Objects.equals(errorCode, "0")).setSerialNo(StrUtil.uuid())
  60 + .setApiCode(errorCode).setApiMsg(MapUtil.getStr(responseObj, "errorMsg"));
60 } 61 }
61 62
62 /** 63 /**
63 * 构建请求地址 64 * 构建请求地址
64 * 65 *
65 - * 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档 66 + * 参见 <a href="https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71">文档</a>
66 * 67 *
67 * @param path 请求路径 68 * @param path 请求路径
68 * @return 请求地址 69 * @return 请求地址
@@ -82,15 +83,14 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { @@ -82,15 +83,14 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
82 } 83 }
83 84
84 @Override 85 @Override
85 - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { 86 + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
86 throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); 87 throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
87 } 88 }
88 89
89 @Override 90 @Override
90 - protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {  
91 - SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("") 91 + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
  92 + return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
92 .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(""); 93 .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
93 - return SmsCommonResult.build("0", "success", null, data, codeMapping);  
94 } 94 }
95 95
96 } 96 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/tencent/TencentSmsChannelProperties.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;  
2 -  
3 -import cn.hutool.core.bean.BeanUtil;  
4 -import cn.hutool.core.lang.Assert;  
5 -import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;  
6 -import lombok.Data;  
7 -  
8 -/**  
9 - * 腾讯云短信配置实现类  
10 - * 腾讯云发送短信时,需要额外的参数 sdkAppId,  
11 - *  
12 - * @author shiwp  
13 - */  
14 -@Data  
15 -public class TencentSmsChannelProperties extends SmsChannelProperties {  
16 -  
17 - /**  
18 - * 应用 id  
19 - */  
20 - private String sdkAppId;  
21 -  
22 - /**  
23 - * 考虑到不破坏原有的 apiKey + apiSecret 的结构,  
24 - * 所以腾讯云短信存储时,将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。  
25 - * 因此在使用时,需要将 secretId 和 sdkAppId 解析出来,分别存储到对应字段中。  
26 - */  
27 - public static TencentSmsChannelProperties build(SmsChannelProperties properties) {  
28 - if (properties instanceof TencentSmsChannelProperties) {  
29 - return (TencentSmsChannelProperties) properties;  
30 - }  
31 - TencentSmsChannelProperties result = BeanUtil.toBean(properties, TencentSmsChannelProperties.class);  
32 - String combineKey = properties.getApiKey();  
33 - Assert.notEmpty(combineKey, "apiKey 不能为空");  
34 - String[] keys = combineKey.trim().split(" ");  
35 - Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]");  
36 - Assert.notBlank(keys[0], "腾讯云短信 secretId 不能为空");  
37 - Assert.notBlank(keys[1], "腾讯云短信 sdkAppId 不能为空");  
38 - result.setSdkAppId(keys[1]).setApiKey(keys[0]);  
39 - return result;  
40 - }  
41 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/tencent/TencentSmsClient.java
@@ -4,9 +4,7 @@ import cn.hutool.core.lang.Assert; @@ -4,9 +4,7 @@ import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.core.KeyValue; 5 import cn.iocoder.yudao.framework.common.core.KeyValue;
6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;  
8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
9 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
11 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
12 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
@@ -17,23 +15,22 @@ import com.fasterxml.jackson.annotation.JsonFormat; @@ -17,23 +15,22 @@ import com.fasterxml.jackson.annotation.JsonFormat;
17 import com.fasterxml.jackson.annotation.JsonProperty; 15 import com.fasterxml.jackson.annotation.JsonProperty;
18 import com.google.common.annotations.VisibleForTesting; 16 import com.google.common.annotations.VisibleForTesting;
19 import com.tencentcloudapi.common.Credential; 17 import com.tencentcloudapi.common.Credential;
20 -import com.tencentcloudapi.common.exception.TencentCloudSDKException;  
21 import com.tencentcloudapi.sms.v20210111.SmsClient; 18 import com.tencentcloudapi.sms.v20210111.SmsClient;
22 import com.tencentcloudapi.sms.v20210111.models.*; 19 import com.tencentcloudapi.sms.v20210111.models.*;
23 import lombok.Data; 20 import lombok.Data;
24 21
25 import java.time.LocalDateTime; 22 import java.time.LocalDateTime;
26 import java.util.List; 23 import java.util.List;
27 -import java.util.function.Function;  
28 -import java.util.function.Supplier; 24 +import java.util.Objects;
29 25
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
30 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 27 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
31 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; 28 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
32 29
33 /** 30 /**
34 * 腾讯云短信功能实现 31 * 腾讯云短信功能实现
35 - * <p>  
36 - * 参见 https://cloud.tencent.com/document/product/382/52077 32 + *
  33 + * 参见 <a href="https://cloud.tencent.com/document/product/382/52077">文档</a>
37 * 34 *
38 * @author shiwp 35 * @author shiwp
39 */ 36 */
@@ -42,7 +39,7 @@ public class TencentSmsClient extends AbstractSmsClient { @@ -42,7 +39,7 @@ public class TencentSmsClient extends AbstractSmsClient {
42 /** 39 /**
43 * 调用成功 code 40 * 调用成功 code
44 */ 41 */
45 - public static final String API_SUCCESS_CODE = "Ok"; 42 + public static final String API_CODE_SUCCESS = "Ok";
46 43
47 /** 44 /**
48 * REGION,使用南京 45 * REGION,使用南京
@@ -51,180 +48,103 @@ public class TencentSmsClient extends AbstractSmsClient { @@ -51,180 +48,103 @@ public class TencentSmsClient extends AbstractSmsClient {
51 48
52 /** 49 /**
53 * 是否国际/港澳台短信: 50 * 是否国际/港澳台短信:
  51 + *
54 * 0:表示国内短信。 52 * 0:表示国内短信。
55 * 1:表示国际/港澳台短信。 53 * 1:表示国际/港澳台短信。
56 */ 54 */
57 - private static final long INTERNATIONAL = 0L; 55 + private static final long INTERNATIONAL_CHINA = 0L;
58 56
59 private SmsClient client; 57 private SmsClient client;
60 58
61 public TencentSmsClient(SmsChannelProperties properties) { 59 public TencentSmsClient(SmsChannelProperties properties) {
62 - super(properties, new TencentSmsCodeMapping()); 60 + super(properties);
63 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); 61 Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
  62 + validateSdkAppId(properties);
64 } 63 }
65 64
66 @Override 65 @Override
67 protected void doInit() { 66 protected void doInit() {
68 // 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey 67 // 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey
69 - Credential credential = new Credential(properties.getApiKey(), properties.getApiSecret()); 68 + Credential credential = new Credential(getApiKey(), properties.getApiSecret());
70 client = new SmsClient(credential, ENDPOINT); 69 client = new SmsClient(credential, ENDPOINT);
71 } 70 }
72 71
73 - @Override  
74 - protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId,  
75 - String mobile,  
76 - String apiTemplateId,  
77 - List<KeyValue<String, Object>> templateParams) throws Throwable {  
78 - return invoke(() -> buildSendSmsRequest(sendLogId, mobile, apiTemplateId, templateParams),  
79 - this::doSendSms0,  
80 - response -> {  
81 - SendStatus sendStatus = response.getSendStatusSet()[0];  
82 - return SmsCommonResult.build(sendStatus.getCode(), sendStatus.getMessage(), response.getRequestId(),  
83 - new SmsSendRespDTO().setSerialNo(sendStatus.getSerialNo()), codeMapping);  
84 - });  
85 - }  
86 -  
87 -  
88 /** 72 /**
89 - * 腾讯云发放短信的时候,需要额外的参数 sdkAppId。  
90 - * 考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。  
91 - * 因此,这边需要使用 TencentSmsChannelProperties 做拆分,重新封装到 properties 内。 73 + * 参数校验腾讯云的 SDK AppId
  74 + *
  75 + * 原因是:腾讯云发放短信的时候,需要额外的参数 sdkAppId
  76 + *
  77 + * 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
92 * 78 *
93 - * @param properties 数据库中存储的短信渠道配置  
94 - * @return TencentSmsChannelProperties 79 + * @param properties 配置
95 */ 80 */
96 - @Override  
97 - protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {  
98 - return TencentSmsChannelProperties.build(properties); 81 + private static void validateSdkAppId(SmsChannelProperties properties) {
  82 + String combineKey = properties.getApiKey();
  83 + Assert.notEmpty(combineKey, "apiKey 不能为空");
  84 + String[] keys = combineKey.trim().split(" ");
  85 + Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]");
99 } 86 }
100 87
101 - /**  
102 - * 调用腾讯云 SDK 发送短信  
103 - *  
104 - * @param request 发送短信请求  
105 - * @return 发送短信响应  
106 - * @throws TencentCloudSDKException SDK 用来封装发送短信失败  
107 - */  
108 - private SendSmsResponse doSendSms0(SendSmsRequest request) throws TencentCloudSDKException {  
109 - return client.SendSms(request); 88 + private String getSdkAppId() {
  89 + return StrUtil.subAfter(properties.getApiKey(), " ", true);
110 } 90 }
111 91
112 - /**  
113 - * 封装腾讯云发送短信请求  
114 - *  
115 - * @param sendLogId 日志编号  
116 - * @param mobile 手机号  
117 - * @param apiTemplateId 短信 API 的模板编号  
118 - * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序  
119 - * @return 腾讯云发送短信请求  
120 - */  
121 - private SendSmsRequest buildSendSmsRequest(Long sendLogId,  
122 - String mobile,  
123 - String apiTemplateId,  
124 - List<KeyValue<String, Object>> templateParams) { 92 + private String getApiKey() {
  93 + return StrUtil.subBefore(properties.getApiKey(), " ", true);
  94 + }
  95 +
  96 + @Override
  97 + public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
  98 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
  99 + // 构建请求
125 SendSmsRequest request = new SendSmsRequest(); 100 SendSmsRequest request = new SendSmsRequest();
126 - request.setSmsSdkAppId(((TencentSmsChannelProperties) properties).getSdkAppId()); 101 + request.setSmsSdkAppId(getSdkAppId());
127 request.setPhoneNumberSet(new String[]{mobile}); 102 request.setPhoneNumberSet(new String[]{mobile});
128 request.setSignName(properties.getSignature()); 103 request.setSignName(properties.getSignature());
129 request.setTemplateId(apiTemplateId); 104 request.setTemplateId(apiTemplateId);
130 request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue()))); 105 request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
131 request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId))); 106 request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId)));
132 - return request; 107 + // 执行请求
  108 + SendSmsResponse response = client.SendSms(request);
  109 + SendStatus status = response.getSendStatusSet()[0];
  110 + return new SmsSendRespDTO().setSuccess(Objects.equals(status.getCode(), API_CODE_SUCCESS)).setSerialNo(status.getSerialNo())
  111 + .setApiRequestId(response.getRequestId()).setApiCode(status.getCode()).setApiMsg(status.getMessage());
133 } 112 }
134 113
135 @Override 114 @Override
136 - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { 115 + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
137 List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class); 116 List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
138 - return CollectionUtils.convertList(callback, status -> {  
139 - SmsReceiveRespDTO data = new SmsReceiveRespDTO();  
140 - data.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription());  
141 - data.setReceiveTime(status.getReceiveTime()).setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()));  
142 - data.setMobile(status.getMobile()).setSerialNo(status.getSerialNo());  
143 - SessionContext context;  
144 - Long logId;  
145 - Assert.notNull(context = status.getSessionContext(), "回执信息中未解析出 context,请联系腾讯云小助手");  
146 - Assert.notNull(logId = context.getLogId(), "回执信息中未解析出 logId,请联系腾讯云小助手");  
147 - data.setLogId(logId);  
148 - return data;  
149 - }); 117 + return convertList(callback, status -> new SmsReceiveRespDTO()
  118 + .setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()))
  119 + .setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription())
  120 + .setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime())
  121 + .setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId()));
150 } 122 }
151 123
152 @Override 124 @Override
153 - protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {  
154 - return invoke(() -> this.buildSmsTemplateStatusRequest(apiTemplateId),  
155 - this::doGetSmsTemplate0,  
156 - response -> {  
157 - SmsTemplateRespDTO data = convertTemplateStatusDTO(response.getDescribeTemplateStatusSet()[0]);  
158 - return SmsCommonResult.build(API_SUCCESS_CODE, null, response.getRequestId(), data, codeMapping);  
159 - });  
160 - }  
161 -  
162 - @VisibleForTesting  
163 - SmsTemplateRespDTO convertTemplateStatusDTO(DescribeTemplateListStatus templateStatus) {  
164 - if (templateStatus == null) {  
165 - return null;  
166 - }  
167 - SmsTemplateAuditStatusEnum auditStatus;  
168 - Assert.notNull(templateStatus.getStatusCode(),  
169 - StrUtil.format("短信模版审核状态为 null,模版 id{}", templateStatus.getTemplateId()));  
170 - switch (templateStatus.getStatusCode().intValue()) {  
171 - case -1:  
172 - auditStatus = SmsTemplateAuditStatusEnum.FAIL;  
173 - break;  
174 - case 0:  
175 - auditStatus = SmsTemplateAuditStatusEnum.SUCCESS;  
176 - break;  
177 - case 1:  
178 - auditStatus = SmsTemplateAuditStatusEnum.CHECKING;  
179 - break;  
180 - default:  
181 - throw new IllegalStateException(StrUtil.format("不能解析短信模版审核状态{},模版 id{}",  
182 - templateStatus.getStatusCode(), templateStatus.getTemplateId()));  
183 - }  
184 - SmsTemplateRespDTO data = new SmsTemplateRespDTO();  
185 - data.setId(String.valueOf(templateStatus.getTemplateId())).setContent(templateStatus.getTemplateContent());  
186 - data.setAuditStatus(auditStatus.getStatus()).setAuditReason(templateStatus.getReviewReply());  
187 - return data;  
188 - }  
189 -  
190 - /**  
191 - * 封装查询模版审核状态请求  
192 - * @param apiTemplateId api 的模版 id  
193 - * @return 查询模版审核状态请求  
194 - */  
195 - private DescribeSmsTemplateListRequest buildSmsTemplateStatusRequest(String apiTemplateId) { 125 + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
  126 + // 构建请求
196 DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest(); 127 DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
197 request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)}); 128 request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
198 - // 地区 0:表示国内短信。1:表示国际/港澳台短信。  
199 - request.setInternational(INTERNATIONAL);  
200 - return request;  
201 - }  
202 -  
203 - /**  
204 - * 调用腾讯云 SDK 查询短信模版状态  
205 - *  
206 - * @param request 查询短信模版状态请求  
207 - * @return 查询短信模版状态响应  
208 - * @throws TencentCloudSDKException SDK 用来封装查询短信模版状态失败  
209 - */  
210 - private DescribeSmsTemplateListResponse doGetSmsTemplate0(DescribeSmsTemplateListRequest request) throws TencentCloudSDKException {  
211 - return client.DescribeSmsTemplateList(request); 129 + request.setInternational(INTERNATIONAL_CHINA);
  130 + // 执行请求
  131 + DescribeSmsTemplateListResponse response = client.DescribeSmsTemplateList(request);
  132 + DescribeTemplateListStatus status = response.getDescribeTemplateStatusSet()[0];
  133 + if (status == null || status.getStatusCode() == null) {
  134 + return null;
  135 + }
  136 + return new SmsTemplateRespDTO().setId(status.getTemplateId().toString()).setContent(status.getTemplateContent())
  137 + .setAuditStatus(convertSmsTemplateAuditStatus(status.getStatusCode().intValue())).setAuditReason(status.getReviewReply());
212 } 138 }
213 139
214 - <Q, P, R> SmsCommonResult<R> invoke(Supplier<Q> requestSupplier,  
215 - SdkFunction<Q, P> responseSupplier,  
216 - Function<P, SmsCommonResult<R>> resultGen) {  
217 - // 构建请求body  
218 - Q request = requestSupplier.get();  
219 - P response;  
220 - // 调用腾讯云发送短信  
221 - try {  
222 - response = responseSupplier.apply(request);  
223 - } catch (TencentCloudSDKException e) {  
224 - // 调用异常,封装结果  
225 - return SmsCommonResult.build(e.getErrorCode(), e.getMessage(), e.getRequestId(), null, codeMapping); 140 + @VisibleForTesting
  141 + Integer convertSmsTemplateAuditStatus(int templateStatus) {
  142 + switch (templateStatus) {
  143 + case 1: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
  144 + case 0: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
  145 + case -1: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
  146 + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
226 } 147 }
227 - return resultGen.apply(response);  
228 } 148 }
229 149
230 @Data 150 @Data
@@ -278,7 +198,7 @@ public class TencentSmsClient extends AbstractSmsClient { @@ -278,7 +198,7 @@ public class TencentSmsClient extends AbstractSmsClient {
278 private String serialNo; 198 private String serialNo;
279 199
280 /** 200 /**
281 - * 用户的 session 内容(与发送接口的请求参数SessionContext一致) 201 + * 用户的 session 内容(与发送接口的请求参数 SessionContext 一致)
282 */ 202 */
283 @JsonProperty("ext") 203 @JsonProperty("ext")
284 private SessionContext sessionContext; 204 private SessionContext sessionContext;
@@ -293,10 +213,7 @@ public class TencentSmsClient extends AbstractSmsClient { @@ -293,10 +213,7 @@ public class TencentSmsClient extends AbstractSmsClient {
293 * 发送短信记录id 213 * 发送短信记录id
294 */ 214 */
295 private Long logId; 215 private Long logId;
296 - }  
297 216
298 - private interface SdkFunction<T, R> {  
299 - R apply(T t) throws TencentCloudSDKException;  
300 } 217 }
301 218
302 } 219 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/tencent/TencentSmsCodeMapping.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.ErrorCode;  
4 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
5 -import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;  
6 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
7 -  
8 -import static cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;  
9 -  
10 -/**  
11 - * 腾讯云的 SmsCodeMapping 实现类  
12 - *  
13 - * 参见 https://cloud.tencent.com/document/api/382/52075#.E5.85.AC.E5.85.B1.E9.94.99.E8.AF.AF.E7.A0.81  
14 - *  
15 - * @author : shiwp  
16 - */  
17 -public class TencentSmsCodeMapping implements SmsCodeMapping {  
18 -  
19 - @Override  
20 - public ErrorCode apply(String apiCode) {  
21 - switch (apiCode) {  
22 - case TencentSmsClient.API_SUCCESS_CODE: return GlobalErrorCodeConstants.SUCCESS;  
23 - case "FailedOperation.ContainSensitiveWord": return SMS_SEND_CONTENT_INVALID;  
24 - case "FailedOperation.JsonParseFail":  
25 - case "MissingParameter.EmptyPhoneNumberSet":  
26 - case "LimitExceeded.PhoneNumberCountLimit":  
27 - case "FailedOperation.FailResolvePacket": return GlobalErrorCodeConstants.BAD_REQUEST;  
28 - case "FailedOperation.InsufficientBalanceInSmsPackage": return SMS_ACCOUNT_MONEY_NOT_ENOUGH;  
29 - case "FailedOperation.MarketingSendTimeConstraint": return SMS_SEND_MARKET_LIMIT_CONTROL;  
30 - case "FailedOperation.PhoneNumberInBlacklist": return SMS_MOBILE_BLACK;  
31 - case "FailedOperation.SignatureIncorrectOrUnapproved": return SMS_SIGN_INVALID;  
32 - case "FailedOperation.MissingTemplateToModify":  
33 - case "FailedOperation.TemplateIncorrectOrUnapproved": return SMS_TEMPLATE_INVALID;  
34 - case "InvalidParameterValue.IncorrectPhoneNumber": return SMS_MOBILE_INVALID;  
35 - case "InvalidParameterValue.SdkAppIdNotExist": return SMS_APP_ID_INVALID;  
36 - case "InvalidParameterValue.TemplateParameterLengthLimit":  
37 - case "InvalidParameterValue.TemplateParameterFormatError": return SMS_TEMPLATE_PARAM_ERROR;  
38 - case "LimitExceeded.PhoneNumberDailyLimit": return SMS_SEND_DAY_LIMIT_CONTROL;  
39 - case "LimitExceeded.PhoneNumberThirtySecondLimit":  
40 - case "LimitExceeded.PhoneNumberOneHourLimit": return SMS_SEND_BUSINESS_LIMIT_CONTROL;  
41 - case "UnauthorizedOperation.RequestPermissionDeny":  
42 - case "FailedOperation.ForbidAddMarketingTemplates":  
43 - case "FailedOperation.NotEnterpriseCertification":  
44 - case "UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny": return SMS_PERMISSION_DENY;  
45 - case "UnauthorizedOperation.RequestIpNotInWhitelist": return SMS_IP_DENY;  
46 - case "AuthFailure.SecretIdNotFound": return SMS_ACCOUNT_INVALID;  
47 - }  
48 - return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;  
49 - }  
50 -}  
51 \ No newline at end of file 0 \ No newline at end of file
yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java
1 package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; 1 package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
2 2
3 import cn.hutool.core.util.ReflectUtil; 3 import cn.hutool.core.util.ReflectUtil;
4 -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;  
5 import cn.iocoder.yudao.framework.common.core.KeyValue; 4 import cn.iocoder.yudao.framework.common.core.KeyValue;
6 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
7 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; 5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 6 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 7 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
11 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; 9 import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
12 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; 10 import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
13 -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;  
14 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
15 -import com.aliyuncs.AcsRequest; 11 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
16 import com.aliyuncs.IAcsClient; 12 import com.aliyuncs.IAcsClient;
17 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; 13 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
18 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; 14 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
19 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; 15 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
20 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; 16 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
21 -import com.aliyuncs.exceptions.ClientException;  
22 import com.google.common.collect.Lists; 17 import com.google.common.collect.Lists;
23 -import org.junit.jupiter.api.Assertions;  
24 import org.junit.jupiter.api.Test; 18 import org.junit.jupiter.api.Test;
25 import org.mockito.ArgumentMatcher; 19 import org.mockito.ArgumentMatcher;
26 import org.mockito.InjectMocks; 20 import org.mockito.InjectMocks;
@@ -28,12 +22,10 @@ import org.mockito.Mock; @@ -28,12 +22,10 @@ import org.mockito.Mock;
28 22
29 import java.time.LocalDateTime; 23 import java.time.LocalDateTime;
30 import java.util.List; 24 import java.util.List;
31 -import java.util.function.Function;  
32 25
33 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 26 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
34 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 27 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
35 import static org.junit.jupiter.api.Assertions.*; 28 import static org.junit.jupiter.api.Assertions.*;
36 -import static org.mockito.ArgumentMatchers.any;  
37 import static org.mockito.ArgumentMatchers.argThat; 29 import static org.mockito.ArgumentMatchers.argThat;
38 import static org.mockito.Mockito.when; 30 import static org.mockito.Mockito.when;
39 31
@@ -67,8 +59,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { @@ -67,8 +59,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
67 } 59 }
68 60
69 @Test 61 @Test
70 - @SuppressWarnings("unchecked")  
71 - public void testDoSendSms() throws ClientException { 62 + public void tesSendSms_success() throws Throwable {
72 // 准备参数 63 // 准备参数
73 Long sendLogId = randomLongId(); 64 Long sendLogId = randomLongId();
74 String mobile = randomString(); 65 String mobile = randomString();
@@ -87,20 +78,47 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { @@ -87,20 +78,47 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
87 }))).thenReturn(response); 78 }))).thenReturn(response);
88 79
89 // 调用 80 // 调用
90 - SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile, 81 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
91 apiTemplateId, templateParams); 82 apiTemplateId, templateParams);
92 // 断言 83 // 断言
  84 + assertTrue(result.getSuccess());
  85 + assertEquals(response.getRequestId(), result.getApiRequestId());
93 assertEquals(response.getCode(), result.getApiCode()); 86 assertEquals(response.getCode(), result.getApiCode());
94 assertEquals(response.getMessage(), result.getApiMsg()); 87 assertEquals(response.getMessage(), result.getApiMsg());
95 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());  
96 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); 88 + assertEquals(response.getBizId(), result.getSerialNo());
  89 + }
  90 +
  91 + @Test
  92 + public void tesSendSms_fail() throws Throwable {
  93 + // 准备参数
  94 + Long sendLogId = randomLongId();
  95 + String mobile = randomString();
  96 + String apiTemplateId = randomString();
  97 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  98 + new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
  99 + // mock 方法
  100 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("ERROR"));
  101 + when(client.getAcsResponse(argThat((ArgumentMatcher<SendSmsRequest>) acsRequest -> {
  102 + assertEquals(mobile, acsRequest.getPhoneNumbers());
  103 + assertEquals(properties.getSignature(), acsRequest.getSignName());
  104 + assertEquals(apiTemplateId, acsRequest.getTemplateCode());
  105 + assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam());
  106 + assertEquals(sendLogId.toString(), acsRequest.getOutId());
  107 + return true;
  108 + }))).thenReturn(response);
  109 +
  110 + // 调用
  111 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
  112 + // 断言
  113 + assertFalse(result.getSuccess());
97 assertEquals(response.getRequestId(), result.getApiRequestId()); 114 assertEquals(response.getRequestId(), result.getApiRequestId());
98 - // 断言结果  
99 - assertEquals(response.getBizId(), result.getData().getSerialNo()); 115 + assertEquals(response.getCode(), result.getApiCode());
  116 + assertEquals(response.getMessage(), result.getApiMsg());
  117 + assertEquals(response.getBizId(), result.getSerialNo());
100 } 118 }
101 119
102 @Test 120 @Test
103 - public void testDoTParseSmsReceiveStatus() throws Throwable { 121 + public void testParseSmsReceiveStatus() {
104 // 准备参数 122 // 准备参数
105 String text = "[\n" + 123 String text = "[\n" +
106 " {\n" + 124 " {\n" +
@@ -118,20 +136,21 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { @@ -118,20 +136,21 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
118 // mock 方法 136 // mock 方法
119 137
120 // 调用 138 // 调用
121 - List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text); 139 + List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
122 // 断言 140 // 断言
123 assertEquals(1, statuses.size()); 141 assertEquals(1, statuses.size());
124 assertTrue(statuses.get(0).getSuccess()); 142 assertTrue(statuses.get(0).getSuccess());
125 assertEquals("DELIVERED", statuses.get(0).getErrorCode()); 143 assertEquals("DELIVERED", statuses.get(0).getErrorCode());
126 assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); 144 assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
127 assertEquals("13900000001", statuses.get(0).getMobile()); 145 assertEquals("13900000001", statuses.get(0).getMobile());
128 - assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime()); 146 + assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24),
  147 + statuses.get(0).getReceiveTime());
129 assertEquals("12345", statuses.get(0).getSerialNo()); 148 assertEquals("12345", statuses.get(0).getSerialNo());
130 assertEquals(67890L, statuses.get(0).getLogId()); 149 assertEquals(67890L, statuses.get(0).getLogId());
131 } 150 }
132 151
133 @Test 152 @Test
134 - public void testDoGetSmsTemplate() throws ClientException { 153 + public void testGetSmsTemplate() throws Throwable {
135 // 准备参数 154 // 准备参数
136 String apiTemplateId = randomString(); 155 String apiTemplateId = randomString();
137 // mock 方法 156 // mock 方法
@@ -145,18 +164,12 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { @@ -145,18 +164,12 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
145 }))).thenReturn(response); 164 }))).thenReturn(response);
146 165
147 // 调用 166 // 调用
148 - SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId); 167 + SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId);
149 // 断言 168 // 断言
150 - assertEquals(response.getCode(), result.getApiCode());  
151 - assertEquals(response.getMessage(), result.getApiMsg());  
152 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());  
153 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());  
154 - assertEquals(response.getRequestId(), result.getApiRequestId());  
155 - // 断言结果  
156 - assertEquals(response.getTemplateCode(), result.getData().getId());  
157 - assertEquals(response.getTemplateContent(), result.getData().getContent());  
158 - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());  
159 - assertEquals(response.getReason(), result.getData().getAuditReason()); 169 + assertEquals(response.getTemplateCode(), result.getId());
  170 + assertEquals(response.getTemplateContent(), result.getContent());
  171 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
  172 + assertEquals(response.getReason(), result.getAuditReason());
160 } 173 }
161 174
162 @Test 175 @Test
@@ -171,55 +184,4 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { @@ -171,55 +184,4 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
171 "未知审核状态(3)"); 184 "未知审核状态(3)");
172 } 185 }
173 186
174 - @Test  
175 - @SuppressWarnings("unchecked")  
176 - public void testInvoke_throwable() throws ClientException {  
177 - // 准备参数  
178 - QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();  
179 - // mock 方法  
180 - ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString());  
181 - when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);  
182 -  
183 - // 调用,并断言异常  
184 - SmsCommonResult<?> result = smsClient.invoke(request, null);  
185 - // 断言  
186 - assertEquals(ex.getErrCode(), result.getApiCode());  
187 - assertEquals(ex.getErrMsg(), result.getApiMsg());  
188 - Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getCode(), result.getCode());  
189 - Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getMsg(), result.getMsg());  
190 - assertEquals(ex.getRequestId(), result.getApiRequestId());  
191 - }  
192 -  
193 - @Test  
194 - public void testInvoke_success() throws ClientException {  
195 - // 准备参数  
196 - QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();  
197 - Function<QuerySmsTemplateResponse, SmsTemplateRespDTO> responseConsumer = response -> {  
198 - SmsTemplateRespDTO data = new SmsTemplateRespDTO();  
199 - data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());  
200 - data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason());  
201 - return data;  
202 - };  
203 - // mock 方法  
204 - QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {  
205 - o.setCode("OK");  
206 - o.setTemplateStatus(1); // 设置模板通过  
207 - });  
208 - when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response);  
209 -  
210 - // 调用  
211 - SmsCommonResult<SmsTemplateRespDTO> result = smsClient.invoke(request, responseConsumer);  
212 - // 断言  
213 - assertEquals(response.getCode(), result.getApiCode());  
214 - assertEquals(response.getMessage(), result.getApiMsg());  
215 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());  
216 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());  
217 - assertEquals(response.getRequestId(), result.getApiRequestId());  
218 - // 断言结果  
219 - assertEquals(response.getTemplateCode(), result.getData().getId());  
220 - assertEquals(response.getTemplateContent(), result.getData().getContent());  
221 - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());  
222 - assertEquals(response.getReason(), result.getData().getAuditReason());  
223 - }  
224 -  
225 } 187 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMappingTest.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;  
2 -  
3 -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;  
4 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
5 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
6 -import org.junit.jupiter.api.Test;  
7 -import org.mockito.InjectMocks;  
8 -  
9 -import static org.junit.jupiter.api.Assertions.assertEquals;  
10 -  
11 -/**  
12 - * {@link AliyunSmsCodeMapping} 的单元测试  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -public class AliyunSmsCodeMappingTest extends BaseMockitoUnitTest {  
17 -  
18 - @InjectMocks  
19 - private AliyunSmsCodeMapping codeMapping;  
20 -  
21 - @Test  
22 - public void testApply() {  
23 - assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply("OK"));  
24 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("MissingAccessKeyId"));  
25 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_NOT_EXISTS"));  
26 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_ABNORMAL"));  
27 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("isv.DAY_LIMIT_CONTROL"));  
28 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("isv.SMS_CONTENT_ILLEGAL"));  
29 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGN_ILLEGAL"));  
30 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SIGN_NAME_ILLEGAL"));  
31 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("isp.RAM_PERMISSION_DENY"));  
32 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.OUT_OF_SERVICE"));  
33 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.AMOUNT_NOT_ENOUGH"));  
34 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("isv.SMS_TEMPLATE_ILLEGAL"));  
35 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGNATURE_ILLEGAL"));  
36 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_PARAMETERS"));  
37 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_JSON_PARAM"));  
38 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("isv.MOBILE_NUMBER_ILLEGAL"));  
39 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("isv.TEMPLATE_MISSING_PARAMETERS"));  
40 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("isv.BUSINESS_LIMIT_CONTROL"));  
41 - }  
42 -  
43 -}  
yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/tencent/TencentSmsClientTest.java
1 package cn.iocoder.yudao.framework.sms.core.client.impl.tencent; 1 package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
2 2
3 import cn.hutool.core.util.ReflectUtil; 3 import cn.hutool.core.util.ReflectUtil;
4 -import cn.hutool.core.util.StrUtil;  
5 import cn.iocoder.yudao.framework.common.core.KeyValue; 4 import cn.iocoder.yudao.framework.common.core.KeyValue;
6 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
7 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
8 import cn.iocoder.yudao.framework.common.util.collection.MapUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
10 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
11 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
12 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
13 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
@@ -31,7 +28,6 @@ import java.util.List; @@ -31,7 +28,6 @@ import java.util.List;
31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; 28 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
32 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; 29 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
33 import static org.junit.jupiter.api.Assertions.*; 30 import static org.junit.jupiter.api.Assertions.*;
34 -import static org.junit.jupiter.api.Assertions.assertThrows;  
35 import static org.mockito.ArgumentMatchers.argThat; 31 import static org.mockito.ArgumentMatchers.argThat;
36 import static org.mockito.Mockito.when; 32 import static org.mockito.Mockito.when;
37 33
@@ -78,7 +74,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -78,7 +74,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
78 } 74 }
79 75
80 @Test 76 @Test
81 - public void testDoSendSms() throws Throwable { 77 + public void testDoSendSms_success() throws Throwable {
82 // 准备参数 78 // 准备参数
83 Long sendLogId = randomLongId(); 79 Long sendLogId = randomLongId();
84 String mobile = randomString(); 80 String mobile = randomString();
@@ -94,7 +90,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -94,7 +90,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
94 o.setSendStatusSet(sendStatuses); 90 o.setSendStatusSet(sendStatuses);
95 SendStatus sendStatus = new SendStatus(); 91 SendStatus sendStatus = new SendStatus();
96 sendStatuses[0] = sendStatus; 92 sendStatuses[0] = sendStatus;
97 - sendStatus.setCode(TencentSmsClient.API_SUCCESS_CODE); 93 + sendStatus.setCode(TencentSmsClient.API_CODE_SUCCESS);
98 sendStatus.setMessage("send success"); 94 sendStatus.setMessage("send success");
99 sendStatus.setSerialNo(serialNo); 95 sendStatus.setSerialNo(serialNo);
100 }); 96 });
@@ -109,20 +105,58 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -109,20 +105,58 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
109 }))).thenReturn(response); 105 }))).thenReturn(response);
110 106
111 // 调用 107 // 调用
112 - SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,  
113 - apiTemplateId, templateParams); 108 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
114 // 断言 109 // 断言
  110 + assertTrue(result.getSuccess());
  111 + assertEquals(response.getRequestId(), result.getApiRequestId());
115 assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode()); 112 assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
116 assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg()); 113 assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
117 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());  
118 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg()); 114 + assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
  115 + }
  116 +
  117 + @Test
  118 + public void testDoSendSms_fail() throws Throwable {
  119 + // 准备参数
  120 + Long sendLogId = randomLongId();
  121 + String mobile = randomString();
  122 + String apiTemplateId = randomString();
  123 + List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
  124 + new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
  125 + String requestId = randomString();
  126 + String serialNo = randomString();
  127 + // mock 方法
  128 + SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> {
  129 + o.setRequestId(requestId);
  130 + SendStatus[] sendStatuses = new SendStatus[1];
  131 + o.setSendStatusSet(sendStatuses);
  132 + SendStatus sendStatus = new SendStatus();
  133 + sendStatuses[0] = sendStatus;
  134 + sendStatus.setCode("ERROR");
  135 + sendStatus.setMessage("send success");
  136 + sendStatus.setSerialNo(serialNo);
  137 + });
  138 + when(client.SendSms(argThat(request -> {
  139 + assertEquals(mobile, request.getPhoneNumberSet()[0]);
  140 + assertEquals(properties.getSignature(), request.getSignName());
  141 + assertEquals(apiTemplateId, request.getTemplateId());
  142 + assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)),
  143 + toJsonString(request.getTemplateParamSet()));
  144 + assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId"));
  145 + return true;
  146 + }))).thenReturn(response);
  147 +
  148 + // 调用
  149 + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
  150 + // 断言
  151 + assertFalse(result.getSuccess());
119 assertEquals(response.getRequestId(), result.getApiRequestId()); 152 assertEquals(response.getRequestId(), result.getApiRequestId());
120 - // 断言结果  
121 - assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getData().getSerialNo()); 153 + assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
  154 + assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
  155 + assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
122 } 156 }
123 157
124 @Test 158 @Test
125 - public void testDoTParseSmsReceiveStatus() throws Throwable { 159 + public void testParseSmsReceiveStatus() {
126 // 准备参数 160 // 准备参数
127 String text = "[\n" + 161 String text = "[\n" +
128 " {\n" + 162 " {\n" +
@@ -139,7 +173,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -139,7 +173,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
139 // mock 方法 173 // mock 方法
140 174
141 // 调用 175 // 调用
142 - List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text); 176 + List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
143 // 断言 177 // 断言
144 assertEquals(1, statuses.size()); 178 assertEquals(1, statuses.size());
145 assertTrue(statuses.get(0).getSuccess()); 179 assertTrue(statuses.get(0).getSuccess());
@@ -152,7 +186,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -152,7 +186,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
152 } 186 }
153 187
154 @Test 188 @Test
155 - public void testDoGetSmsTemplate() throws Throwable { 189 + public void testGetSmsTemplate() throws Throwable {
156 // 准备参数 190 // 准备参数
157 Long apiTemplateId = randomLongId(); 191 Long apiTemplateId = randomLongId();
158 String requestId = randomString(); 192 String requestId = randomString();
@@ -173,50 +207,24 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { @@ -173,50 +207,24 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
173 }))).thenReturn(response); 207 }))).thenReturn(response);
174 208
175 // 调用 209 // 调用
176 - SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId.toString()); 210 + SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId.toString());
177 // 断言 211 // 断言
178 - assertEquals(TencentSmsClient.API_SUCCESS_CODE, result.getApiCode());  
179 - assertNull(result.getApiMsg());  
180 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());  
181 - assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());  
182 - assertEquals(response.getRequestId(), result.getApiRequestId());  
183 - // 断言结果  
184 - assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getData().getId());  
185 - assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getData().getContent());  
186 - assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());  
187 - assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getData().getAuditReason());  
188 - }  
189 -  
190 - @Test  
191 - public void testConvertSuccessTemplateStatus() {  
192 - testTemplateStatus(SmsTemplateAuditStatusEnum.SUCCESS, 0L);  
193 - }  
194 -  
195 - @Test  
196 - public void testConvertCheckingTemplateStatus() {  
197 - testTemplateStatus(SmsTemplateAuditStatusEnum.CHECKING, 1L);  
198 - }  
199 -  
200 - @Test  
201 - public void testConvertFailTemplateStatus() {  
202 - testTemplateStatus(SmsTemplateAuditStatusEnum.FAIL, -1L); 212 + assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getId());
  213 + assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getContent());
  214 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
  215 + assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getAuditReason());
203 } 216 }
204 217
205 @Test 218 @Test
206 - public void testConvertUnknownTemplateStatus() {  
207 - DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus();  
208 - templateStatus.setStatusCode(3L);  
209 - Long templateId = randomLongId();  
210 - // 调用,并断言结果  
211 - assertThrows(IllegalStateException.class, () -> smsClient.convertTemplateStatusDTO(templateStatus),  
212 - StrUtil.format("不能解析短信模版审核状态[3],模版id[{}]", templateId));  
213 - }  
214 -  
215 - private void testTemplateStatus(SmsTemplateAuditStatusEnum expected, Long value) {  
216 - DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus();  
217 - templateStatus.setStatusCode(value);  
218 - SmsTemplateRespDTO result = smsClient.convertTemplateStatusDTO(templateStatus);  
219 - assertEquals(expected.getStatus(), result.getAuditStatus()); 219 + public void testConvertSmsTemplateAuditStatus() {
  220 + assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
  221 + smsClient.convertSmsTemplateAuditStatus(0));
  222 + assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
  223 + smsClient.convertSmsTemplateAuditStatus(1));
  224 + assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
  225 + smsClient.convertSmsTemplateAuditStatus(-1));
  226 + assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3),
  227 + "未知审核状态(3)");
220 } 228 }
221 229
222 } 230 }
yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/tencent/TencentSmsCodeMappingTest.java deleted
1 -package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;  
2 -  
3 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
4 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;  
5 -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;  
6 -import org.junit.jupiter.api.Test;  
7 -import org.mockito.InjectMocks;  
8 -  
9 -import static org.junit.jupiter.api.Assertions.assertEquals;  
10 -  
11 -/**  
12 - * {@link TencentSmsCodeMapping} 的单元测试  
13 - *  
14 - * @author : shiwp  
15 - */  
16 -public class TencentSmsCodeMappingTest extends BaseMockitoUnitTest {  
17 -  
18 - @InjectMocks  
19 - private TencentSmsCodeMapping codeMapping;  
20 -  
21 - @Test  
22 - public void testApply() {  
23 - assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply(TencentSmsClient.API_SUCCESS_CODE));  
24 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("FailedOperation.ContainSensitiveWord"));  
25 - assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("FailedOperation.JsonParseFail"));  
26 - assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("MissingParameter.EmptyPhoneNumberSet"));  
27 - assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("LimitExceeded.PhoneNumberCountLimit"));  
28 - assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("FailedOperation.FailResolvePacket"));  
29 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("FailedOperation.InsufficientBalanceInSmsPackage"));  
30 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_MARKET_LIMIT_CONTROL, codeMapping.apply("FailedOperation.MarketingSendTimeConstraint"));  
31 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK, codeMapping.apply("FailedOperation.PhoneNumberInBlacklist"));  
32 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("FailedOperation.SignatureIncorrectOrUnapproved"));  
33 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("FailedOperation.MissingTemplateToModify"));  
34 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("FailedOperation.TemplateIncorrectOrUnapproved"));  
35 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("InvalidParameterValue.IncorrectPhoneNumber"));  
36 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_APP_ID_INVALID, codeMapping.apply("InvalidParameterValue.SdkAppIdNotExist"));  
37 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("InvalidParameterValue.TemplateParameterLengthLimit"));  
38 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("InvalidParameterValue.TemplateParameterFormatError"));  
39 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberDailyLimit"));  
40 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberThirtySecondLimit"));  
41 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberOneHourLimit"));  
42 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("UnauthorizedOperation.RequestPermissionDeny"));  
43 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("FailedOperation.ForbidAddMarketingTemplates"));  
44 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("FailedOperation.NotEnterpriseCertification"));  
45 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny"));  
46 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_IP_DENY, codeMapping.apply("UnauthorizedOperation.RequestIpNotInWhitelist"));  
47 - assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("AuthFailure.SecretIdNotFound"));  
48 - }  
49 -  
50 -}  
51 \ No newline at end of file 0 \ No newline at end of file
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
@@ -82,6 +82,10 @@ public interface ErrorCodeConstants { @@ -82,6 +82,10 @@ public interface ErrorCodeConstants {
82 // ========== 短信模板 1-002-012-000 ========== 82 // ========== 短信模板 1-002-012-000 ==========
83 ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在"); 83 ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
84 ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板"); 84 ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板");
  85 + ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "短信 API 模板调用失败,原因是:{}");
  86 + ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "短信 API 模版无法使用,原因:审批中");
  87 + ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "短信 API 模版无法使用,原因:审批不通过,{}");
  88 + ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "短信 API 模版无法使用,原因:模版不存在");
85 89
86 // ========== 短信发送 1-002-013-000 ========== 90 // ========== 短信发送 1-002-013-000 ==========
87 ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在"); 91 ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在");
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogExcelVO.java
@@ -63,12 +63,6 @@ public class SmsLogExcelVO { @@ -63,12 +63,6 @@ public class SmsLogExcelVO {
63 @ExcelProperty("发送时间") 63 @ExcelProperty("发送时间")
64 private LocalDateTime sendTime; 64 private LocalDateTime sendTime;
65 65
66 - @ExcelProperty("发送结果的编码")  
67 - private Integer sendCode;  
68 -  
69 - @ExcelProperty("发送结果的提示")  
70 - private String sendMsg;  
71 -  
72 @ExcelProperty("短信 API 发送结果的编码") 66 @ExcelProperty("短信 API 发送结果的编码")
73 private String apiSendCode; 67 private String apiSendCode;
74 68
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/vo/log/SmsLogRespVO.java
@@ -52,12 +52,6 @@ public class SmsLogRespVO { @@ -52,12 +52,6 @@ public class SmsLogRespVO {
52 @Schema(description = "发送时间") 52 @Schema(description = "发送时间")
53 private LocalDateTime sendTime; 53 private LocalDateTime sendTime;
54 54
55 - @Schema(description = "发送结果的编码", example = "0")  
56 - private Integer sendCode;  
57 -  
58 - @Schema(description = "发送结果的提示", example = "成功")  
59 - private String sendMsg;  
60 -  
61 @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS") 55 @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS")
62 private String apiSendCode; 56 private String apiSendCode;
63 57
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/sms/SmsLogDO.java
1 package cn.iocoder.yudao.module.system.dal.dataobject.sms; 1 package cn.iocoder.yudao.module.system.dal.dataobject.sms;
2 2
3 -import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;  
4 -import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;  
5 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 3 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
7 -import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; 5 +import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
  6 +import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
8 import com.baomidou.mybatisplus.annotation.KeySequence; 7 import com.baomidou.mybatisplus.annotation.KeySequence;
9 import com.baomidou.mybatisplus.annotation.TableField; 8 import com.baomidou.mybatisplus.annotation.TableField;
10 import com.baomidou.mybatisplus.annotation.TableName; 9 import com.baomidou.mybatisplus.annotation.TableName;
@@ -116,19 +115,6 @@ public class SmsLogDO extends BaseDO { @@ -116,19 +115,6 @@ public class SmsLogDO extends BaseDO {
116 */ 115 */
117 private LocalDateTime sendTime; 116 private LocalDateTime sendTime;
118 /** 117 /**
119 - * 发送结果的编码  
120 - *  
121 - * 枚举 {@link SmsFrameworkErrorCodeConstants}  
122 - */  
123 - private Integer sendCode;  
124 - /**  
125 - * 发送结果的提示  
126 - *  
127 - * 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants}  
128 - * 异常情况下,通过格式化 Exception 的提示存储  
129 - */  
130 - private String sendMsg;  
131 - /**  
132 * 短信 API 发送结果的编码 118 * 短信 API 发送结果的编码
133 * 119 *
134 * 由于第三方的错误码可能是字符串,所以使用 String 类型 120 * 由于第三方的错误码可能是字符串,所以使用 String 类型
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogService.java
@@ -37,15 +37,15 @@ public interface SmsLogService { @@ -37,15 +37,15 @@ public interface SmsLogService {
37 * 更新日志的发送结果 37 * 更新日志的发送结果
38 * 38 *
39 * @param id 日志编号 39 * @param id 日志编号
40 - * @param sendCode 发送结果的编码  
41 - * @param sendMsg 发送结果的提示 40 + * @param success 发送是否成功
42 * @param apiSendCode 短信 API 发送结果的编码 41 * @param apiSendCode 短信 API 发送结果的编码
43 * @param apiSendMsg 短信 API 发送失败的提示 42 * @param apiSendMsg 短信 API 发送失败的提示
44 * @param apiRequestId 短信 API 发送返回的唯一请求 ID 43 * @param apiRequestId 短信 API 发送返回的唯一请求 ID
45 * @param apiSerialNo 短信 API 发送返回的序号 44 * @param apiSerialNo 短信 API 发送返回的序号
46 */ 45 */
47 - void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,  
48 - String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo); 46 + void updateSmsSendResult(Long id, Boolean success,
  47 + String apiSendCode, String apiSendMsg,
  48 + String apiRequestId, String apiSerialNo);
49 49
50 /** 50 /**
51 * 更新日志的接收结果 51 * 更新日志的接收结果
@@ -56,7 +56,8 @@ public interface SmsLogService { @@ -56,7 +56,8 @@ public interface SmsLogService {
56 * @param apiReceiveCode API 接收结果的编码 56 * @param apiReceiveCode API 接收结果的编码
57 * @param apiReceiveMsg API 接收结果的说明 57 * @param apiReceiveMsg API 接收结果的说明
58 */ 58 */
59 - void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg); 59 + void updateSmsReceiveResult(Long id, Boolean success,
  60 + LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
60 61
61 /** 62 /**
62 * 获得短信日志分页 63 * 获得短信日志分页
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
3 -import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO; 4 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
5 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; 5 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
6 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; 6 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
7 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; 7 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
8 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper; 8 import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper;
9 -import cn.iocoder.yudao.framework.common.pojo.PageResult;  
10 import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum; 9 import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
11 import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; 10 import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
12 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
@@ -55,13 +54,12 @@ public class SmsLogServiceImpl implements SmsLogService { @@ -55,13 +54,12 @@ public class SmsLogServiceImpl implements SmsLogService {
55 } 54 }
56 55
57 @Override 56 @Override
58 - public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, 57 + public void updateSmsSendResult(Long id, Boolean success,
59 String apiSendCode, String apiSendMsg, 58 String apiSendCode, String apiSendMsg,
60 String apiRequestId, String apiSerialNo) { 59 String apiRequestId, String apiSerialNo) {
61 - SmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ?  
62 - SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;  
63 - smsLogMapper.updateById(SmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus())  
64 - .sendTime(LocalDateTime.now()).sendCode(sendCode).sendMsg(sendMsg) 60 + SmsSendStatusEnum sendStatus = success ? SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;
  61 + smsLogMapper.updateById(SmsLogDO.builder().id(id)
  62 + .sendStatus(sendStatus.getStatus()).sendTime(LocalDateTime.now())
65 .apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) 63 .apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
66 .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build()); 64 .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
67 } 65 }
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.exceptions.ExceptionUtil;
4 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.core.KeyValue; 7 import cn.iocoder.yudao.framework.common.core.KeyValue;
@@ -8,7 +9,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; @@ -8,7 +9,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
8 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 9 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
9 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; 10 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
10 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 11 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
11 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
12 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 12 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
13 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 13 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
14 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO; 14 import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
@@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer; @@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
19 import cn.iocoder.yudao.module.system.service.member.MemberService; 19 import cn.iocoder.yudao.module.system.service.member.MemberService;
20 import cn.iocoder.yudao.module.system.service.user.AdminUserService; 20 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
21 import com.google.common.annotations.VisibleForTesting; 21 import com.google.common.annotations.VisibleForTesting;
  22 +import lombok.extern.slf4j.Slf4j;
22 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
23 24
24 import javax.annotation.Resource; 25 import javax.annotation.Resource;
@@ -35,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; @@ -35,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
35 * @author 芋道源码 36 * @author 芋道源码
36 */ 37 */
37 @Service 38 @Service
  39 +@Slf4j
38 public class SmsSendServiceImpl implements SmsSendService { 40 public class SmsSendServiceImpl implements SmsSendService {
39 41
40 @Resource 42 @Resource
@@ -158,11 +160,17 @@ public class SmsSendServiceImpl implements SmsSendService { @@ -158,11 +160,17 @@ public class SmsSendServiceImpl implements SmsSendService {
158 SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId()); 160 SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId());
159 Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId()); 161 Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId());
160 // 发送短信 162 // 发送短信
161 - SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),  
162 - message.getApiTemplateId(), message.getTemplateParams());  
163 - smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),  
164 - sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(),  
165 - sendResult.getData() != null ? sendResult.getData().getSerialNo() : null); 163 + try {
  164 + SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(),
  165 + message.getApiTemplateId(), message.getTemplateParams());
  166 + smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(),
  167 + sendResponse.getApiCode(), sendResponse.getApiMsg(),
  168 + sendResponse.getApiRequestId(), sendResponse.getSerialNo());
  169 + } catch (Throwable ex) {
  170 + log.error("[doSendSms][发送短信异常,日志编号({})]", message.getLogId(), ex);
  171 + smsLogService.updateSmsSendResult(message.getLogId(), false,
  172 + "EXCEPTION", ExceptionUtil.getRootCauseMessage(ex), null, null);
  173 + }
166 } 174 }
167 175
168 @Override 176 @Override
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
  3 +import cn.hutool.core.exceptions.ExceptionUtil;
  4 +import cn.hutool.core.lang.Assert;
3 import cn.hutool.core.util.ReUtil; 5 import cn.hutool.core.util.ReUtil;
4 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 8 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 9 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
  11 +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
10 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
11 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; 13 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; 14 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
@@ -21,11 +23,11 @@ import lombok.extern.slf4j.Slf4j; @@ -21,11 +23,11 @@ import lombok.extern.slf4j.Slf4j;
21 import org.springframework.cache.annotation.CacheEvict; 23 import org.springframework.cache.annotation.CacheEvict;
22 import org.springframework.cache.annotation.Cacheable; 24 import org.springframework.cache.annotation.Cacheable;
23 import org.springframework.stereotype.Service; 25 import org.springframework.stereotype.Service;
24 -import org.springframework.util.Assert;  
25 26
26 import javax.annotation.Resource; 27 import javax.annotation.Resource;
27 import java.util.List; 28 import java.util.List;
28 import java.util.Map; 29 import java.util.Map;
  30 +import java.util.Objects;
29 import java.util.regex.Pattern; 31 import java.util.regex.Pattern;
30 32
31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -171,9 +173,24 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { @@ -171,9 +173,24 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
171 // 获得短信模板 173 // 获得短信模板
172 SmsClient smsClient = smsChannelService.getSmsClient(channelId); 174 SmsClient smsClient = smsChannelService.getSmsClient(channelId);
173 Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); 175 Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
174 - SmsCommonResult<SmsTemplateRespDTO> templateResult = smsClient.getSmsTemplate(apiTemplateId);  
175 - // 校验短信模板是否正确  
176 - templateResult.checkError(); 176 + SmsTemplateRespDTO template;
  177 + try {
  178 + template = smsClient.getSmsTemplate(apiTemplateId);
  179 + } catch (Throwable ex) {
  180 + throw exception(SMS_TEMPLATE_API_ERROR, ExceptionUtil.getRootCauseMessage(ex));
  181 + }
  182 + // 校验短信模版
  183 + if (template == null) {
  184 + throw exception(SMS_TEMPLATE_API_NOT_FOUND);
  185 + }
  186 + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) {
  187 + throw exception(SMS_TEMPLATE_API_AUDIT_CHECKING);
  188 + }
  189 + if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) {
  190 + throw exception(SMS_TEMPLATE_API_AUDIT_FAIL, template.getAuditReason());
  191 + }
  192 + Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
  193 + String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus()));
177 } 194 }
178 195
179 @Override 196 @Override
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImplTest.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.sms; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.sms;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
6 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 7 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
@@ -172,22 +171,20 @@ public class SmsLogServiceImplTest extends BaseDbUnitTest { @@ -172,22 +171,20 @@ public class SmsLogServiceImplTest extends BaseDbUnitTest {
172 smsLogMapper.insert(dbSmsLog); 171 smsLogMapper.insert(dbSmsLog);
173 // 准备参数 172 // 准备参数
174 Long id = dbSmsLog.getId(); 173 Long id = dbSmsLog.getId();
175 - Integer sendCode = randomInteger();  
176 - String sendMsg = randomString(); 174 + Boolean success = randomBoolean();
177 String apiSendCode = randomString(); 175 String apiSendCode = randomString();
178 String apiSendMsg = randomString(); 176 String apiSendMsg = randomString();
179 String apiRequestId = randomString(); 177 String apiRequestId = randomString();
180 String apiSerialNo = randomString(); 178 String apiSerialNo = randomString();
181 179
182 // 调用 180 // 调用
183 - smsLogService.updateSmsSendResult(id, sendCode, sendMsg, 181 + smsLogService.updateSmsSendResult(id, success,
184 apiSendCode, apiSendMsg, apiRequestId, apiSerialNo); 182 apiSendCode, apiSendMsg, apiRequestId, apiSerialNo);
185 // 断言 183 // 断言
186 dbSmsLog = smsLogMapper.selectById(id); 184 dbSmsLog = smsLogMapper.selectById(id);
187 - assertEquals(CommonResult.isSuccess(sendCode) ? SmsSendStatusEnum.SUCCESS.getStatus()  
188 - : SmsSendStatusEnum.FAILURE.getStatus(), dbSmsLog.getSendStatus()); 185 + assertEquals(success ? SmsSendStatusEnum.SUCCESS.getStatus() : SmsSendStatusEnum.FAILURE.getStatus(),
  186 + dbSmsLog.getSendStatus());
189 assertNotNull(dbSmsLog.getSendTime()); 187 assertNotNull(dbSmsLog.getSendTime());
190 - assertEquals(sendMsg, dbSmsLog.getSendMsg());  
191 assertEquals(apiSendCode, dbSmsLog.getApiSendCode()); 188 assertEquals(apiSendCode, dbSmsLog.getApiSendCode());
192 assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg()); 189 assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg());
193 assertEquals(apiRequestId, dbSmsLog.getApiRequestId()); 190 assertEquals(apiRequestId, dbSmsLog.getApiRequestId());
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java
@@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue; @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; 6 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
8 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; 9 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
11 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 10 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
@@ -244,15 +243,14 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -244,15 +243,14 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
244 243
245 @Test 244 @Test
246 @SuppressWarnings("unchecked") 245 @SuppressWarnings("unchecked")
247 - public void testDoSendSms() { 246 + public void testDoSendSms() throws Throwable {
248 // 准备参数 247 // 准备参数
249 SmsSendMessage message = randomPojo(SmsSendMessage.class); 248 SmsSendMessage message = randomPojo(SmsSendMessage.class);
250 // mock SmsClientFactory 的方法 249 // mock SmsClientFactory 的方法
251 SmsClient smsClient = spy(SmsClient.class); 250 SmsClient smsClient = spy(SmsClient.class);
252 when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient); 251 when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
253 // mock SmsClient 的方法 252 // mock SmsClient 的方法
254 - SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class);  
255 - sendResult.setData(randomPojo(SmsSendRespDTO.class)); 253 + SmsSendRespDTO sendResult = randomPojo(SmsSendRespDTO.class);
256 when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()), 254 when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
257 eq(message.getTemplateParams()))).thenReturn(sendResult); 255 eq(message.getTemplateParams()))).thenReturn(sendResult);
258 256
@@ -260,8 +258,8 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { @@ -260,8 +258,8 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
260 smsService.doSendSms(message); 258 smsService.doSendSms(message);
261 // 断言 259 // 断言
262 verify(smsLogService).updateSmsSendResult(eq(message.getLogId()), 260 verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
263 - eq(sendResult.getCode()), eq(sendResult.getMsg()), eq(sendResult.getApiCode()),  
264 - eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getData().getSerialNo())); 261 + eq(sendResult.getSuccess()), eq(sendResult.getApiCode()),
  262 + eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getSerialNo()));
265 } 263 }
266 264
267 @Test 265 @Test
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
1 package cn.iocoder.yudao.module.system.service.sms; 1 package cn.iocoder.yudao.module.system.service.sms;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;  
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; 5 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
7 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 6 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
8 import cn.iocoder.yudao.framework.sms.core.client.SmsClient; 7 import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
9 -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;  
10 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; 8 import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
  9 +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
11 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 10 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; 11 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
13 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; 12 import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
@@ -65,7 +64,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -65,7 +64,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
65 64
66 @Test 65 @Test
67 @SuppressWarnings("unchecked") 66 @SuppressWarnings("unchecked")
68 - public void testCreateSmsTemplate_success() { 67 + public void testCreateSmsTemplate_success() throws Throwable {
69 // 准备参数 68 // 准备参数
70 SmsTemplateCreateReqVO reqVO = randomPojo(SmsTemplateCreateReqVO.class, o -> { 69 SmsTemplateCreateReqVO reqVO = randomPojo(SmsTemplateCreateReqVO.class, o -> {
71 o.setContent("正在进行登录操作{operation},您的验证码是{code}"); 70 o.setContent("正在进行登录操作{operation},您的验证码是{code}");
@@ -80,8 +79,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -80,8 +79,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
80 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); 79 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
81 // mock 获得 API 短信模板成功 80 // mock 获得 API 短信模板成功
82 when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); 81 when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
83 - when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,  
84 - o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); 82 + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(
  83 + randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus())));
85 84
86 // 调用 85 // 调用
87 Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); 86 Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO);
@@ -96,7 +95,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -96,7 +95,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
96 95
97 @Test 96 @Test
98 @SuppressWarnings("unchecked") 97 @SuppressWarnings("unchecked")
99 - public void testUpdateSmsTemplate_success() { 98 + public void testUpdateSmsTemplate_success() throws Throwable {
100 // mock 数据 99 // mock 数据
101 SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); 100 SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
102 smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 101 smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
@@ -115,8 +114,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { @@ -115,8 +114,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
115 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); 114 when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
116 // mock 获得 API 短信模板成功 115 // mock 获得 API 短信模板成功
117 when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); 116 when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
118 - when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,  
119 - o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); 117 + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(
  118 + randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus())));
120 119
121 // 调用 120 // 调用
122 smsTemplateService.updateSmsTemplate(reqVO); 121 smsTemplateService.updateSmsTemplate(reqVO);