Commit d843d6a5a8329e89c0fa8f9e9f982b89091d0852

Authored by YunaiV
1 parent 5a1491d7

短信提交 2021-04-03,重构返回的结果

Showing 27 changed files with 201 additions and 196 deletions
src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.core;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +/**
  8 + * Key Value 的键值对
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +public class KeyValue<K, V> {
  16 +
  17 + private K key;
  18 + private V value;
  19 +
  20 +}
... ...
src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java
... ... @@ -8,6 +8,7 @@ import lombok.Data;
8 8 import org.springframework.util.Assert;
9 9  
10 10 import java.io.Serializable;
  11 +import java.util.Objects;
11 12  
12 13 /**
13 14 * 通用返回
... ... @@ -67,9 +68,13 @@ public class CommonResult&lt;T&gt; implements Serializable {
67 68 return result;
68 69 }
69 70  
  71 + public static boolean isSuccess(Integer code) {
  72 + return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
  73 + }
  74 +
70 75 @JsonIgnore // 避免 jackson 序列化
71 76 public boolean isSuccess() {
72   - return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code);
  77 + return isSuccess(GlobalErrorCodeConstants.SUCCESS.getCode());
73 78 }
74 79  
75 80 @JsonIgnore // 避免 jackson 序列化
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java
1 1 package cn.iocoder.dashboard.framework.sms.core.client;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
3 4 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail;
4 5 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
5 6  
6 7 import javax.servlet.ServletRequest;
7   -import java.util.Map;
  8 +import java.util.List;
8 9  
9 10 /**
10 11 * 短信客户端接口
... ... @@ -24,13 +25,13 @@ public interface SmsClient {
24 25 /**
25 26 * 发送消息
26 27 *
27   - * @param sendLogId 发送日志编号
  28 + * @param logId 日志编号
28 29 * @param mobile 手机号
29 30 * @param apiTemplateId 短信 API 的模板编号
30 31 * @param templateParams 短信模板参数
31 32 * @return 短信发送结果
32 33 */
33   - SmsCommonResult<SmsSendRespDTO> send(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams);
  34 + SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams);
34 35  
35 36 // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX
36 37 /**
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.dto;
3 3 import lombok.Data;
4 4  
5 5 /**
6   - * 短信发送响应 DTO
  6 + * 短信发送 Response DTO
7 7 *
8 8 * @author 芋道源码
9 9 */
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java
1 1 package cn.iocoder.dashboard.framework.sms.core.client.impl;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
3 5 import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
4 6 import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
5   -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
6 7 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
7 8 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
8 9 import lombok.extern.slf4j.Slf4j;
9 10  
10   -import java.util.Map;
  11 +import java.util.List;
11 12  
12 13 /**
13 14 * 短信客户端抽象类
... ... @@ -67,16 +68,16 @@ public abstract class AbstractSmsClient implements SmsClient {
67 68 }
68 69  
69 70 @Override
70   - public final SmsCommonResult<SmsSendRespDTO> send(Long sendLogId, String mobile,
71   - String apiTemplateId, Map<String, Object> templateParams) {
  71 + public final SmsCommonResult<SmsSendRespDTO> send(Long logId, String mobile,
  72 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
72 73 // 执行短信发送
73 74 SmsCommonResult<SmsSendRespDTO> result;
74 75 try {
75   - result = doSend(sendLogId, mobile, apiTemplateId, templateParams);
  76 + result = doSend(logId, mobile, apiTemplateId, templateParams);
76 77 } catch (Throwable ex) {
77 78 // 打印异常日志
78 79 log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
79   - sendLogId, mobile, apiTemplateId, templateParams, ex);
  80 + logId, mobile, apiTemplateId, templateParams, ex);
80 81 // 封装返回
81 82 return SmsCommonResult.error(ex);
82 83 }
... ... @@ -93,6 +94,7 @@ public abstract class AbstractSmsClient implements SmsClient {
93 94 * @return 短信发送结果
94 95 */
95 96 protected abstract SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile,
96   - String apiTemplateId, Map<String, Object> templateParams) throws Throwable;
  97 + String apiTemplateId, List<KeyValue<String, Object>> templateParams)
  98 + throws Throwable;
97 99  
98 100 }
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java
... ... @@ -3,12 +3,14 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
3 3 import cn.hutool.core.collection.CollectionUtil;
4 4 import cn.hutool.core.date.DateUtil;
5 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.dashboard.common.core.KeyValue;
6 7 import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
7 8 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail;
8 9 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
9 10 import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
10 11 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
11 12 import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
  13 +import cn.iocoder.dashboard.util.collection.MapUtils;
