Commit be20178f1207c76391dc45aebea0c001842e93ce
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 | 31 | * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序 |
| 32 | 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 | 49 | * @param apiTemplateId 短信 API 的模板编号 |
| 50 | 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 | 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 | 26 | * 短信 API 发送返回的序号 |
| 15 | 27 | */ |
| 16 | 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 | 1 | package cn.iocoder.yudao.framework.sms.core.client.impl; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.framework.common.core.KeyValue; | |
| 4 | 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 | 4 | import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties; |
| 11 | 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 | 17 | * 短信渠道配置 |
| 26 | 18 | */ |
| 27 | 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 | 41 | return; |
| 55 | 42 | } |
| 56 | 43 | log.info("[refresh][配置({})发生变化,重新初始化]", properties); |
| 57 | - this.properties = prepareProperties(properties); | |
| 58 | 44 | // 初始化 |
| 59 | 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 | 48 | @Override |
| 73 | 49 | public Long getId() { |
| 74 | 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 | 1 | package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.lang.Assert; |
| 4 | -import cn.hutool.core.util.ReflectUtil; | |
| 5 | -import cn.hutool.core.util.StrUtil; | |
| 6 | 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 | 7 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 9 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 10 | 9 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| 11 | 10 | import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; |
| 12 | 11 | import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; |
| 13 | 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 | 13 | import com.aliyuncs.DefaultAcsClient; |
| 19 | 14 | import com.aliyuncs.IAcsClient; |
| 20 | 15 | import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; |
| 16 | +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; | |
| 21 | 17 | import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; |
| 22 | -import com.aliyuncs.exceptions.ClientException; | |
| 18 | +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; | |
| 23 | 19 | import com.aliyuncs.profile.DefaultProfile; |
| 24 | 20 | import com.aliyuncs.profile.IClientProfile; |
| 25 | 21 | import com.fasterxml.jackson.annotation.JsonFormat; |
| ... | ... | @@ -31,9 +27,8 @@ import lombok.extern.slf4j.Slf4j; |
| 31 | 27 | import java.time.LocalDateTime; |
| 32 | 28 | import java.util.List; |
| 33 | 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 | 32 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 38 | 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 | 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 | 50 | * REGION, 使用杭州 |
| 51 | 51 | */ |
| 52 | 52 | private static final String ENDPOINT = "cn-hangzhou"; |
| ... | ... | @@ -57,7 +57,7 @@ public class AliyunSmsClient extends AbstractSmsClient { |
| 57 | 57 | private volatile IAcsClient client; |
| 58 | 58 | |
| 59 | 59 | public AliyunSmsClient(SmsChannelProperties properties) { |
| 60 | - super(properties, new AliyunSmsCodeMapping()); | |
| 60 | + super(properties); | |
| 61 | 61 | Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); |
| 62 | 62 | Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); |
| 63 | 63 | } |
| ... | ... | @@ -69,9 +69,9 @@ public class AliyunSmsClient extends AbstractSmsClient { |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 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 | 75 | SendSmsRequest request = new SendSmsRequest(); |
| 76 | 76 | request.setPhoneNumbers(mobile); |
| 77 | 77 | request.setSignName(properties.getSignature()); |
| ... | ... | @@ -79,34 +79,32 @@ public class AliyunSmsClient extends AbstractSmsClient { |
| 79 | 79 | request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); |
| 80 | 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 | 87 | @Override |
| 86 | - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { | |
| 88 | + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) { | |
| 87 | 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 | 96 | @Override |
| 99 | - protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) { | |
| 100 | - // 构建参数 | |
| 97 | + public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable { | |
| 98 | + // 构建请求 | |
| 101 | 99 | QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); |
| 102 | 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 | 110 | @VisibleForTesting |
| ... | ... | @@ -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 | 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 | 8 | import cn.hutool.crypto.digest.HmacAlgorithm; |
| 9 | 9 | import cn.hutool.http.HttpUtil; |
| 10 | 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 | 13 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 13 | 14 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 14 | 15 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| 15 | 16 | import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient; |
| 16 | 17 | import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; |
| 17 | 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 | 20 | import java.util.HashMap; |
| 22 | 21 | import java.util.List; |
| 23 | 22 | import java.util.Map; |
| 23 | +import java.util.Objects; | |
| 24 | 24 | |
| 25 | 25 | /** |
| 26 | 26 | * 基于钉钉 WebHook 实现的调试的短信客户端实现类 |
| ... | ... | @@ -32,7 +32,7 @@ import java.util.Map; |
| 32 | 32 | public class DebugDingTalkSmsClient extends AbstractSmsClient { |
| 33 | 33 | |
| 34 | 34 | public DebugDingTalkSmsClient(SmsChannelProperties properties) { |
| 35 | - super(properties, new DebugDingTalkCodeMapping()); | |
| 35 | + super(properties); | |
| 36 | 36 | Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); |
| 37 | 37 | Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); |
| 38 | 38 | } |
| ... | ... | @@ -42,8 +42,8 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | 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 | 48 | String url = buildUrl("robot/send"); |
| 49 | 49 | Map<String, Object> params = new HashMap<>(); |
| ... | ... | @@ -55,14 +55,15 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { |
| 55 | 55 | String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params)); |
| 56 | 56 | // 解析结果 |
| 57 | 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 | 68 | * @param path 请求路径 |
| 68 | 69 | * @return 请求地址 |
| ... | ... | @@ -82,15 +83,14 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient { |
| 82 | 83 | } |
| 83 | 84 | |
| 84 | 85 | @Override |
| 85 | - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { | |
| 86 | + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) { | |
| 86 | 87 | throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调"); |
| 87 | 88 | } |
| 88 | 89 | |
| 89 | 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 | 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 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 9 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 10 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 11 | 9 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 12 | 10 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| ... | ... | @@ -17,23 +15,22 @@ import com.fasterxml.jackson.annotation.JsonFormat; |
| 17 | 15 | import com.fasterxml.jackson.annotation.JsonProperty; |
| 18 | 16 | import com.google.common.annotations.VisibleForTesting; |
| 19 | 17 | import com.tencentcloudapi.common.Credential; |
| 20 | -import com.tencentcloudapi.common.exception.TencentCloudSDKException; | |
| 21 | 18 | import com.tencentcloudapi.sms.v20210111.SmsClient; |
| 22 | 19 | import com.tencentcloudapi.sms.v20210111.models.*; |
| 23 | 20 | import lombok.Data; |
| 24 | 21 | |
| 25 | 22 | import java.time.LocalDateTime; |
| 26 | 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 | 27 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 31 | 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 | 35 | * @author shiwp |
| 39 | 36 | */ |
| ... | ... | @@ -42,7 +39,7 @@ public class TencentSmsClient extends AbstractSmsClient { |
| 42 | 39 | /** |
| 43 | 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 | 45 | * REGION,使用南京 |
| ... | ... | @@ -51,180 +48,103 @@ public class TencentSmsClient extends AbstractSmsClient { |
| 51 | 48 | |
| 52 | 49 | /** |
| 53 | 50 | * 是否国际/港澳台短信: |
| 51 | + * | |
| 54 | 52 | * 0:表示国内短信。 |
| 55 | 53 | * 1:表示国际/港澳台短信。 |
| 56 | 54 | */ |
| 57 | - private static final long INTERNATIONAL = 0L; | |
| 55 | + private static final long INTERNATIONAL_CHINA = 0L; | |
| 58 | 56 | |
| 59 | 57 | private SmsClient client; |
| 60 | 58 | |
| 61 | 59 | public TencentSmsClient(SmsChannelProperties properties) { |
| 62 | - super(properties, new TencentSmsCodeMapping()); | |
| 60 | + super(properties); | |
| 63 | 61 | Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); |
| 62 | + validateSdkAppId(properties); | |
| 64 | 63 | } |
| 65 | 64 | |
| 66 | 65 | @Override |
| 67 | 66 | protected void doInit() { |
| 68 | 67 | // 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey |
| 69 | - Credential credential = new Credential(properties.getApiKey(), properties.getApiSecret()); | |
| 68 | + Credential credential = new Credential(getApiKey(), properties.getApiSecret()); | |
| 70 | 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 | 100 | SendSmsRequest request = new SendSmsRequest(); |
| 126 | - request.setSmsSdkAppId(((TencentSmsChannelProperties) properties).getSdkAppId()); | |
| 101 | + request.setSmsSdkAppId(getSdkAppId()); | |
| 127 | 102 | request.setPhoneNumberSet(new String[]{mobile}); |
| 128 | 103 | request.setSignName(properties.getSignature()); |
| 129 | 104 | request.setTemplateId(apiTemplateId); |
| 130 | 105 | request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue()))); |
| 131 | 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 | 114 | @Override |
| 136 | - protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable { | |
| 115 | + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) { | |
| 137 | 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 | 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 | 127 | DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest(); |
| 197 | 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 | 150 | @Data |
| ... | ... | @@ -278,7 +198,7 @@ public class TencentSmsClient extends AbstractSmsClient { |
| 278 | 198 | private String serialNo; |
| 279 | 199 | |
| 280 | 200 | /** |
| 281 | - * 用户的 session 内容(与发送接口的请求参数SessionContext一致) | |
| 201 | + * 用户的 session 内容(与发送接口的请求参数 SessionContext 一致) | |
| 282 | 202 | */ |
| 283 | 203 | @JsonProperty("ext") |
| 284 | 204 | private SessionContext sessionContext; |
| ... | ... | @@ -293,10 +213,7 @@ public class TencentSmsClient extends AbstractSmsClient { |
| 293 | 213 | * 发送短信记录id |
| 294 | 214 | */ |
| 295 | 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 | 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 | 1 | package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ReflectUtil; |
| 4 | -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 5 | 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 | 6 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 9 | 7 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 10 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| 11 | 9 | import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; |
| 12 | 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 | 12 | import com.aliyuncs.IAcsClient; |
| 17 | 13 | import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; |
| 18 | 14 | import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse; |
| 19 | 15 | import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; |
| 20 | 16 | import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; |
| 21 | -import com.aliyuncs.exceptions.ClientException; | |
| 22 | 17 | import com.google.common.collect.Lists; |
| 23 | -import org.junit.jupiter.api.Assertions; | |
| 24 | 18 | import org.junit.jupiter.api.Test; |
| 25 | 19 | import org.mockito.ArgumentMatcher; |
| 26 | 20 | import org.mockito.InjectMocks; |
| ... | ... | @@ -28,12 +22,10 @@ import org.mockito.Mock; |
| 28 | 22 | |
| 29 | 23 | import java.time.LocalDateTime; |
| 30 | 24 | import java.util.List; |
| 31 | -import java.util.function.Function; | |
| 32 | 25 | |
| 33 | 26 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 34 | 27 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 35 | 28 | import static org.junit.jupiter.api.Assertions.*; |
| 36 | -import static org.mockito.ArgumentMatchers.any; | |
| 37 | 29 | import static org.mockito.ArgumentMatchers.argThat; |
| 38 | 30 | import static org.mockito.Mockito.when; |
| 39 | 31 | |
| ... | ... | @@ -67,8 +59,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { |
| 67 | 59 | } |
| 68 | 60 | |
| 69 | 61 | @Test |
| 70 | - @SuppressWarnings("unchecked") | |
| 71 | - public void testDoSendSms() throws ClientException { | |
| 62 | + public void tesSendSms_success() throws Throwable { | |
| 72 | 63 | // 准备参数 |
| 73 | 64 | Long sendLogId = randomLongId(); |
| 74 | 65 | String mobile = randomString(); |
| ... | ... | @@ -87,20 +78,47 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { |
| 87 | 78 | }))).thenReturn(response); |
| 88 | 79 | |
| 89 | 80 | // 调用 |
| 90 | - SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile, | |
| 81 | + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, | |
| 91 | 82 | apiTemplateId, templateParams); |
| 92 | 83 | // 断言 |
| 84 | + assertTrue(result.getSuccess()); | |
| 85 | + assertEquals(response.getRequestId(), result.getApiRequestId()); | |
| 93 | 86 | assertEquals(response.getCode(), result.getApiCode()); |
| 94 | 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 | 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 | 120 | @Test |
| 103 | - public void testDoTParseSmsReceiveStatus() throws Throwable { | |
| 121 | + public void testParseSmsReceiveStatus() { | |
| 104 | 122 | // 准备参数 |
| 105 | 123 | String text = "[\n" + |
| 106 | 124 | " {\n" + |
| ... | ... | @@ -118,20 +136,21 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { |
| 118 | 136 | // mock 方法 |
| 119 | 137 | |
| 120 | 138 | // 调用 |
| 121 | - List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text); | |
| 139 | + List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text); | |
| 122 | 140 | // 断言 |
| 123 | 141 | assertEquals(1, statuses.size()); |
| 124 | 142 | assertTrue(statuses.get(0).getSuccess()); |
| 125 | 143 | assertEquals("DELIVERED", statuses.get(0).getErrorCode()); |
| 126 | 144 | assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); |
| 127 | 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 | 148 | assertEquals("12345", statuses.get(0).getSerialNo()); |
| 130 | 149 | assertEquals(67890L, statuses.get(0).getLogId()); |
| 131 | 150 | } |
| 132 | 151 | |
| 133 | 152 | @Test |
| 134 | - public void testDoGetSmsTemplate() throws ClientException { | |
| 153 | + public void testGetSmsTemplate() throws Throwable { | |
| 135 | 154 | // 准备参数 |
| 136 | 155 | String apiTemplateId = randomString(); |
| 137 | 156 | // mock 方法 |
| ... | ... | @@ -145,18 +164,12 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { |
| 145 | 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 | 175 | @Test |
| ... | ... | @@ -171,55 +184,4 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest { |
| 171 | 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 | 1 | package cn.iocoder.yudao.framework.sms.core.client.impl.tencent; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ReflectUtil; |
| 4 | -import cn.hutool.core.util.StrUtil; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 6 | -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | |
| 7 | 5 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
| 8 | 6 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 9 | 7 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 10 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 11 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 12 | 9 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 13 | 10 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| ... | ... | @@ -31,7 +28,6 @@ import java.util.List; |
| 31 | 28 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 32 | 29 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 33 | 30 | import static org.junit.jupiter.api.Assertions.*; |
| 34 | -import static org.junit.jupiter.api.Assertions.assertThrows; | |
| 35 | 31 | import static org.mockito.ArgumentMatchers.argThat; |
| 36 | 32 | import static org.mockito.Mockito.when; |
| 37 | 33 | |
| ... | ... | @@ -78,7 +74,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 78 | 74 | } |
| 79 | 75 | |
| 80 | 76 | @Test |
| 81 | - public void testDoSendSms() throws Throwable { | |
| 77 | + public void testDoSendSms_success() throws Throwable { | |
| 82 | 78 | // 准备参数 |
| 83 | 79 | Long sendLogId = randomLongId(); |
| 84 | 80 | String mobile = randomString(); |
| ... | ... | @@ -94,7 +90,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 94 | 90 | o.setSendStatusSet(sendStatuses); |
| 95 | 91 | SendStatus sendStatus = new SendStatus(); |
| 96 | 92 | sendStatuses[0] = sendStatus; |
| 97 | - sendStatus.setCode(TencentSmsClient.API_SUCCESS_CODE); | |
| 93 | + sendStatus.setCode(TencentSmsClient.API_CODE_SUCCESS); | |
| 98 | 94 | sendStatus.setMessage("send success"); |
| 99 | 95 | sendStatus.setSerialNo(serialNo); |
| 100 | 96 | }); |
| ... | ... | @@ -109,20 +105,58 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 109 | 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 | 112 | assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode()); |
| 116 | 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 | 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 | 158 | @Test |
| 125 | - public void testDoTParseSmsReceiveStatus() throws Throwable { | |
| 159 | + public void testParseSmsReceiveStatus() { | |
| 126 | 160 | // 准备参数 |
| 127 | 161 | String text = "[\n" + |
| 128 | 162 | " {\n" + |
| ... | ... | @@ -139,7 +173,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 139 | 173 | // mock 方法 |
| 140 | 174 | |
| 141 | 175 | // 调用 |
| 142 | - List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text); | |
| 176 | + List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text); | |
| 143 | 177 | // 断言 |
| 144 | 178 | assertEquals(1, statuses.size()); |
| 145 | 179 | assertTrue(statuses.get(0).getSuccess()); |
| ... | ... | @@ -152,7 +186,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 152 | 186 | } |
| 153 | 187 | |
| 154 | 188 | @Test |
| 155 | - public void testDoGetSmsTemplate() throws Throwable { | |
| 189 | + public void testGetSmsTemplate() throws Throwable { | |
| 156 | 190 | // 准备参数 |
| 157 | 191 | Long apiTemplateId = randomLongId(); |
| 158 | 192 | String requestId = randomString(); |
| ... | ... | @@ -173,50 +207,24 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest { |
| 173 | 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 | 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 | 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 | 82 | // ========== 短信模板 1-002-012-000 ========== |
| 83 | 83 | ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在"); |
| 84 | 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 | 90 | // ========== 短信发送 1-002-013-000 ========== |
| 87 | 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 | 63 | @ExcelProperty("发送时间") |
| 64 | 64 | private LocalDateTime sendTime; |
| 65 | 65 | |
| 66 | - @ExcelProperty("发送结果的编码") | |
| 67 | - private Integer sendCode; | |
| 68 | - | |
| 69 | - @ExcelProperty("发送结果的提示") | |
| 70 | - private String sendMsg; | |
| 71 | - | |
| 72 | 66 | @ExcelProperty("短信 API 发送结果的编码") |
| 73 | 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 | 52 | @Schema(description = "发送时间") |
| 53 | 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 | 55 | @Schema(description = "短信 API 发送结果的编码", example = "SUCCESS") |
| 62 | 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 | 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 | 3 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 6 | 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 | 7 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 9 | 8 | import com.baomidou.mybatisplus.annotation.TableField; |
| 10 | 9 | import com.baomidou.mybatisplus.annotation.TableName; |
| ... | ... | @@ -116,19 +115,6 @@ public class SmsLogDO extends BaseDO { |
| 116 | 115 | */ |
| 117 | 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 | 118 | * 短信 API 发送结果的编码 |
| 133 | 119 | * |
| 134 | 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 | 37 | * 更新日志的发送结果 |
| 38 | 38 | * |
| 39 | 39 | * @param id 日志编号 |
| 40 | - * @param sendCode 发送结果的编码 | |
| 41 | - * @param sendMsg 发送结果的提示 | |
| 40 | + * @param success 发送是否成功 | |
| 42 | 41 | * @param apiSendCode 短信 API 发送结果的编码 |
| 43 | 42 | * @param apiSendMsg 短信 API 发送失败的提示 |
| 44 | 43 | * @param apiRequestId 短信 API 发送返回的唯一请求 ID |
| 45 | 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 | 56 | * @param apiReceiveCode API 接收结果的编码 |
| 57 | 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 | 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 | 4 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO; |
| 5 | 5 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO; |
| 6 | 6 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO; |
| 8 | 8 | import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper; |
| 9 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 10 | 9 | import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum; |
| 11 | 10 | import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum; |
| 12 | 11 | import lombok.extern.slf4j.Slf4j; |
| ... | ... | @@ -55,13 +54,12 @@ public class SmsLogServiceImpl implements SmsLogService { |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | 56 | @Override |
| 58 | - public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, | |
| 57 | + public void updateSmsSendResult(Long id, Boolean success, | |
| 59 | 58 | String apiSendCode, String apiSendMsg, |
| 60 | 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 | 63 | .apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) |
| 66 | 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 | 1 | package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.exceptions.ExceptionUtil; | |
| 4 | 5 | import cn.hutool.core.lang.Assert; |
| 5 | 6 | import cn.hutool.core.util.StrUtil; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| ... | ... | @@ -8,7 +9,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 8 | 9 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 9 | 10 | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; |
| 10 | 11 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 11 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 12 | 12 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 13 | 13 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 14 | 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 | 19 | import cn.iocoder.yudao.module.system.service.member.MemberService; |
| 20 | 20 | import cn.iocoder.yudao.module.system.service.user.AdminUserService; |
| 21 | 21 | import com.google.common.annotations.VisibleForTesting; |
| 22 | +import lombok.extern.slf4j.Slf4j; | |
| 22 | 23 | import org.springframework.stereotype.Service; |
| 23 | 24 | |
| 24 | 25 | import javax.annotation.Resource; |
| ... | ... | @@ -35,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; |
| 35 | 36 | * @author 芋道源码 |
| 36 | 37 | */ |
| 37 | 38 | @Service |
| 39 | +@Slf4j | |
| 38 | 40 | public class SmsSendServiceImpl implements SmsSendService { |
| 39 | 41 | |
| 40 | 42 | @Resource |
| ... | ... | @@ -158,11 +160,17 @@ public class SmsSendServiceImpl implements SmsSendService { |
| 158 | 160 | SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId()); |
| 159 | 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 | 176 | @Override | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
| 1 | 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 | 5 | import cn.hutool.core.util.ReUtil; |
| 4 | 6 | import cn.hutool.core.util.StrUtil; |
| 5 | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 8 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 9 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 8 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 9 | 10 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| 11 | +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; | |
| 10 | 12 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; |
| 11 | 13 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; |
| 12 | 14 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO; |
| ... | ... | @@ -21,11 +23,11 @@ import lombok.extern.slf4j.Slf4j; |
| 21 | 23 | import org.springframework.cache.annotation.CacheEvict; |
| 22 | 24 | import org.springframework.cache.annotation.Cacheable; |
| 23 | 25 | import org.springframework.stereotype.Service; |
| 24 | -import org.springframework.util.Assert; | |
| 25 | 26 | |
| 26 | 27 | import javax.annotation.Resource; |
| 27 | 28 | import java.util.List; |
| 28 | 29 | import java.util.Map; |
| 30 | +import java.util.Objects; | |
| 29 | 31 | import java.util.regex.Pattern; |
| 30 | 32 | |
| 31 | 33 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| ... | ... | @@ -171,9 +173,24 @@ public class SmsTemplateServiceImpl implements SmsTemplateService { |
| 171 | 173 | // 获得短信模板 |
| 172 | 174 | SmsClient smsClient = smsChannelService.getSmsClient(channelId); |
| 173 | 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 | 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 | 2 | |
| 3 | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 6 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 6 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
| 8 | 7 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| ... | ... | @@ -172,22 +171,20 @@ public class SmsLogServiceImplTest extends BaseDbUnitTest { |
| 172 | 171 | smsLogMapper.insert(dbSmsLog); |
| 173 | 172 | // 准备参数 |
| 174 | 173 | Long id = dbSmsLog.getId(); |
| 175 | - Integer sendCode = randomInteger(); | |
| 176 | - String sendMsg = randomString(); | |
| 174 | + Boolean success = randomBoolean(); | |
| 177 | 175 | String apiSendCode = randomString(); |
| 178 | 176 | String apiSendMsg = randomString(); |
| 179 | 177 | String apiRequestId = randomString(); |
| 180 | 178 | String apiSerialNo = randomString(); |
| 181 | 179 | |
| 182 | 180 | // 调用 |
| 183 | - smsLogService.updateSmsSendResult(id, sendCode, sendMsg, | |
| 181 | + smsLogService.updateSmsSendResult(id, success, | |
| 184 | 182 | apiSendCode, apiSendMsg, apiRequestId, apiSerialNo); |
| 185 | 183 | // 断言 |
| 186 | 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 | 187 | assertNotNull(dbSmsLog.getSendTime()); |
| 190 | - assertEquals(sendMsg, dbSmsLog.getSendMsg()); | |
| 191 | 188 | assertEquals(apiSendCode, dbSmsLog.getApiSendCode()); |
| 192 | 189 | assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg()); |
| 193 | 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 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 7 | 7 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 8 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 9 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 10 | 9 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO; |
| 11 | 10 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| ... | ... | @@ -244,15 +243,14 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { |
| 244 | 243 | |
| 245 | 244 | @Test |
| 246 | 245 | @SuppressWarnings("unchecked") |
| 247 | - public void testDoSendSms() { | |
| 246 | + public void testDoSendSms() throws Throwable { | |
| 248 | 247 | // 准备参数 |
| 249 | 248 | SmsSendMessage message = randomPojo(SmsSendMessage.class); |
| 250 | 249 | // mock SmsClientFactory 的方法 |
| 251 | 250 | SmsClient smsClient = spy(SmsClient.class); |
| 252 | 251 | when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient); |
| 253 | 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 | 254 | when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()), |
| 257 | 255 | eq(message.getTemplateParams()))).thenReturn(sendResult); |
| 258 | 256 | |
| ... | ... | @@ -260,8 +258,8 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest { |
| 260 | 258 | smsService.doSendSms(message); |
| 261 | 259 | // 断言 |
| 262 | 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 | 265 | @Test | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.system.service.sms; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 5 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
| 7 | 6 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 8 | 7 | import cn.iocoder.yudao.framework.sms.core.client.SmsClient; |
| 9 | -import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult; | |
| 10 | 8 | import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO; |
| 9 | +import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum; | |
| 11 | 10 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 12 | 11 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO; |
| 13 | 12 | import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO; |
| ... | ... | @@ -65,7 +64,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 65 | 64 | |
| 66 | 65 | @Test |
| 67 | 66 | @SuppressWarnings("unchecked") |
| 68 | - public void testCreateSmsTemplate_success() { | |
| 67 | + public void testCreateSmsTemplate_success() throws Throwable { | |
| 69 | 68 | // 准备参数 |
| 70 | 69 | SmsTemplateCreateReqVO reqVO = randomPojo(SmsTemplateCreateReqVO.class, o -> { |
| 71 | 70 | o.setContent("正在进行登录操作{operation},您的验证码是{code}"); |
| ... | ... | @@ -80,8 +79,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 80 | 79 | when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); |
| 81 | 80 | // mock 获得 API 短信模板成功 |
| 82 | 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 | 86 | Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); |
| ... | ... | @@ -96,7 +95,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 96 | 95 | |
| 97 | 96 | @Test |
| 98 | 97 | @SuppressWarnings("unchecked") |
| 99 | - public void testUpdateSmsTemplate_success() { | |
| 98 | + public void testUpdateSmsTemplate_success() throws Throwable { | |
| 100 | 99 | // mock 数据 |
| 101 | 100 | SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); |
| 102 | 101 | smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 |
| ... | ... | @@ -115,8 +114,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest { |
| 115 | 114 | when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); |
| 116 | 115 | // mock 获得 API 短信模板成功 |
| 117 | 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 | 121 | smsTemplateService.updateSmsTemplate(reqVO); | ... | ... |