12 14 import cn.iocoder.dashboard.util.json.JsonUtils;
13 15 import com.aliyuncs.DefaultAcsClient;
14 16 import com.aliyuncs.IAcsClient;
... ... @@ -60,14 +62,14 @@ public class AliyunSmsClient extends AbstractSmsClient {
60 62  
61 63 @Override
62 64 protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile,
63   - String apiTemplateId, Map<String, Object> templateParams) throws Throwable {
  65 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
64 66 // 构建参数
65 67 SendSmsRequest request = new SendSmsRequest();
66 68 request.setSysMethod(MethodType.POST);
67 69 request.setPhoneNumbers(mobile);
68 70 request.setSignName(properties.getSignature());
69 71 request.setTemplateCode(apiTemplateId);
70   - request.setTemplateParam(JsonUtils.toJsonString(templateParams));
  72 + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
71 73 request.setOutId(String.valueOf(sendLogId));
72 74  
73 75 try {
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java
1 1 package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
2 2  
3 3 import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
4 5 import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
5 6  
6 7 import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
... ... @@ -15,7 +16,7 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping {
15 16 @Override
16 17 public ErrorCode apply(String apiCode) {
17 18 switch (apiCode) {
18   - case "OK": return null;
  19 + case "OK": return GlobalErrorCodeConstants.SUCCESS;
19 20 case "MissingAccessKeyId": return SMS_CHANNEL_API_KEY_MISSING;
20 21 case "isp.RAM_PERMISSION_DENY": return SMS_CHANNEL_PERMISSION_DENY;
21 22 case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR;
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java
... ... @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil;
6 6 import cn.hutool.core.util.CharsetUtil;
7 7 import cn.hutool.core.util.StrUtil;
8 8 import cn.hutool.core.util.URLUtil;
  9 +import cn.iocoder.dashboard.common.core.KeyValue;
9 10 import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
10 11 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail;
11 12 import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
... ... @@ -65,7 +66,7 @@ public class YunpianSmsClient extends AbstractSmsClient {
65 66  
66 67 @Override
67 68 protected SmsCommonResult<SmsSendRespDTO> doSend(Long sendLogId, String mobile,
68   - String apiTemplateId, Map<String, Object> templateParams) throws Throwable {
  69 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
69 70 // 构建参数
70 71 Map<String, String> request = new HashMap<>();
71 72 request.put(YunpianConstant.APIKEY, properties.getApiKey());
... ... @@ -89,13 +90,13 @@ public class YunpianSmsClient extends AbstractSmsClient {
89 90 data, codeMapping);
90 91 }
91 92  
92   - private static String formatTplValue(Map<String, Object> templateParams) {
  93 + private static String formatTplValue(List<KeyValue<String, Object>> templateParams) {
93 94 if (CollUtil.isEmpty(templateParams)) {
94 95 return "";
95 96 }
96 97 // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化
97 98 StringJoiner joiner = new StringJoiner("&");
98   - templateParams.forEach((key, value) -> joiner.add(String.format("#%s#=%s", key, URLUtil.encode(String.valueOf(value)))));
  99 + templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue())))));
99 100 return joiner.toString();
100 101 }
101 102  
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java
... ... @@ -12,7 +12,6 @@ import cn.iocoder.dashboard.common.exception.ErrorCode;
12 12 public interface SmsFrameworkErrorCodeConstants {
13 13  
14 14 // ========== 渠道相关 2001000100 ==========
15   - ErrorCode SMS_CHANNEL_CLIENT_NOT_EXISTS = new ErrorCode(2001000100, "短信渠道的客户端不存在");
16 15 ErrorCode SMS_CHANNEL_API_KEY_MISSING = new ErrorCode(2001000101, "API Key 不存在");
17 16 ErrorCode SMS_CHANNEL_PERMISSION_DENY = new ErrorCode(2001000102, "没有发送短信的权限");
18 17  
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java
... ... @@ -4,7 +4,6 @@ import cn.iocoder.dashboard.common.pojo.CommonResult;
4 4 import cn.iocoder.dashboard.common.pojo.PageResult;
5 5 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
6 6 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
7   -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
8 7 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
9 8 import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
10 9 import io.swagger.annotations.Api;
... ... @@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
13 12 import org.springframework.web.bind.annotation.*;
14 13  
15 14 import javax.annotation.Resource;
16   -import java.util.List;
17 15  
18 16 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
19 17  
... ... @@ -31,12 +29,6 @@ public class SmsChannelController {
31 29 return success(service.pageSmsChannels(reqVO));
32 30 }
33 31  
34   - @ApiOperation("获取渠道枚举")
35   - @GetMapping("/list/channel-enum")
36   - public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() {
37   - return success(service.getSmsChannelEnums());
38   - }
39   -
40 32 @ApiOperation("添加消息渠道")
41 33 @PostMapping("/create")
42 34 public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java deleted
1   -package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp;
2   -
3   -import io.swagger.annotations.ApiModel;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -import lombok.NoArgsConstructor;
7   -
8   -import java.io.Serializable;
9   -
10   -
11   -@ApiModel("用户分页 Request VO")
12   -@Data
13   -@NoArgsConstructor
14   -@EqualsAndHashCode
15   -public class SmsChannelEnumRespVO implements Serializable {
16   -
17   - private String code;
18   -
19   - private String name;
20   -
21   -}
src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java
1 1 package cn.iocoder.dashboard.modules.system.convert.sms;
2 2  
3   -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
4 3 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
5 4 import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
6 5 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
7   -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
8 6 import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
9 7 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
10 8 import org.mapstruct.Mapper;
... ... @@ -21,8 +19,6 @@ public interface SmsChannelConvert {
21 19  
22 20 SysSmsChannelDO convert(SysUserUpdateReqVO bean);
23 21  
24   - List<SmsChannelEnumRespVO> convertEnum(List<SmsChannelEnum> bean);
25   -
26 22 List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean);
27 23  
28 24 List<SmsChannelProperties> convertProperty(List<SmsChannelAllVO> list);
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java
... ... @@ -6,16 +6,18 @@ import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7 7 import lombok.Data;
8 8 import lombok.EqualsAndHashCode;
  9 +import lombok.ToString;
9 10  
10 11 /**
11   - * 短信渠道
  12 + * 短信渠道 DO
12 13 *
13 14 * @author zzf
14 15 * @since 2021-01-25
15 16 */
16   -@TableName(value = "sms_channel", autoResultMap = true)
  17 +@TableName(value = "sys_sms_channel", autoResultMap = true)
17 18 @Data
18 19 @EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
19 21 public class SysSmsChannelDO extends BaseDO {
20 22  
21 23 /**
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java
... ... @@ -2,28 +2,30 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
2 2  
3 3 import cn.iocoder.dashboard.common.enums.UserTypeEnum;
4 4 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
5   -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
  5 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
6 6 import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
  7 +import com.baomidou.mybatisplus.annotation.TableField;
7 8 import com.baomidou.mybatisplus.annotation.TableName;
  9 +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
8 10 import lombok.*;
9 11  
10 12 import java.util.Date;
11 13 import java.util.Map;
12 14  
13 15 /**
14   - * 短信发送日志
  16 + * 短信日志 DO
15 17 *
16 18 * @author zzf
17 19 * @since 2021-01-25
18 20 */
19   -@TableName(value = "sms_send_log", autoResultMap = true)
  21 +@TableName(value = "sys_sms_log", autoResultMap = true)
20 22 @Data
21 23 @EqualsAndHashCode(callSuper = true)
22 24 @ToString(callSuper = true)
23 25 @AllArgsConstructor
24 26 @NoArgsConstructor
25 27 @Builder
26   -public class SysSmsSendLogDO extends BaseDO {
  28 +public class SysSmsLogDO extends BaseDO {
27 29  
28 30 /**
29 31 * 自增编号
... ... @@ -48,7 +50,7 @@ public class SysSmsSendLogDO extends BaseDO {
48 50 // ========= 模板相关字段 =========
49 51  
50 52 /**
51   - * 短信模板编号
  53 + * 模板编号
52 54 *
53 55 * 关联 {@link SysSmsTemplateDO#getId()}
54 56 */
... ... @@ -70,8 +72,9 @@ public class SysSmsSendLogDO extends BaseDO {
70 72 */
71 73 private String templateContent;
72 74 /**
73   - * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容
  75 + * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的参数
74 76 */
  77 + @TableField(typeHandler = JacksonTypeHandler.class)
75 78 private Map<String, Object> templateParams;
76 79 /**
77 80 * 短信 API 的模板编号
... ... @@ -106,32 +109,32 @@ public class SysSmsSendLogDO extends BaseDO {
106 109 */
107 110 private Integer sendStatus;
108 111 /**
109   - * 时间发送时间
  112 + * 发送时间
110 113 */
111 114 private Date sendTime;
112 115 /**
113   - * 发送失败的类型
  116 + * 发送结果的编码
114 117 *
115   - * 枚举 {@link SmsSendFailureTypeEnum#getType()}
  118 + * 枚举 {@link SmsFrameworkErrorCodeConstants}
116 119 */
117   - private Integer sendFailureType;
  120 + private Integer sendCode;
118 121 /**
119   - * 发送失败的提示
  122 + * 发送结果的提示
120 123 *
121   - * 一般情况下,使用 {@link SmsSendFailureTypeEnum#getMsg()}
  124 + * 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants}
122 125 * 异常情况下,通过格式化 Exception 的提示存储
123 126 */
124   - private String sendFailureMsg;
  127 + private String sendMsg;
125 128 /**
126   - * 短信 API 发送失败的类型
  129 + * 短信 API 发送结果的编码
127 130 *
128 131 * 由于第三方的错误码可能是字符串,所以使用 String 类型
129 132 */
130   - private String apiSendFailureType;
  133 + private String apiSendCode;
131 134 /**
132 135 * 短信 API 发送失败的提示
133 136 */
134   - private String apiSendFailureMsg;
  137 + private String apiSendMsg;
135 138 /**
136 139 * 短信 API 发送返回的唯一请求 ID
137 140 *
... ... @@ -147,9 +150,9 @@ public class SysSmsSendLogDO extends BaseDO {
147 150  
148 151 // ========= 接收相关字段 =========
149 152  
150   - /**
151   - * 是否获取过结果[0否 1是]
152   - */
153   - private Integer gotResult;
  153 +// /**
  154 +// * 是否获取过结果[0否 1是]
  155 +// */
  156 +// private Integer gotResult;
154 157  
155 158 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java
... ... @@ -8,18 +8,20 @@ import com.baomidou.mybatisplus.annotation.TableName;
8 8 import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
9 9 import lombok.Data;
10 10 import lombok.EqualsAndHashCode;
  11 +import lombok.ToString;
11 12  
12 13 import java.util.List;
13 14  
14 15 /**
15   - * 短信模板
  16 + * 短信模板 DO
16 17 *
17 18 * @author zzf
18 19 * @since 2021-01-25
19 20 */
  21 +@TableName(value = "sys_sms_template", autoResultMap = true)
20 22 @Data
21 23 @EqualsAndHashCode(callSuper = true)
22   -@TableName(value = "sms_template", autoResultMap = true)
  24 +@ToString(callSuper = true)
23 25 public class SysSmsTemplateDO extends BaseDO {
24 26  
25 27 /**
... ... @@ -46,11 +48,11 @@ public class SysSmsTemplateDO extends BaseDO {
46 48 */
47 49 private String code;
48 50 /**
49   - * 名称
  51 + * 模板名称
50 52 */
51 53 private String name;
52 54 /**
53   - * 内容
  55 + * 模板内容
54 56 *
55 57 * 内容的参数,使用 {} 包括,例如说 {name}
56 58 */
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java
1 1 package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
2 2  
3 3 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
4   -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
  4 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
5 5 import org.apache.ibatis.annotations.Mapper;
6 6  
7 7 @Mapper
8   -public interface SysSmsSendLogMapper extends BaseMapperX<SysSmsSendLogDO> {
  8 +public interface SysSmsLogMapper extends BaseMapperX<SysSmsLogDO> {
9 9 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java
... ... @@ -16,6 +16,7 @@ public enum SysSmsSendStatusEnum {
16 16 INIT(0), // 初始化
17 17 SUCCESS(10), // 发送成功
18 18 FAILURE(20), // 发送失败
  19 + IGNORE(30), // 忽略,即不发送
19 20 ;
20 21  
21 22 private final int status;
... ...
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java
1 1 package cn.iocoder.dashboard.modules.system.mq.message.sms;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
3 4 import cn.iocoder.dashboard.framework.redis.core.stream.StreamMessage;
4 5 import lombok.Data;
5 6  
6 7 import javax.validation.constraints.NotNull;
7   -import java.util.Map;
  8 +import java.util.List;
8 9  
9 10 /**
10 11 * 短信发送消息
... ... @@ -15,10 +16,10 @@ import java.util.Map;
15 16 public class SysSmsSendMessage implements StreamMessage {
16 17  
17 18 /**
18   - * 发送日志编号
  19 + * 短信日志编号
19 20 */
20   - @NotNull(message = "发送日志编号不能为空")
21   - private Long sendLogId;
  21 + @NotNull(message = "短信日志编号不能为空")
  22 + private Long logId;
22 23 /**
23 24 * 手机号
24 25 */
... ... @@ -37,7 +38,7 @@ public class SysSmsSendMessage implements StreamMessage {
37 38 /**
38 39 * 短信模板参数
39 40 */
40   - private Map<String, Object> templateParams;
  41 + private List<KeyValue<String, Object>> templateParams;
41 42  
42 43 @Override
43 44 public String getStreamKey() {
... ...
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java
1 1 package cn.iocoder.dashboard.modules.system.mq.producer.sms;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
3 4 import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils;
4 5 import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
5 6 import lombok.extern.slf4j.Slf4j;
... ... @@ -7,7 +8,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
7 8 import org.springframework.stereotype.Component;
8 9  
9 10 import javax.annotation.Resource;
10   -import java.util.Map;
  11 +import java.util.List;
11 12  
12 13 /**
13 14 * 短信发送流消息监听器
... ... @@ -25,16 +26,15 @@ public class SysSmsProducer {
25 26 /**
26 27 * 发送短信 Message
27 28 *
28   - * @param sendLogId 发送日志编号
  29 + * @param logId 短信日志编号
29 30 * @param mobile 手机号
30 31 * @param channelId 渠道编号
31 32 * @param apiTemplateId 短信模板编号
32 33 * @param templateParams 短信模板参数
33   - * @param sendLogId 发送日志编号
34 34 */
35   - public void sendSmsSendMessage(Long sendLogId, String mobile,
36   - Long channelId, String apiTemplateId, Map<String, Object> templateParams) {
37   - SysSmsSendMessage message = new SysSmsSendMessage().setSendLogId(sendLogId).setMobile(mobile);
  35 + public void sendSmsSendMessage(Long logId, String mobile,
  36 + Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
  37 + SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile);
38 38 message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
39 39 RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message);
40 40 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java
... ... @@ -3,11 +3,8 @@ package cn.iocoder.dashboard.modules.system.service.sms;
3 3 import cn.iocoder.dashboard.common.pojo.PageResult;
4 4 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
5 5 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
6   -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
7 6 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
8 7  
9   -import java.util.List;
10   -
11 8 /**
12 9 * 短信渠道Service接口
13 10 *
... ... @@ -17,9 +14,9 @@ import java.util.List;
17 14 public interface SysSmsChannelService {
18 15  
19 16 /**
20   - * 初始化短信渠道并缓存短信模板信息
  17 + * 初始化短信客户端
21 18 */
22   - void initSmsClientAndCacheSmsTemplate();
  19 + void initSmsClients();
23 20  
24 21 /**
25 22 * 分页查询短信渠道信息
... ... @@ -37,11 +34,4 @@ public interface SysSmsChannelService {
37 34 */
38 35 Long createSmsChannel(SmsChannelCreateReqVO reqVO);
39 36  
40   - /**
41   - * 获取短信渠道枚举/渠道编码
42   - *
43   - * @return 短信渠道枚举/渠道编码
44   - */
45   - List<SmsChannelEnumRespVO> getSmsChannelEnums();
46   -
47 37 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java renamed to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java
... ... @@ -5,45 +5,40 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
5 5 import java.util.Map;
6 6  
7 7 /**
8   - * 短信发送日志服务接口
  8 + * 短信日志服务接口
9 9 *
10 10 * @author zzf
11 11 * @date 13:48 2021/3/2
12 12 */
13   -public interface SysSmsSendLogService {
  13 +public interface SysSmsLogService {
14 14  
15 15 /**
16   - * 创建发送日志
  16 + * 创建短信日志
17 17 *
18 18 * @param mobile 手机号
19 19 * @param userId 用户编号
20 20 * @param userType 用户类型
  21 + * @param isSend 是否发送
21 22 * @param template 短信模板
22 23 * @param templateContent 短信内容
23 24 * @param templateParams 短信参数
24   - * @return
  25 + * @return 发送日志编号
25 26 */
26   - Long createSmsSendLog(String mobile, Long userId, Integer userType,
27   - SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
  27 + Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
  28 + SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
28 29  
29 30 /**
30 31 * 更新发送日志的结果
31 32 *
32 33 * @param id 日志编号
33   - * @param success 是否成功
34   - * @param sendFailureType 发送失败的类型
35   - * @param sendFailureMsg 发送失败的提示
36   - * @param apiSendFailureType 短信 API 发送失败的类型
37   - * @param apiSendFailureMsg 短信 API 发送失败的提示
  34 + * @param sendCode 发送结果的编码
  35 + * @param sendMsg 发送结果的提示
  36 + * @param apiSendCode 短信 API 发送结果的编码
  37 + * @param apiSendMsg 短信 API 发送失败的提示
38 38 * @param apiRequestId 短信 API 发送返回的唯一请求 ID
39 39 * @param apiSerialNo 短信 API 发送返回的序号
40 40 */
41   - void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
42   - String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo);
43   -
44   - default void updateSmsSendLogFailure(Long id, SmsSendFailureTypeEnum sendFailureType) {
45   - updateSmsSendLogResult(id, false, sendFailureType.getType(), sendFailureType.getMsg(),
46   - null, null, null, null);
47   - }
  41 + void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
  42 + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo);
48 43  
49 44 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java
... ... @@ -3,21 +3,17 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl;
3 3 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.dashboard.common.pojo.PageResult;
5 5 import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
6   -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
7 6 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
8 7 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
9 8 import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
10   -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
11 9 import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert;
12 10 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
13 11 import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper;
14   -import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper;
15 12 import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
16 13 import org.springframework.stereotype.Service;
17 14  
18 15 import javax.annotation.PostConstruct;
19 16 import javax.annotation.Resource;
20   -import java.util.Arrays;
21 17 import java.util.List;
22 18  
23 19 /**
... ... @@ -35,12 +31,9 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
35 31 @Resource
36 32 private SysSmsChannelMapper channelMapper;
37 33  
38   - @Resource
39   - private SysSmsTemplateMapper templateMapper;
40   -
41 34 @Override
42 35 @PostConstruct
43   - public void initSmsClientAndCacheSmsTemplate() {
  36 + public void initSmsClients() {
44 37 // 查询有效渠道信息
45 38 List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
46 39 // 创建渠道 Client
... ... @@ -48,6 +41,8 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
48 41 propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
49 42 }
50 43  
  44 + // TODO 芋艿:刷新缓存
  45 +
51 46 @Override
52 47 public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
53 48 return channelMapper.selectChannelPage(reqVO);
... ... @@ -60,11 +55,6 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
60 55 return channelDO.getId();
61 56 }
62 57  
63   - @Override
64   - public List<SmsChannelEnumRespVO> getSmsChannelEnums() {
65   - return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
66   - }
67   -
68 58 // @Override
69 59 // public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
70 60 // List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus();
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java
1 1 package cn.iocoder.dashboard.modules.system.service.sms.impl;
2 2  
3   -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO;
4 5 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
5   -import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper;
6 7 import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
7   -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
  8 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
8 9 import lombok.extern.slf4j.Slf4j;
9 10 import org.springframework.stereotype.Service;
10 11  
... ... @@ -21,15 +22,18 @@ import java.util.Objects;
21 22 */
22 23 @Slf4j
23 24 @Service
24   -public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
  25 +public class SysSmsSendLogServiceImpl implements SysSmsLogService {
25 26  
26 27 @Resource
27   - private SysSmsSendLogMapper smsSendLogMapper;
  28 + private SysSmsLogMapper smsLogMapper;
28 29  
29 30 @Override
30   - public Long createSmsSendLog(String mobile, Long userId, Integer userType,
31   - SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
32   - SysSmsSendLogDO.SysSmsSendLogDOBuilder logBuilder = SysSmsSendLogDO.builder();
  31 + public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
  32 + SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
  33 + SysSmsLogDO.SysSmsLogDOBuilder logBuilder = SysSmsLogDO.builder();
  34 + // 根据是否要发送,设置状态
  35 + logBuilder.sendStatus(Objects.equals(isSend, true) ? SysSmsSendStatusEnum.INIT.getStatus()
  36 + : SysSmsSendStatusEnum.IGNORE.getStatus());
33 37 // 设置手机相关字段
34 38 logBuilder.mobile(mobile).userId(userId).userType(userType);
35 39 // 设置模板相关字段
... ... @@ -39,18 +43,18 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
39 43 logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode());
40 44  
41 45 // 插入数据库
42   - SysSmsSendLogDO logDO = logBuilder.build();
43   - smsSendLogMapper.insert(logDO);
  46 + SysSmsLogDO logDO = logBuilder.build();
  47 + smsLogMapper.insert(logDO);
44 48 return logDO.getId();
45 49 }
46 50  
47 51 @Override
48   - public void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
49   - String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo) {
50   - SysSmsSendStatusEnum sendStatus = Objects.equals(success, true) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE;
51   - smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendStatus(sendStatus.getStatus()).setSendTime(new Date())
52   - .setSendFailureType(sendFailureType).setSendFailureMsg(sendFailureMsg)
53   - .setApiSendFailureType(apiSendFailureType).setApiSendFailureMsg(apiSendFailureMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo));
  52 + public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
  53 + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
  54 + SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE;
  55 + smsLogMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date())
  56 + .sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
  57 + .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
54 58 }
55 59  
56 60 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java
1 1 package cn.iocoder.dashboard.modules.system.service.sms.impl;
2 2  
3   -import cn.hutool.core.collection.CollUtil;
4 3 import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.dashboard.common.core.KeyValue;
5 5 import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
6 6 import cn.iocoder.dashboard.common.enums.UserTypeEnum;
7   -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
8 7 import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
9 8 import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
10   -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
11 11 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
12 12 import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
13 13 import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
14 14 import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer;
15   -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
  15 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
  16 +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService;
16 17 import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
17 18 import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
18 19 import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
19 20 import lombok.extern.slf4j.Slf4j;
20 21 import org.springframework.stereotype.Service;
  22 +import org.springframework.util.Assert;
21 23  
22 24 import javax.annotation.Resource;
23 25 import javax.servlet.ServletRequest;
24 26 import java.util.List;
25 27 import java.util.Map;
26 28 import java.util.Objects;
  29 +import java.util.stream.Collectors;
27 30  
28 31 import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
29 32 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
... ... @@ -39,9 +42,11 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
39 42 public class SysSmsServiceImpl implements SysSmsService {
40 43  
41 44 @Resource
  45 + private SysSmsChannelService smsChannelService;
  46 + @Resource
42 47 private SysSmsTemplateService smsTemplateService;
43 48 @Resource
44   - private SysSmsSendLogService smsSendLogService;
  49 + private SysSmsLogService smsLogService;
45 50 @Resource
46 51 private SysSmsProducer smsProducer;
47 52 @Resource
... ... @@ -54,53 +59,58 @@ public class SysSmsServiceImpl implements SysSmsService {
54 59 public void sendSingleSms(String mobile, Long userId, Integer userType,
55 60 String templateCode, Map<String, Object> templateParams) {
56 61 // 校验短信模板是否合法
57   - SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams);
  62 + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
58 63 // 校验手机号码是否存在
59 64 mobile = this.checkMobile(mobile, userId, userType);
60 65  
61 66 // 创建发送日志
  67 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); // 如果模板被禁用,则不发送短信,只记录日志
62 68 String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams);
63   - Long sendLogId = smsSendLogService.createSmsSendLog(mobile, userId, userType, template, content, templateParams);
  69 + Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams);
64 70  
65   - // 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。
66   - if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) {
67   - smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE);
  71 + // 发送 MQ 消息,异步执行发送短信
  72 + if (!isSend) {
68 73 return;
69 74 }
70   - // 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台
71   - smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), templateParams);
  75 + List<KeyValue<String, Object>> newTemplateParams = this.buildTemplateParams(template, templateParams);
  76 + smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), newTemplateParams);
72 77 }
73 78  
74 79 @Override
75 80 public void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
76 81 String templateCode, Map<String, Object> templateParams) {
77 82 // 校验短信模板是否存在
78   - SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams);
  83 + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode);
79 84 }
80 85  
81   - private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map<String, Object> templateParams) {
  86 + private SysSmsTemplateDO checkSmsTemplateValid(String templateCode) {
82 87 // 短信模板不存在
83 88 SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode);
84 89 if (template == null) {
85 90 throw exception(SMS_TEMPLATE_NOT_EXISTS);
86 91 }
87   - // 参数不够
88   - if (CollUtil.isNotEmpty(template.getParams())) {
89   - template.getParams().forEach(param -> {
90   - if (!templateParams.containsKey(param)) {
91   - throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS);
92   - }
93   - });
94   - }
95   - // 移除多余参数
96   - if (CollUtil.isEmpty(template.getParams())) {
97   - templateParams.clear();
98   - } else {
99   - templateParams.entrySet().removeIf(entry -> !template.getParams().contains(entry.getKey()));
100   - }
101 92 return template;
102 93 }
103 94  
  95 + /**
  96 + * 将参数模板,处理成有序的 KeyValue 数组
  97 + *
  98 + * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023
  99 + *
  100 + * @param template 短信模板
  101 + * @param templateParams 原始参数
  102 + * @return 处理后的参数
  103 + */
  104 + private List<KeyValue<String, Object>> buildTemplateParams(SysSmsTemplateDO template, Map<String, Object> templateParams) {
  105 + return template.getParams().stream().map(key -> {
  106 + Object value = templateParams.get(key);
  107 + if (value == null) {
  108 + throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key);
  109 + }
  110 + return new KeyValue<>(key, value);
  111 + }).collect(Collectors.toList());
  112 + }
  113 +
104 114 private String checkMobile(String mobile, Long userId, Integer userType) {
105 115 mobile = getMobile(mobile, userId, userType);
106 116 if (StrUtil.isEmpty(mobile)) {
... ... @@ -130,15 +140,12 @@ public class SysSmsServiceImpl implements SysSmsService {
130 140 public void doSendSms(SysSmsSendMessage message) {
131 141 // 获得渠道对应的 SmsClient 客户端
132 142 SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
133   - if (smsClient == null) {
134   - log.error("[doSendSms][短信 message({}) 找不到对应的客户端]", message);
135   - smsSendLogService.updateSmsSendLogFailure(message.getSendLogId(), SmsSendFailureTypeEnum.SMS_CHANNEL_CLIENT_NOT_EXISTS);
136   - return;
137   - }
138   -
  143 + Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId()));
139 144 // 发送短信
140   - SmsCommonResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(),
  145 + SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.send(message.getLogId(), message.getMobile(),
141 146 message.getApiTemplateId(), message.getTemplateParams());
  147 + smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
  148 + sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), sendResult.getData().getSerialNo());
142 149 }
143 150  
144 151 @Override
... ...
src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java
... ... @@ -2,6 +2,8 @@ package cn.iocoder.dashboard.util.collection;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.CollectionUtil;
  5 +import cn.iocoder.dashboard.common.core.KeyValue;
  6 +import com.google.common.collect.Maps;
5 7 import com.google.common.collect.Multimap;
6 8  
7 9 import java.util.ArrayList;
... ... @@ -55,4 +57,10 @@ public class MapUtils {
55 57 consumer.accept(value);
56 58 }
57 59  
  60 + public static <K, V> Map<K, V> convertMap(List<KeyValue<K, V>> keyValues) {
  61 + Map<K, V> map = Maps.newLinkedHashMapWithExpectedSize(keyValues.size());
  62 + keyValues.forEach(keyValue -> map.put(keyValue.getKey(), keyValue.getValue()));
  63 + return map;
  64 + }
  65 +
58 66 }
... ...
src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java
1 1 package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
3 4 import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
4 6 import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
5 7 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
6 8 import org.junit.jupiter.api.Test;
7 9  
8   -import java.util.HashMap;
9   -import java.util.Map;
  10 +import java.util.ArrayList;
  11 +import java.util.List;
10 12  
11 13 /**
12 14 * {@link AliyunSmsClient} 的集成测试
... ... @@ -26,11 +28,11 @@ public class AliyunSmsClientTest {
26 28 AliyunSmsClient smsClient = new AliyunSmsClient(properties);
27 29 smsClient.init();
28 30 // 发送短信
29   - Map<String, Object> templateParams = new HashMap<>();
30   - templateParams.put("code", "1024");
  31 + List<KeyValue<String, Object>> templateParams = new ArrayList<>();
  32 + templateParams.add(new KeyValue<>("code", "1024"));
31 33 // templateParams.put("operation", "嘿嘿");
32 34 // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
33   - SmsCommonResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams);
  35 + SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams);
34 36 System.out.println(result);
35 37 }
36 38  
... ...
src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java
1 1 package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
2 2  
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
3 4 import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
4 6 import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
5 7 import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
6 8 import org.junit.jupiter.api.Test;
7 9  
8   -import java.util.HashMap;
9   -import java.util.Map;
  10 +import java.util.ArrayList;
  11 +import java.util.List;
10 12  
11 13 /**
12 14 * {@link YunpianSmsClient} 的集成测试
... ... @@ -25,11 +27,11 @@ public class YunpianSmsClientIntegrationTest {
25 27 YunpianSmsClient smsClient = new YunpianSmsClient(properties);
26 28 smsClient.init();
27 29 // 发送短信
28   - Map<String, Object> templateParams = new HashMap<>();
29   - templateParams.put("code", "1024");
30   - templateParams.put("operation", "嘿嘿");
  30 + List<KeyValue<String, Object>> templateParams = new ArrayList<>();
  31 + templateParams.add(new KeyValue<>("code", "1024"));
  32 + templateParams.add(new KeyValue<>("operation", "嘿嘿"));
31 33 // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams);
32   - SmsCommonResult result = smsClient.send(1L, "15601691399", "4383920", templateParams);
  34 + SmsCommonResult<SmsSendRespDTO> result = smsClient.send(1L, "15601691399", "4383920", templateParams);
33 35 System.out.println(result);
34 36 }
35 37  
... ...