From df8bda53e867f5c4d5b8b55157ca5b8163d661a6 Mon Sep 17 00:00:00 2001 From: zefeng_java <986510453@qq.com> Date: Wed, 27 Jan 2021 13:52:44 +0800 Subject: [PATCH 01/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 12 ++ sql/ruoyi-vue-pro.sql | 73 ++++++++++ .../dashboard/DashboardApplication.java | 30 ++-- .../common/enums/SmsChannelEnum.java | 33 +++++ .../dashboard/framework/msg/sms/SmsBody.java | 28 ++++ .../framework/msg/sms/SmsResult.java | 27 ++++ .../framework/msg/sms/SmsSender.java | 67 +++++++++ .../msg/sms/config/SmsConfiguration.java | 48 ++++++ .../sms/factory/DefaultSmsSenderFactory.java | 137 ++++++++++++++++++ .../msg/sms/impl/ali/AliSmsSender.java | 86 +++++++++++ .../AbstractSmsIntercepterChain.java | 38 +++++ .../DefaultSmsIntercepterChain.java | 20 +++ .../msg/sms/intercepter/SmsIntercepter.java | 41 ++++++ .../sms/intercepter/SmsLogIntercepter.java | 46 ++++++ .../msg/sms/proxy/DefaultSmsSenderProxy.java | 41 ++++++ .../msg/sms/proxy/SmsSenderProxy.java | 34 +++++ .../framework/redis/core/RedisKeyDefine.java | 42 ++---- .../redis/core/RedisKeyRegistry.java | 25 ---- .../controller/sms/SmsChannelController.java | 54 +++++++ .../controller/sms/SmsTemplateController.java | 84 +++++++++++ .../controller/sms/vo/SmsChannelAllVO.java | 58 ++++++++ .../msg/controller/sms/vo/SmsTemplateVO.java | 30 ++++ .../sms/vo/req/SmsChannelCreateReqVO.java | 44 ++++++ .../sms/vo/req/SmsChannelPageReqVO.java | 29 ++++ .../sms/vo/resp/SmsChannelEnumRespVO.java | 21 +++ .../sms/vo/resp/SmsChannelPageRespVO.java | 43 ++++++ .../msg/convert/sms/SmsChannelConvert.java | 34 +++++ .../msg/convert/sms/SmsTemplateConvert.java | 26 ++++ .../dal/mysql/dao/sms/SmsChannelMapper.java | 31 ++++ .../msg/dal/mysql/dao/sms/SmsLogMapper.java | 10 ++ .../dal/mysql/dao/sms/SmsTemplateMapper.java | 39 +++++ .../dal/mysql/daoobject/sms/SmsChannelDO.java | 65 +++++++++ .../msg/dal/mysql/daoobject/sms/SmsLog.java | 71 +++++++++ .../mysql/daoobject/sms/SmsTemplateDO.java | 81 +++++++++++ .../dashboard/modules/msg/package-info.java | 6 + .../msg/service/sms/SmsChannelService.java | 34 +++++ .../msg/service/sms/SmsLogService.java | 10 ++ .../msg/service/sms/SmsTemplateService.java | 10 ++ .../sms/impl/SmsChannelServiceImpl.java | 88 +++++++++++ .../service/sms/impl/SmsLogServiceImpl.java | 15 ++ .../sms/impl/SmsTemplateServiceImpl.java | 14 ++ .../system/enums/SysErrorCodeConstants.java | 7 + 42 files changed, 1660 insertions(+), 72 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyRegistry.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java diff --git a/pom.xml b/pom.xml index 39f97ab43..163aa1941 100644 --- a/pom.xml +++ b/pom.xml @@ -222,6 +222,18 @@ ${easyexcel.verion} + + com.aliyun + aliyun-java-sdk-core + 4.5.18 + + + + com.aliyun + aliyun-java-sdk-dysmsapi + 2.1.0 + + diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index af7f492f9..edba4204c 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -884,4 +884,77 @@ INSERT INTO `sys_user_role` VALUES (5, 100, 1, '', NULL, '', NULL, b'0'); INSERT INTO `sys_user_role` VALUES (6, 100, 2, '', NULL, '', NULL, b'0'); COMMIT; + +-- ---------------------------- +-- Table structure for sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS `sms_channel`; +CREATE TABLE `sms_channel` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `code` varchar(50) not null COMMENT '编码(来自枚举类 阿里、华为、七牛等)', + `api_key` varchar(100) NOT NULL COMMENT '账号id', -- add + `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', -- add + `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)', -- add + `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', + `name` varchar(50) not null COMMENT '名称', + `signature` varchar(50) not null COMMENT '签名值', + `remark` varchar(200) NOT NULL COMMENT '备注', + + `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)', + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠道'; +/* + 优先级值一样时,按照id顺序取值 +*/ + +-- ---------------------------- +-- Table structure for sms_template +-- ---------------------------- +DROP TABLE IF EXISTS `sms_template`; +CREATE TABLE `sms_template` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)', + `channel_id` bigint(20) not null COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', -- add + `type` tinyint(4) NOT NULL default 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]', + `biz_code` varchar(50) not null COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', -- add + `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(默认直接继承渠道表的,逻辑也与渠道表的一致,可以针对每个biz_code进行修改)',-- add + `code` varchar(50) not null COMMENT '编码', + `name` varchar(50) not null COMMENT '名称', + `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识', + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', -- add + `remark` varchar(200) NOT NULL COMMENT '备注', + + `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)', + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信模板'; + +-- ---------------------------- +-- Table structure for sms_log +-- ---------------------------- +DROP TABLE IF EXISTS `sms_log`; +CREATE TABLE `sms_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)', + `api_sms_id` varchar(50) not null COMMENT '实际渠道短信唯一标识', + `template_id` bigint(20) NOT NULL COMMENT '模板id', + `phone` char(11) not null COMMENT '手机号', + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `remark` varchar(200) NOT NULL COMMENT '备注', + `send_status` tinyint(4) NOT NULL default 0 COMMENT '发送状态(0发送中 1成功 2失败)', + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信日志'; + SET FOREIGN_KEY_CHECKS = 1; diff --git a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java index 32783aa8c..498bf63c7 100644 --- a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java +++ b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java @@ -1,15 +1,15 @@ -package cn.iocoder.dashboard; - -import de.codecentric.boot.admin.server.config.EnableAdminServer; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@EnableAdminServer -public class DashboardApplication { - - public static void main(String[] args) { - SpringApplication.run(DashboardApplication.class, args); - } - -} +//package cn.iocoder.dashboard; +// +//import de.codecentric.boot.admin.server.config.EnableAdminServer; +//import org.springframework.boot.SpringApplication; +//import org.springframework.boot.autoconfigure.SpringBootApplication; +// +//@SpringBootApplication +//@EnableAdminServer +//public class DashboardApplication { +// +// public static void main(String[] args) { +// SpringApplication.run(DashboardApplication.class, args); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java new file mode 100644 index 000000000..fdb80387d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java @@ -0,0 +1,33 @@ +package cn.iocoder.dashboard.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信渠道枚举 + * + * @author zzf + * @date 2021/1/25 10:56 + */ +@Getter +@AllArgsConstructor +public enum SmsChannelEnum { + + ALI("ALI", "阿里"), + HUA_WEI("HUA_WEI", "华为"), + QI_NIU("QI_NIU", "七牛"), + TEN_XUN("TEN_XUN", "腾讯"); + + private final String code; + + private final String name; + + public static SmsChannelEnum getByCode(String code) { + for (SmsChannelEnum value : SmsChannelEnum.values()) { + if (value.getCode().equals(code)) { + return value; + } + } + return null; + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java new file mode 100644 index 000000000..693838d4a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java @@ -0,0 +1,28 @@ +package cn.iocoder.dashboard.framework.msg.sms; + +import cn.iocoder.dashboard.util.json.JsonUtils; +import lombok.Data; + +import java.util.Map; + +/** + * 消息内容实体类 + */ +@Data +public class SmsBody { + + /** + * 模板编码 + */ + private String code; + + /** + * 参数列表 + */ + private Map params; + + public String getParamsStr() { + return JsonUtils.toJsonString(params); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java new file mode 100644 index 000000000..8a8741839 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java @@ -0,0 +1,27 @@ +package cn.iocoder.dashboard.framework.msg.sms; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 消息内容实体类 + */ +@Data +public class SmsResult implements Serializable { + + /** + * 是否成功 + */ + private Boolean success; + + /** + * 提示 + */ + private String message; + + /** + * 返回值 + */ + private T result; +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java new file mode 100644 index 000000000..30b10df61 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java @@ -0,0 +1,67 @@ +package cn.iocoder.dashboard.framework.msg.sms; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * 短信父接口 + * + * @author zzf + * @date 2021/1/25 14:14 + */ +public interface SmsSender { + + /** + * 发送通知 + * + * @param msgBody 通知内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + SmsResult send(SmsBody msgBody, Collection targets); + + /** + * 发送通知 + * + * @param msgBody 通知内容 + * @param target 发送对象列表 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody msgBody, String target) { + if (StringUtils.isBlank(target)) { + return failResult(); + } + + return send(msgBody, Collections.singletonList(target)); + } + + /** + * 发送通知 + * + * @param msgBody 通知内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody msgBody, String... targets) { + if (targets == null) { + return failResult(); + } + + return send(msgBody, Arrays.asList(targets)); + } + + default SmsResult failResult() { + SmsResult resultBody = new SmsResult<>(); + resultBody.setSuccess(false); + return resultBody; + } + + default SmsResult failResult(String message) { + SmsResult resultBody = failResult(); + resultBody.setMessage(message); + return resultBody; + } +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java new file mode 100644 index 000000000..7b5b26a5b --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java @@ -0,0 +1,48 @@ +package cn.iocoder.dashboard.framework.msg.sms.config; + +import cn.iocoder.dashboard.framework.msg.sms.factory.DefaultSmsSenderFactory; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.DefaultSmsIntercepterChain; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsLogIntercepter; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信服务配置 + * + * @author guer + */ +@Configuration +@ConditionalOnProperty("sms.enabled") +public class SmsConfiguration { + + @Resource + private SmsChannelService channelService; + + + @Bean + public AbstractSmsIntercepterChain smsIntercepterChain() { + DefaultSmsIntercepterChain intercepterChain = new DefaultSmsIntercepterChain(); + //添加拦截器 + intercepterChain.addSmsIntercepter(new SmsLogIntercepter()); + return intercepterChain; + } + + @Bean + public DefaultSmsSenderFactory smsSenderFactory(AbstractSmsIntercepterChain intercepterChain) { + DefaultSmsSenderFactory defaultSmsSenderFactory = new DefaultSmsSenderFactory(); + List smsChannelAllVOList = channelService.listChannelAllEnabledInfo(); + //初始化渠道、模板信息 + defaultSmsSenderFactory.init(smsChannelAllVOList); + //注入拦截器链 + defaultSmsSenderFactory.setIntercepterChain(intercepterChain); + return defaultSmsSenderFactory; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java new file mode 100644 index 000000000..123943a3d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java @@ -0,0 +1,137 @@ +package cn.iocoder.dashboard.framework.msg.sms.factory; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.common.exception.ServiceException; +import cn.iocoder.dashboard.framework.msg.sms.SmsSender; +import cn.iocoder.dashboard.framework.msg.sms.impl.ali.AliSmsSender; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; +import cn.iocoder.dashboard.framework.msg.sms.proxy.DefaultSmsSenderProxy; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO; +import lombok.Setter; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; + +/** + * 短信发送者工厂 + * + * @author zzf + * @date 2021/1/25 16:18 + */ +public class DefaultSmsSenderFactory { + + /** + * sender索引 + * key: {@link SmsTemplateVO#getBizCode()} + * value: {@link SmsSender} + */ + private final ConcurrentHashMap> bizCode2SenderMap = new ConcurrentHashMap<>(8); + + /** + * sender索引 + * key: {@link SmsTemplateVO#getCode()} + * value: {@link SmsSender} + */ + private final ConcurrentHashMap> templateCode2SenderMap = new ConcurrentHashMap<>(8); + + + @Setter + private AbstractSmsIntercepterChain intercepterChain; + + /** + * 读写锁 + */ + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + + + public void init(List smsChannelAllVOList) { + if (ObjectUtil.isEmpty(smsChannelAllVOList)) { + throw new ServiceException(SMS_CHANNEL_NOT_FOUND); + } + try { + writeLock.lock(); + addSender(smsChannelAllVOList); + } finally { + writeLock.unlock(); + } + } + + public SmsSender getSenderByBizCode(String bizCode) { + return getSmsSender(bizCode, bizCode2SenderMap); + } + + public SmsSender getSenderByTemplateCode(String templateCode) { + return getSmsSender(templateCode, templateCode2SenderMap); + } + + private SmsSender getSmsSender(String templateCode, ConcurrentHashMap> cacheMap) { + try { + readLock.lock(); + SmsSender smsSender = cacheMap.get(templateCode); + if (smsSender == null) { + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + return smsSender; + } finally { + readLock.unlock(); + } + } + + public void flush(List smsChannelAllVOList) { + try { + writeLock.lock(); + bizCode2SenderMap.clear(); + templateCode2SenderMap.clear(); + addSender(smsChannelAllVOList); + } finally { + writeLock.unlock(); + } + } + + + private void addSender(List smsChannelAllVOList) { + smsChannelAllVOList.forEach(channelAllVO -> addSender(SmsChannelEnum.getByCode(channelAllVO.getCode()), channelAllVO)); + } + + private void addSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { + if (channelEnum == null) { + throw new ServiceException(INVALID_CHANNEL_CODE); + } + List templateList = channelAllVO.getTemplateList(); + if (ObjectUtil.isEmpty(templateList)) { + throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); + } + + SmsSender aliSmsSender = getSender(channelEnum, channelAllVO); + + + templateList.forEach(smsTemplateVO -> { + bizCode2SenderMap.put(smsTemplateVO.getBizCode(), aliSmsSender); + templateCode2SenderMap.put(smsTemplateVO.getCode(), aliSmsSender); + }); + } + + private SmsSender getSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { + switch (channelEnum) { + case ALI: + return new DefaultSmsSenderProxy<>(new AliSmsSender(channelAllVO), intercepterChain); + // TODO fill more channel + default: + break; + } + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + + + + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java new file mode 100644 index 000000000..fbf6aeceb --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java @@ -0,0 +1,86 @@ +package cn.iocoder.dashboard.framework.msg.sms.impl.ali; + +import cn.iocoder.dashboard.framework.msg.sms.SmsBody; +import cn.iocoder.dashboard.framework.msg.sms.SmsResult; +import cn.iocoder.dashboard.framework.msg.sms.SmsSender; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; + +/** + * 阿里短信实现类 + * + * @author zzf + * @date 2021/1/25 14:17 + */ +@Slf4j +public class AliSmsSender implements SmsSender { + + private static final String OK = "OK"; + + private static final String PRODUCT = "Dysmsapi"; + + private static final String DOMAIN = "dysmsapi.aliyuncs.com"; + + private static final String ENDPOINT = "cn-hangzhou"; + + private final SmsChannelAllVO channelVO; + + private final IAcsClient acsClient; + + /** + * 构造阿里云短信发送处理 + * + * @param channelVO 阿里云短信配置 + */ + public AliSmsSender(SmsChannelAllVO channelVO) { + + this.channelVO = channelVO; + + String accessKeyId = channelVO.getApiKey(); + String accessKeySecret = channelVO.getApiSecret(); + + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); + DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); + + acsClient = new DefaultAcsClient(profile); + } + + + @Override + public SmsResult send(SmsBody msgBody, Collection targets) { + SendSmsRequest request = new SendSmsRequest(); + request.setSysMethod(MethodType.POST); + request.setPhoneNumbers(StringUtils.join(targets, ",")); + request.setSignName(channelVO.getApiSignatureId()); + request.setTemplateCode(channelVO.getTemplateByTemplateCode(msgBody.getCode()).getApiTemplateId()); + request.setTemplateParam(msgBody.getParamsStr()); + + try { + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + + boolean result = OK.equals(sendSmsResponse.getCode()); + if (!result) { + log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); + } + SmsResult resultBody = new SmsResult<>(); + resultBody.setSuccess(result); + resultBody.setResult(sendSmsResponse); + return resultBody; + } catch (Exception e) { + log.debug(e.getMessage(), e); + } + + return failResult(); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java new file mode 100644 index 000000000..f95de7128 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java @@ -0,0 +1,38 @@ +package cn.iocoder.dashboard.framework.msg.sms.intercepter; + +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +public abstract class AbstractSmsIntercepterChain { + + @Getter + protected final List intercepterList = new ArrayList<>(8); + + + /** + * 添加短信拦截器 + * + * @param smsIntercepter 短信拦截器 + */ + public void addSmsIntercepter(SmsIntercepter smsIntercepter) { + addSmsIntercepter(Collections.singletonList(smsIntercepter)); + } + + /** + * 添加短信拦截器 + * + * @param smsIntercepterList 短信拦截器数组 + */ + abstract void addSmsIntercepter(List smsIntercepterList); + + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java new file mode 100644 index 000000000..76d31906d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java @@ -0,0 +1,20 @@ +package cn.iocoder.dashboard.framework.msg.sms.intercepter; + +import java.util.Comparator; +import java.util.List; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +public class DefaultSmsIntercepterChain extends AbstractSmsIntercepterChain { + + @Override + public void addSmsIntercepter(List smsIntercepterList) { + intercepterList.addAll(smsIntercepterList); + //排序 + intercepterList.sort(Comparator.comparingInt(SmsIntercepter::getOrder)); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java new file mode 100644 index 000000000..df83c8d6a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java @@ -0,0 +1,41 @@ +package cn.iocoder.dashboard.framework.msg.sms.intercepter; + +import cn.iocoder.dashboard.framework.msg.sms.SmsBody; +import cn.iocoder.dashboard.framework.msg.sms.SmsResult; + +import java.util.Collection; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +public interface SmsIntercepter { + + /** + * 监听发送前 + * + * @param msgBody 消息体 + * @param targets 发送对象数组 + */ + void beforeSender(SmsBody msgBody, Collection targets); + + /** + * 监听发送后 + * + * @param msgBody 消息体 + * @param targets 发送对象数组 + * @param resultBody 返回对象 + */ + void afterSender(SmsBody msgBody, Collection targets, SmsResult resultBody); + + /** + * 排序值,拦截器根据order值顺序执行 + *

+ * 值越小,越早执行 + * + * @return 排序值 + */ + int getOrder(); +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java new file mode 100644 index 000000000..9a7effd95 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java @@ -0,0 +1,46 @@ +package cn.iocoder.dashboard.framework.msg.sms.intercepter; + +import cn.iocoder.dashboard.framework.msg.sms.SmsBody; +import cn.iocoder.dashboard.framework.msg.sms.SmsResult; +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsLogMapper; +import cn.iocoder.dashboard.util.json.JsonUtils; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; + +/** + * 短信日志拦截器 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +@Slf4j +public class SmsLogIntercepter implements SmsIntercepter { + + + @Override + public void beforeSender(SmsBody msgBody, Collection targets) { + log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets); + + } + + @Override + public void afterSender(SmsBody msgBody, Collection targets, SmsResult resultBody) { + if (resultBody.getSuccess()) { + // + } else { + log.warn("send sms fail, body: {}, target: {}, resultBody: {}", + JsonUtils.toJsonString(msgBody), + targets, + JsonUtils.toJsonString(resultBody) + ); + } + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java new file mode 100644 index 000000000..f9d7e566f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java @@ -0,0 +1,41 @@ +package cn.iocoder.dashboard.framework.msg.sms.proxy; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.dashboard.framework.msg.sms.SmsBody; +import cn.iocoder.dashboard.framework.msg.sms.SmsResult; +import cn.iocoder.dashboard.framework.msg.sms.SmsSender; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; + +import java.util.Collection; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +public class DefaultSmsSenderProxy implements SmsSender { + + private final SmsSender smsSender; + private final AbstractSmsIntercepterChain chain; + + @Override + public SmsResult send(SmsBody msgBody, Collection targets) { + if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) { + chain.getIntercepterList().forEach(s -> s.beforeSender(msgBody, targets)); + } + + SmsResult resultBody = smsSender.send(msgBody, targets); + + if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) { + chain.getIntercepterList().forEach(s -> s.afterSender(msgBody, targets, resultBody)); + } + return resultBody; + } + + public DefaultSmsSenderProxy(SmsSender smsSender, + AbstractSmsIntercepterChain chain) { + this.smsSender = smsSender; + this.chain = chain; + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java new file mode 100644 index 000000000..069916e2a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.framework.msg.sms.proxy; + +import cn.iocoder.dashboard.framework.msg.sms.SmsSender; +import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsIntercepter; + +import java.util.Collections; +import java.util.List; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +public interface SmsSenderProxy extends SmsSender { + + /** + * 添加短信拦截器 + * + * @param smsIntercepter 短信拦截器 + */ + default void addSmsIntercepter(SmsIntercepter smsIntercepter) { + addSmsIntercepter(Collections.singletonList(smsIntercepter)); + } + + /** + * 添加短信拦截器 + * + * @param smsIntercepterList 短信拦截器数组 + */ + void addSmsIntercepter(List smsIntercepterList); + + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyDefine.java b/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyDefine.java index b9adcc3f1..ee3a342a0 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyDefine.java +++ b/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyDefine.java @@ -1,8 +1,6 @@ package cn.iocoder.dashboard.framework.redis.core; -import lombok.AllArgsConstructor; import lombok.Data; -import lombok.Getter; import java.time.Duration; @@ -26,20 +24,15 @@ public class RedisKeyDefine { } - @Getter - @AllArgsConstructor - public enum TimeoutTypeEnum { + /** + * 过期时间 - 永不过期 + */ + public static final Duration TIMEOUT_FOREVER = null; - FOREVER(1), // 永不超时 - DYNAMIC(2), // 动态超时 - FIXED(3); // 固定超时 - - /** - * 类型 - */ - private final Integer type; - - } + /** + * 过期时间 - 动态,通过参数传入 + */ + public static final Duration TIMEOUT_DYNAMIC = null; /** * Key 模板 @@ -55,12 +48,10 @@ public class RedisKeyDefine { * 如果是使用分布式锁,设置为 {@link java.util.concurrent.locks.Lock} 类型 */ private final Class valueType; - /** - * 超时类型 - */ - private final TimeoutTypeEnum timeoutType; /** * 过期时间 + * + * 为空时,表示永不过期 {@link #TIMEOUT_FOREVER} */ private final Duration timeout; @@ -68,20 +59,7 @@ public class RedisKeyDefine { this.keyTemplate = keyTemplate; this.keyType = keyType; this.valueType = valueType; - this.timeoutType = TimeoutTypeEnum.FIXED; this.timeout = timeout; - // 添加注册表 - RedisKeyRegistry.add(this); - } - - public RedisKeyDefine(String keyTemplate, KeyTypeEnum keyType, Class valueType, TimeoutTypeEnum timeoutType) { - this.keyTemplate = keyTemplate; - this.keyType = keyType; - this.valueType = valueType; - this.timeoutType = timeoutType; - this.timeout = Duration.ZERO; - // 添加注册表 - RedisKeyRegistry.add(this); } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyRegistry.java b/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyRegistry.java deleted file mode 100644 index 4a220fbd0..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyRegistry.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.dashboard.framework.redis.core; - -import java.util.ArrayList; -import java.util.List; - -/** - * {@link RedisKeyDefine} 注册表 - */ -public class RedisKeyRegistry { - - private static final List defines = new ArrayList<>(); - - public static void add(RedisKeyDefine define) { - defines.add(define); - } - - public static List list() { - return defines; - } - - public static int size() { - return defines.size(); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java new file mode 100644 index 000000000..c28d9b862 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java @@ -0,0 +1,54 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms; + +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.dashboard.common.pojo.CommonResult.success; + +@Api("短信 渠道/签名 API") +@RestController +@RequestMapping("/sms/channel") +public class SmsChannelController { + + @Resource + private SmsChannelService service; + + @ApiOperation("获取渠道/签名分页") + @GetMapping("/page") + public CommonResult> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { + return success(service.pageChannels(reqVO)); + } + + @ApiOperation("获取渠道枚举") + @GetMapping("/list/channel-enum") + public CommonResult> getChannelEnums() { + return success(service.getChannelEnums()); + } + + + @ApiOperation("添加消息渠道") + @PostMapping("/create") + public CommonResult add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { + return success(service.createChannel(reqVO)); + } + + @ApiOperation("刷新消息渠道信息") + @PutMapping("/flush") + public CommonResult flushChannel() { + return success(service.flushChannel()); + } + + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java new file mode 100644 index 000000000..8bd73b12e --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java @@ -0,0 +1,84 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms; + +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginReqVO; +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginRespVO; +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO; +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; +import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; +import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; +import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; +import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; +import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; +import cn.iocoder.dashboard.util.collection.SetUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.dashboard.common.pojo.CommonResult.success; +import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId; +import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds; + +@Api("认证 API") +@RestController +@RequestMapping("/sms/template") +public class SmsTemplateController { + + @Resource + private SysAuthService authService; + @Resource + private SysUserService userService; + @Resource + private SysRoleService roleService; + @Resource + private SysPermissionService permissionService; + + @ApiOperation("使用账号密码登录") + @PostMapping("/login") + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 + public CommonResult login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { + String token = authService.login(reqVO.getUsername(), reqVO.getPassword(), reqVO.getUuid(), reqVO.getCode()); + // 返回结果 + return success(SysAuthLoginRespVO.builder().token(token).build()); + } + + @ApiOperation("获取登陆用户的权限信息") + @GetMapping("/get-permission-info") + public CommonResult getPermissionInfo() { + // 获得用户信息 + SysUserDO user = userService.getUser(getLoginUserId()); + if (user == null) { + return null; + } + // 获得角色列表 + List roleList = roleService.listRolesFromCache(getLoginUserRoleIds()); + // 获得菜单列表 + List menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(), + SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()), + SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); + // 拼接结果返回 + return success(SysAuthConvert.INSTANCE.convert(user, roleList, menuList)); + } + + @ApiOperation("获得登陆用户的菜单列表") + @GetMapping("list-menus") + public CommonResult> listMenus() { + // 获得用户拥有的菜单列表 + List menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(), + SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 + SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 + // 转换成 Tree 结构返回 + return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList)); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java new file mode 100644 index 000000000..bac72c959 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.List; + +/** + * 渠道(包含模板)信息VO类 + * + * @author zzf + * @date 2021/1/25 17:01 + */ +@Data +@EqualsAndHashCode +public class SmsChannelAllVO implements Serializable { + + /** + * id + */ + private Long id; + + /** + * 编码(来自枚举类 阿里、华为、七牛等) + */ + private String code; + + /** + * 渠道账号id + */ + private String apiKey; + + /** + * 渠道账号秘钥 + */ + private String apiSecret; + + /** + * 实际渠道签名唯一标识 + */ + private String apiSignatureId; + + /** + * 签名值 + */ + private String signature; + + /** + * 该渠道名下的短信模板集合 + */ + private List templateList; + + public SmsTemplateVO getTemplateByTemplateCode(String tempCode) { + return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get(); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java new file mode 100644 index 000000000..04bfe9a62 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 渠道模板VO类 + * + * @author zzf + * @date 2021/1/25 17:03 + */ +@Data +@EqualsAndHashCode +public class SmsTemplateVO { + + /** + * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) + */ + private String bizCode; + /** + * 编码 + */ + private String code; + + /** + * 实际渠道模板唯一标识 + */ + private String apiTemplateId; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java new file mode 100644 index 000000000..729088b65 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + + +@ApiModel("消息渠道创建 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +public class SmsChannelCreateReqVO implements Serializable { + + @ApiModelProperty("编码(来自枚举类 阿里、华为、七牛等)") + private String code; + + @ApiModelProperty("渠道账号id") + private String apiKey; + + @ApiModelProperty("渠道账号秘钥") + private String apiSecret; + + @ApiModelProperty("优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)") + private Integer priority; + + @ApiModelProperty("名称") + private String name; + + @ApiModelProperty("签名值") + private String signature; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("启用状态(0正常 1停用)") + private Integer status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java new file mode 100644 index 000000000..dd2df146e --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req; + +import cn.iocoder.dashboard.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("消息渠道分页 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SmsChannelPageReqVO extends PageParam { + + @ApiModelProperty(value = "渠道名", example = "阿里", notes = "模糊匹配") + private String name; + + @ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配") + private String signature; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java new file mode 100644 index 000000000..a3e56e0ca --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + + +@ApiModel("用户分页 Request VO") +@Data +@NoArgsConstructor +@EqualsAndHashCode +public class SmsChannelEnumRespVO implements Serializable { + + private String code; + + private String name; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java new file mode 100644 index 000000000..603f13e07 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java @@ -0,0 +1,43 @@ +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp; + +import cn.iocoder.dashboard.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("用户分页 Request VO") +@Data +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SmsChannelPageRespVO extends PageParam { + + @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配") + private String username; + + @ApiModelProperty(value = "手机号码", example = "yudao", notes = "模糊匹配") + private String mobile; + + @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类") + private Integer status; + + @ApiModelProperty(value = "开始时间", example = "2020-10-24") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date beginTime; + + @ApiModelProperty(value = "结束时间", example = "2020-10-24") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endTime; + + @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门") + private Long deptId; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java new file mode 100644 index 000000000..4728586a3 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.modules.msg.convert.sms; + +import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SmsChannelConvert { + + SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); + + @Mapping(source = "records", target = "list") + PageResult convertPage(IPage page); + + SmsChannelDO convert(SmsChannelCreateReqVO bean); + + SmsChannelDO convert(SysUserUpdateReqVO bean); + + List convertEnum(List bean); + + List convert(List bean); + + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java new file mode 100644 index 000000000..313e06c92 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java @@ -0,0 +1,26 @@ +package cn.iocoder.dashboard.modules.msg.convert.sms; + +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SmsTemplateConvert { + + SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class); + + @Mapping(source = "records", target = "list") + PageResult convertPage(IPage page); + + List convert(List bean); + + SmsTemplateVO convert(SmsTemplateDO bean); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java new file mode 100644 index 000000000..f7ede3502 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java @@ -0,0 +1,31 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; + +import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SmsChannelMapper extends BaseMapper { + + default IPage selectChannelPage(SmsChannelPageReqVO reqVO) { + return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper() + .like(StrUtil.isNotBlank(reqVO.getName()), SmsChannelDO::getName, reqVO.getName()) + .like(StrUtil.isNotBlank(reqVO.getSignature()), SmsChannelDO::getName, reqVO.getSignature()) + ); + } + + default List selectEnabledList() { + return selectList(new LambdaQueryWrapper() + .eq(SmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SmsChannelDO::getId) + ); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java new file mode 100644 index 000000000..263783b47 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java @@ -0,0 +1,10 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; + +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SmsLogMapper extends BaseMapper { + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java new file mode 100644 index 000000000..f2d2fb21b --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; + +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SmsTemplateMapper extends BaseMapper { + + /** + * 根据短信渠道id查询短信模板集合 + * + * @param channelId 渠道id + * @return 模板集合 + */ + default List selectListByChannelId(Long channelId) { + return selectList(new LambdaQueryWrapper() + .eq(SmsTemplateDO::getChannelId, channelId) + .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SmsTemplateDO::getId) + ); + } + + /** + * 查询有效短信模板集合 + * + * @return 有效短信模板集合 + */ + default List selectEnabledList() { + return selectList(new LambdaQueryWrapper() + .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SmsTemplateDO::getId) + ); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java new file mode 100644 index 000000000..3c0b5f396 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java @@ -0,0 +1,65 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; + +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +/** + * 短信渠道 + * + * @author zzf + * @since 2021-01-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "sms_channel", autoResultMap = true) +public class SmsChannelDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + /** + * 编码(来自枚举类 阿里、华为、七牛等) + */ + private String code; + + /** + * 渠道账号id + */ + private String apiKey; + + /** + * 渠道账号秘钥 + */ + private String apiSecret; + + /** + * 实际渠道签名唯一标识 + */ + private String apiSignatureId; + + /** + * 名称 + */ + private String name; + + /** + * 签名值 + */ + private String signature; + + /** + * 备注 + */ + private String remark; + + /** + * 启用状态(0正常 1停用) + */ + private Integer status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java new file mode 100644 index 000000000..e5af0471e --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java @@ -0,0 +1,71 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + * 短信日志 + * + * @author zzf + * @since 2021-01-25 + */ +@Data +@EqualsAndHashCode +@TableName(value = "sms_log", autoResultMap = true) +public class SmsLog implements Serializable { + + /** + * 自增编号 + */ + private Long id; + + /** + * 短信渠道编码(来自枚举类) + */ + private String channelCode; + + /** + * 实际渠道短信唯一标识 + */ + private String apiSmsId; + + /** + * 模板id + */ + private Long templateId; + + /** + * 手机号 + */ + private String phone; + + /** + * 内容 + */ + private String content; + + /** + * 备注 + */ + private String remark; + + /** + * 发送状态(0发送中 1成功 2失败) + */ + private Integer sendStatus; + + /** + * 创建者 + */ + private String createBy; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java new file mode 100644 index 000000000..39257a71d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java @@ -0,0 +1,81 @@ +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; + +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +/** + * 短信模板 + * + * @author zzf + * @since 2021-01-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName(value = "sms_template", autoResultMap = true) +public class SmsTemplateDO extends BaseDO { + + /** + * 自增编号 + */ + private Long id; + + /** + * 短信渠道编码(来自枚举类) + */ + private String channelCode; + + /** + * 短信渠道id (对于前端来说就是绑定一个签名) + */ + private Long channelId; + + /** + * 消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息] + */ + private Integer type; + + /** + * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) + */ + private String bizCode; + + /** + * 编码 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 实际渠道模板唯一标识 + */ + private String apiTemplateId; + + /** + * 内容 + */ + private String content; + + /** + * 参数数组(自动根据内容生成) + */ + private String params; + + /** + * 备注 + */ + private String remark; + + /** + * 启用状态(0正常 1停用) + */ + private Integer status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java b/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java new file mode 100644 index 000000000..3a0e7635c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java @@ -0,0 +1,6 @@ +/** + * msg 包,专门专门用于发送消息的功能,支撑上层的通用与核心业务。 + * 例如说:短信、邮件、app通知等等 + * + */ +package cn.iocoder.dashboard.modules.msg; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java new file mode 100644 index 000000000..ed2c047e8 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.modules.msg.service.sms; + +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; + +import java.util.List; + +/** + * 短信渠道Service接口 + * + * @author zzf + * @date 2021/1/25 9:24 + */ +public interface SmsChannelService { + + PageResult pageChannels(SmsChannelPageReqVO reqVO); + + Long createChannel(SmsChannelCreateReqVO reqVO); + + List getChannelEnums(); + + /** + * 查询渠道(包含名下模块)信息集合 + * + * @return 渠道(包含名下模块)信息集合 + */ + List listChannelAllEnabledInfo(); + + boolean flushChannel(); +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java new file mode 100644 index 000000000..70f4d9eeb --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java @@ -0,0 +1,10 @@ +package cn.iocoder.dashboard.modules.msg.service.sms; + +/** + * 短信渠道Service接口 + * + * @author zzf + * @date 2021/1/25 9:24 + */ +public interface SmsLogService { +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java new file mode 100644 index 000000000..2c1364934 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java @@ -0,0 +1,10 @@ +package cn.iocoder.dashboard.modules.msg.service.sms; + +/** + * 短信渠道Service接口 + * + * @author zzf + * @date 2021/1/25 9:24 + */ +public interface SmsTemplateService { +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java new file mode 100644 index 000000000..e5202f491 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java @@ -0,0 +1,88 @@ +package cn.iocoder.dashboard.modules.msg.service.sms.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.msg.sms.factory.AbstractSmsSenderFactory; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.msg.convert.sms.SmsChannelConvert; +import cn.iocoder.dashboard.modules.msg.convert.sms.SmsTemplateConvert; +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsChannelMapper; +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsTemplateMapper; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 短信渠道Service实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Service +public class SmsChannelServiceImpl implements SmsChannelService { + + @Resource + private SmsChannelMapper mapper; + + @Resource + private SmsTemplateMapper templateMapper; + + @Override + public PageResult pageChannels(SmsChannelPageReqVO reqVO) { + return SmsChannelConvert.INSTANCE.convertPage(mapper.selectChannelPage(reqVO)); + } + + @Override + public Long createChannel(SmsChannelCreateReqVO reqVO) { + SmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); + mapper.insert(channelDO); + return channelDO.getId(); + } + + @Override + public List getChannelEnums() { + return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); + } + + @Override + public List listChannelAllEnabledInfo() { + List channelDOList = mapper.selectEnabledList(); + if (ObjectUtil.isNull(channelDOList)) { + return null; + } + List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); + + channelAllVOList.forEach(smsChannelDO -> { + + List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); + if (ObjectUtil.isNull(templateDOList)) { + templateDOList = new ArrayList<>(); + } + smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList)); + }); + return channelAllVOList; + } + + @Override + public boolean flushChannel() { + AbstractSmsSenderFactory smsSenderFactory = SpringUtil.getBean(AbstractSmsSenderFactory.class); + if (smsSenderFactory == null) { + return false; + } + + smsSenderFactory.flush(listChannelAllEnabledInfo()); + + return true; + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java new file mode 100644 index 000000000..f7e348a4d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java @@ -0,0 +1,15 @@ +package cn.iocoder.dashboard.modules.msg.service.sms.impl; + +import cn.iocoder.dashboard.modules.msg.service.sms.SmsLogService; +import org.springframework.stereotype.Service; + +/** + * 短信日志Service实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Service +public class SmsLogServiceImpl implements SmsLogService { + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java new file mode 100644 index 000000000..caf6d8e1c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java @@ -0,0 +1,14 @@ +package cn.iocoder.dashboard.modules.msg.service.sms.impl; + +import cn.iocoder.dashboard.modules.msg.service.sms.SmsTemplateService; +import org.springframework.stereotype.Service; + +/** + * 短信模板Service实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Service +public class SmsTemplateServiceImpl implements SmsTemplateService { +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 1bbde5784..5aa257a97 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -75,4 +75,11 @@ public interface SysErrorCodeConstants { // ========== 文件 1002009000 ========== ErrorCode FILE_PATH_EXISTS = new ErrorCode(1002009001, "文件路径已经存在"); + + // ========== 消息 1003001000 ========== + ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001001, "没有短信渠道信息, 请初始化sms_channel表数据。"); + ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001002, "没有短信模板信息, 请初始化sms_template表数据。"); + ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001003, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); + ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001004, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); + } From 37c39365ec4e0e7a5f043943d6ea854da6f7d6f6 Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Thu, 28 Jan 2021 16:45:25 +0800 Subject: [PATCH 02/54] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/ruoyi-vue-pro.sql | 12 +- .../framework/msg/sms/SmsSender.java | 67 -------- .../msg/sms/config/SmsConfiguration.java | 48 ------ .../sms/factory/DefaultSmsSenderFactory.java | 137 ----------------- .../AbstractSmsIntercepterChain.java | 38 ----- .../DefaultSmsIntercepterChain.java | 20 --- .../msg/sms/intercepter/SmsIntercepter.java | 41 ----- .../sms/intercepter/SmsLogIntercepter.java | 46 ------ .../msg/sms/proxy/DefaultSmsSenderProxy.java | 41 ----- .../msg/sms/proxy/SmsSenderProxy.java | 34 ----- .../framework/{msg => }/sms/SmsBody.java | 2 +- .../dashboard/framework/sms/SmsClient.java | 107 +++++++++++++ .../framework/sms/SmsClientAdapter.java | 42 +++++ .../framework/{msg => }/sms/SmsResult.java | 2 +- .../dashboard/modules/msg/package-info.java | 6 - .../controller/sms/SmsChannelController.java | 12 +- .../controller/sms/SmsTemplateController.java | 2 +- .../controller/sms/vo/SmsChannelAllVO.java | 2 +- .../controller/sms/vo/SmsTemplateVO.java | 2 +- .../sms/vo/req/SmsChannelCreateReqVO.java | 2 +- .../sms/vo/req/SmsChannelPageReqVO.java | 7 +- .../sms/vo/resp/SmsChannelEnumRespVO.java | 2 +- .../sms/vo/resp/SmsChannelPageRespVO.java | 2 +- .../convert/sms/SmsChannelConvert.java | 10 +- .../convert/sms/SmsTemplateConvert.java | 8 +- .../dal/mysql/dao/sms/SmsChannelMapper.java | 6 +- .../dal/mysql/dao/sms/SmsLogMapper.java | 4 +- .../dal/mysql/dao/sms/SmsTemplateMapper.java | 4 +- .../mysql/dataobject}/sms/SmsChannelDO.java | 2 +- .../dal/mysql/dataobject}/sms/SmsLog.java | 2 +- .../mysql/dataobject}/sms/SmsTemplateDO.java | 2 +- .../system/enums/SysErrorCodeConstants.java | 10 +- .../service/sms/SmsChannelService.java | 12 +- .../service/sms/SmsLogService.java | 2 +- .../service/sms/SmsTemplateService.java | 2 +- .../sms/impl/SmsChannelServiceImpl.java | 32 ++-- .../service/sms/impl/SmsLogServiceImpl.java | 4 +- .../sms/impl/SmsTemplateServiceImpl.java | 4 +- .../modules/system/sms/SmsConfiguration.java | 34 +++++ .../modules/system/sms/SmsSenderUtils.java | 143 ++++++++++++++++++ .../system/sms/client/AliSmsClient.java} | 19 ++- .../system/sms/proxy/SmsClientLogProxy.java | 48 ++++++ 42 files changed, 455 insertions(+), 567 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java rename src/main/java/cn/iocoder/dashboard/framework/{msg => }/sms/SmsBody.java (88%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java rename src/main/java/cn/iocoder/dashboard/framework/{msg => }/sms/SmsResult.java (87%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/SmsChannelController.java (75%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/SmsTemplateController.java (98%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/SmsChannelAllVO.java (94%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/SmsTemplateVO.java (88%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/req/SmsChannelCreateReqVO.java (94%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/req/SmsChannelPageReqVO.java (73%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/resp/SmsChannelEnumRespVO.java (83%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/controller/sms/vo/resp/SmsChannelPageRespVO.java (95%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/convert/sms/SmsChannelConvert.java (68%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/convert/sms/SmsTemplateConvert.java (66%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/dal/mysql/dao/sms/SmsChannelMapper.java (83%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/dal/mysql/dao/sms/SmsLogMapper.java (55%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/dal/mysql/dao/sms/SmsTemplateMapper.java (89%) rename src/main/java/cn/iocoder/dashboard/modules/{msg/dal/mysql/daoobject => system/dal/mysql/dataobject}/sms/SmsChannelDO.java (93%) rename src/main/java/cn/iocoder/dashboard/modules/{msg/dal/mysql/daoobject => system/dal/mysql/dataobject}/sms/SmsLog.java (93%) rename src/main/java/cn/iocoder/dashboard/modules/{msg/dal/mysql/daoobject => system/dal/mysql/dataobject}/sms/SmsTemplateDO.java (95%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/SmsChannelService.java (55%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/SmsLogService.java (66%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/SmsTemplateService.java (67%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/impl/SmsChannelServiceImpl.java (61%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/impl/SmsLogServiceImpl.java (60%) rename src/main/java/cn/iocoder/dashboard/modules/{msg => system}/service/sms/impl/SmsTemplateServiceImpl.java (60%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java rename src/main/java/cn/iocoder/dashboard/{framework/msg/sms/impl/ali/AliSmsSender.java => modules/system/sms/client/AliSmsClient.java} (81%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index edba4204c..9355fab64 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -892,9 +892,8 @@ DROP TABLE IF EXISTS `sms_channel`; CREATE TABLE `sms_channel` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `code` varchar(50) not null COMMENT '编码(来自枚举类 阿里、华为、七牛等)', - `api_key` varchar(100) NOT NULL COMMENT '账号id', -- add - `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', -- add - `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)', -- add + `api_key` varchar(100) NOT NULL COMMENT '账号id', + `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', `name` varchar(50) not null COMMENT '名称', `signature` varchar(50) not null COMMENT '签名值', @@ -919,15 +918,14 @@ DROP TABLE IF EXISTS `sms_template`; CREATE TABLE `sms_template` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)', - `channel_id` bigint(20) not null COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', -- add + `channel_id` bigint(20) not null COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', `type` tinyint(4) NOT NULL default 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]', - `biz_code` varchar(50) not null COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', -- add - `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(默认直接继承渠道表的,逻辑也与渠道表的一致,可以针对每个biz_code进行修改)',-- add + `biz_code` varchar(50) not null COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', `code` varchar(50) not null COMMENT '编码', `name` varchar(50) not null COMMENT '名称', `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', -- add + `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', `remark` varchar(200) NOT NULL COMMENT '备注', `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)', diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java deleted file mode 100644 index 30b10df61..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms; - -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -/** - * 短信父接口 - * - * @author zzf - * @date 2021/1/25 14:14 - */ -public interface SmsSender { - - /** - * 发送通知 - * - * @param msgBody 通知内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - SmsResult send(SmsBody msgBody, Collection targets); - - /** - * 发送通知 - * - * @param msgBody 通知内容 - * @param target 发送对象列表 - * @return 是否发送成功 - */ - default SmsResult send(SmsBody msgBody, String target) { - if (StringUtils.isBlank(target)) { - return failResult(); - } - - return send(msgBody, Collections.singletonList(target)); - } - - /** - * 发送通知 - * - * @param msgBody 通知内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - default SmsResult send(SmsBody msgBody, String... targets) { - if (targets == null) { - return failResult(); - } - - return send(msgBody, Arrays.asList(targets)); - } - - default SmsResult failResult() { - SmsResult resultBody = new SmsResult<>(); - resultBody.setSuccess(false); - return resultBody; - } - - default SmsResult failResult(String message) { - SmsResult resultBody = failResult(); - resultBody.setMessage(message); - return resultBody; - } -} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java deleted file mode 100644 index 7b5b26a5b..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.config; - -import cn.iocoder.dashboard.framework.msg.sms.factory.DefaultSmsSenderFactory; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.DefaultSmsIntercepterChain; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsLogIntercepter; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 短信服务配置 - * - * @author guer - */ -@Configuration -@ConditionalOnProperty("sms.enabled") -public class SmsConfiguration { - - @Resource - private SmsChannelService channelService; - - - @Bean - public AbstractSmsIntercepterChain smsIntercepterChain() { - DefaultSmsIntercepterChain intercepterChain = new DefaultSmsIntercepterChain(); - //添加拦截器 - intercepterChain.addSmsIntercepter(new SmsLogIntercepter()); - return intercepterChain; - } - - @Bean - public DefaultSmsSenderFactory smsSenderFactory(AbstractSmsIntercepterChain intercepterChain) { - DefaultSmsSenderFactory defaultSmsSenderFactory = new DefaultSmsSenderFactory(); - List smsChannelAllVOList = channelService.listChannelAllEnabledInfo(); - //初始化渠道、模板信息 - defaultSmsSenderFactory.init(smsChannelAllVOList); - //注入拦截器链 - defaultSmsSenderFactory.setIntercepterChain(intercepterChain); - return defaultSmsSenderFactory; - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java deleted file mode 100644 index 123943a3d..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java +++ /dev/null @@ -1,137 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.factory; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.dashboard.common.enums.SmsChannelEnum; -import cn.iocoder.dashboard.common.exception.ServiceException; -import cn.iocoder.dashboard.framework.msg.sms.SmsSender; -import cn.iocoder.dashboard.framework.msg.sms.impl.ali.AliSmsSender; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; -import cn.iocoder.dashboard.framework.msg.sms.proxy.DefaultSmsSenderProxy; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO; -import lombok.Setter; - -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; - -/** - * 短信发送者工厂 - * - * @author zzf - * @date 2021/1/25 16:18 - */ -public class DefaultSmsSenderFactory { - - /** - * sender索引 - * key: {@link SmsTemplateVO#getBizCode()} - * value: {@link SmsSender} - */ - private final ConcurrentHashMap> bizCode2SenderMap = new ConcurrentHashMap<>(8); - - /** - * sender索引 - * key: {@link SmsTemplateVO#getCode()} - * value: {@link SmsSender} - */ - private final ConcurrentHashMap> templateCode2SenderMap = new ConcurrentHashMap<>(8); - - - @Setter - private AbstractSmsIntercepterChain intercepterChain; - - /** - * 读写锁 - */ - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final Lock readLock = lock.readLock(); - private final Lock writeLock = lock.writeLock(); - - - public void init(List smsChannelAllVOList) { - if (ObjectUtil.isEmpty(smsChannelAllVOList)) { - throw new ServiceException(SMS_CHANNEL_NOT_FOUND); - } - try { - writeLock.lock(); - addSender(smsChannelAllVOList); - } finally { - writeLock.unlock(); - } - } - - public SmsSender getSenderByBizCode(String bizCode) { - return getSmsSender(bizCode, bizCode2SenderMap); - } - - public SmsSender getSenderByTemplateCode(String templateCode) { - return getSmsSender(templateCode, templateCode2SenderMap); - } - - private SmsSender getSmsSender(String templateCode, ConcurrentHashMap> cacheMap) { - try { - readLock.lock(); - SmsSender smsSender = cacheMap.get(templateCode); - if (smsSender == null) { - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - return smsSender; - } finally { - readLock.unlock(); - } - } - - public void flush(List smsChannelAllVOList) { - try { - writeLock.lock(); - bizCode2SenderMap.clear(); - templateCode2SenderMap.clear(); - addSender(smsChannelAllVOList); - } finally { - writeLock.unlock(); - } - } - - - private void addSender(List smsChannelAllVOList) { - smsChannelAllVOList.forEach(channelAllVO -> addSender(SmsChannelEnum.getByCode(channelAllVO.getCode()), channelAllVO)); - } - - private void addSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { - if (channelEnum == null) { - throw new ServiceException(INVALID_CHANNEL_CODE); - } - List templateList = channelAllVO.getTemplateList(); - if (ObjectUtil.isEmpty(templateList)) { - throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); - } - - SmsSender aliSmsSender = getSender(channelEnum, channelAllVO); - - - templateList.forEach(smsTemplateVO -> { - bizCode2SenderMap.put(smsTemplateVO.getBizCode(), aliSmsSender); - templateCode2SenderMap.put(smsTemplateVO.getCode(), aliSmsSender); - }); - } - - private SmsSender getSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { - switch (channelEnum) { - case ALI: - return new DefaultSmsSenderProxy<>(new AliSmsSender(channelAllVO), intercepterChain); - // TODO fill more channel - default: - break; - } - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - - - - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java deleted file mode 100644 index f95de7128..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.intercepter; - -import lombok.Getter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -public abstract class AbstractSmsIntercepterChain { - - @Getter - protected final List intercepterList = new ArrayList<>(8); - - - /** - * 添加短信拦截器 - * - * @param smsIntercepter 短信拦截器 - */ - public void addSmsIntercepter(SmsIntercepter smsIntercepter) { - addSmsIntercepter(Collections.singletonList(smsIntercepter)); - } - - /** - * 添加短信拦截器 - * - * @param smsIntercepterList 短信拦截器数组 - */ - abstract void addSmsIntercepter(List smsIntercepterList); - - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java deleted file mode 100644 index 76d31906d..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.intercepter; - -import java.util.Comparator; -import java.util.List; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -public class DefaultSmsIntercepterChain extends AbstractSmsIntercepterChain { - - @Override - public void addSmsIntercepter(List smsIntercepterList) { - intercepterList.addAll(smsIntercepterList); - //排序 - intercepterList.sort(Comparator.comparingInt(SmsIntercepter::getOrder)); - } -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java deleted file mode 100644 index df83c8d6a..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.intercepter; - -import cn.iocoder.dashboard.framework.msg.sms.SmsBody; -import cn.iocoder.dashboard.framework.msg.sms.SmsResult; - -import java.util.Collection; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -public interface SmsIntercepter { - - /** - * 监听发送前 - * - * @param msgBody 消息体 - * @param targets 发送对象数组 - */ - void beforeSender(SmsBody msgBody, Collection targets); - - /** - * 监听发送后 - * - * @param msgBody 消息体 - * @param targets 发送对象数组 - * @param resultBody 返回对象 - */ - void afterSender(SmsBody msgBody, Collection targets, SmsResult resultBody); - - /** - * 排序值,拦截器根据order值顺序执行 - *

- * 值越小,越早执行 - * - * @return 排序值 - */ - int getOrder(); -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java deleted file mode 100644 index 9a7effd95..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java +++ /dev/null @@ -1,46 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.intercepter; - -import cn.iocoder.dashboard.framework.msg.sms.SmsBody; -import cn.iocoder.dashboard.framework.msg.sms.SmsResult; -import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsLogMapper; -import cn.iocoder.dashboard.util.json.JsonUtils; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import java.util.Collection; - -/** - * 短信日志拦截器 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -@Slf4j -public class SmsLogIntercepter implements SmsIntercepter { - - - @Override - public void beforeSender(SmsBody msgBody, Collection targets) { - log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets); - - } - - @Override - public void afterSender(SmsBody msgBody, Collection targets, SmsResult resultBody) { - if (resultBody.getSuccess()) { - // - } else { - log.warn("send sms fail, body: {}, target: {}, resultBody: {}", - JsonUtils.toJsonString(msgBody), - targets, - JsonUtils.toJsonString(resultBody) - ); - } - - } - - @Override - public int getOrder() { - return 0; - } -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java deleted file mode 100644 index f9d7e566f..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.proxy; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.dashboard.framework.msg.sms.SmsBody; -import cn.iocoder.dashboard.framework.msg.sms.SmsResult; -import cn.iocoder.dashboard.framework.msg.sms.SmsSender; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain; - -import java.util.Collection; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -public class DefaultSmsSenderProxy implements SmsSender { - - private final SmsSender smsSender; - private final AbstractSmsIntercepterChain chain; - - @Override - public SmsResult send(SmsBody msgBody, Collection targets) { - if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) { - chain.getIntercepterList().forEach(s -> s.beforeSender(msgBody, targets)); - } - - SmsResult resultBody = smsSender.send(msgBody, targets); - - if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) { - chain.getIntercepterList().forEach(s -> s.afterSender(msgBody, targets, resultBody)); - } - return resultBody; - } - - public DefaultSmsSenderProxy(SmsSender smsSender, - AbstractSmsIntercepterChain chain) { - this.smsSender = smsSender; - this.chain = chain; - } -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java b/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java deleted file mode 100644 index 069916e2a..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.dashboard.framework.msg.sms.proxy; - -import cn.iocoder.dashboard.framework.msg.sms.SmsSender; -import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsIntercepter; - -import java.util.Collections; -import java.util.List; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -public interface SmsSenderProxy extends SmsSender { - - /** - * 添加短信拦截器 - * - * @param smsIntercepter 短信拦截器 - */ - default void addSmsIntercepter(SmsIntercepter smsIntercepter) { - addSmsIntercepter(Collections.singletonList(smsIntercepter)); - } - - /** - * 添加短信拦截器 - * - * @param smsIntercepterList 短信拦截器数组 - */ - void addSmsIntercepter(List smsIntercepterList); - - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java similarity index 88% rename from src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java index 693838d4a..48fb2253b 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.framework.msg.sms; +package cn.iocoder.dashboard.framework.sms; import cn.iocoder.dashboard.util.json.JsonUtils; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java new file mode 100644 index 000000000..bf1a44f57 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java @@ -0,0 +1,107 @@ +package cn.iocoder.dashboard.framework.sms; + +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * 短信父接口 + * + * @author zzf + * @date 2021/1/25 14:14 + */ +public interface SmsClient { + + /** + * 发送消息 + * + * @param msgBody 消息内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + SmsResult send(SmsBody msgBody, Collection targets); + + /** + * 发送消息 + * + * @param msgBody 消息内容 + * @param target 发送对象 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody msgBody, String target) { + if (StringUtils.isBlank(target)) { + return failResult(); + } + + return send(msgBody, Collections.singletonList(target)); + } + + /** + * 发送消息 + * + * @param msgBody 消息内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody msgBody, String... targets) { + if (targets == null) { + return failResult(); + } + + return send(msgBody, Arrays.asList(targets)); + } + + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + SmsResult sendAsync(SmsBody msgBody, Collection targets); + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param target 发送对象 + * @return 是否发送成功 + */ + default SmsResult sendAsync(SmsBody msgBody, String target) { + if (StringUtils.isBlank(target)) { + return failResult("target must not null."); + } + + return sendAsync(msgBody, Collections.singletonList(target)); + } + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + default SmsResult sendAsync(SmsBody msgBody, String... targets) { + if (targets == null) { + return failResult("targets must not null."); + } + + return sendAsync(msgBody, Arrays.asList(targets)); + } + + default SmsResult failResult() { + SmsResult resultBody = new SmsResult<>(); + resultBody.setSuccess(false); + return resultBody; + } + + default SmsResult failResult(String message) { + SmsResult resultBody = failResult(); + resultBody.setMessage(message); + return resultBody; + } +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java new file mode 100644 index 000000000..6edf7646f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java @@ -0,0 +1,42 @@ +package cn.iocoder.dashboard.framework.sms; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.dashboard.common.exception.ServiceException; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_INIT; + +/** + * 抽象短信客户端工厂 + * + * @author zzf + * @date 2021/1/28 14:01 + */ +public class SmsClientAdapter { + + private final Map> smsSenderMap; + + public SmsClientAdapter(Map> smsSenderMap) { + if (ObjectUtil.isEmpty(smsSenderMap)) { + throw new ServiceException(SMS_CHANNEL_NOT_INIT); + } + this.smsSenderMap = smsSenderMap; + } + + public void flushClient(Map> smsSenderMap) { + this.smsSenderMap.clear(); + smsSenderMap.putAll(Collections.unmodifiableMap(smsSenderMap)); + } + + public SmsResult send(Long channelId, SmsBody smsBody, Collection targetPhone) { + SmsClient smsClient = getSmsSender(channelId); + return smsClient.send(smsBody, targetPhone); + } + + private SmsClient getSmsSender(Long channelId) { + return smsSenderMap.get(channelId); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java similarity index 87% rename from src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java index 8a8741839..b994514b6 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.framework.msg.sms; +package cn.iocoder.dashboard.framework.sms; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java b/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java deleted file mode 100644 index 3a0e7635c..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * msg 包,专门专门用于发送消息的功能,支撑上层的通用与核心业务。 - * 例如说:短信、邮件、app通知等等 - * - */ -package cn.iocoder.dashboard.modules.msg; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java similarity index 75% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index c28d9b862..a75f9e2eb 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -1,12 +1,12 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms; +package cn.iocoder.dashboard.modules.system.controller.sms; import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java similarity index 98% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java index 8bd73b12e..9fdf98440 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms; +package cn.iocoder.dashboard.modules.system.controller.sms; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.CommonResult; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java similarity index 94% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java index bac72c959..042cddaa2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo; +package cn.iocoder.dashboard.modules.system.controller.sms.vo; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java similarity index 88% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java index 04bfe9a62..c5156a6ae 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo; +package cn.iocoder.dashboard.modules.system.controller.sms.vo; import lombok.Data; import lombok.EqualsAndHashCode; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java similarity index 94% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java index 729088b65..b38f7c832 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req; +package cn.iocoder.dashboard.modules.system.controller.sms.vo.req; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java index dd2df146e..19e2987fe 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req; +package cn.iocoder.dashboard.modules.system.controller.sms.vo.req; import cn.iocoder.dashboard.common.pojo.PageParam; import io.swagger.annotations.ApiModel; @@ -7,11 +7,6 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @ApiModel("消息渠道分页 Request VO") @Data diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java similarity index 83% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java index a3e56e0ca..cb156781d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp; +package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp; import io.swagger.annotations.ApiModel; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java similarity index 95% rename from src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java index 603f13e07..2ad1ce357 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp; +package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp; import cn.iocoder.dashboard.common.pojo.PageParam; import io.swagger.annotations.ApiModel; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java similarity index 68% rename from src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java rename to src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index 4728586a3..af87d2253 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -1,11 +1,11 @@ -package cn.iocoder.dashboard.modules.msg.convert.sms; +package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java similarity index 66% rename from src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java rename to src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java index 313e06c92..476b96e0e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java @@ -1,9 +1,9 @@ -package cn.iocoder.dashboard.modules.msg.convert.sms; +package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java similarity index 83% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java index f7ede3502..d1ce95c62 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java @@ -1,10 +1,10 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java similarity index 55% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java index 263783b47..a5dce01de 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java @@ -1,6 +1,6 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsLog; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLog; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java similarity index 89% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java index f2d2fb21b..fd941ae7a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java similarity index 93% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java index 3c0b5f396..5cce2ffa4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableName; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java similarity index 93% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java index e5af0471e..169369b1e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java similarity index 95% rename from src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java index 39257a71d..360999838 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableName; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 5aa257a97..05e9e6393 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -77,9 +77,11 @@ public interface SysErrorCodeConstants { // ========== 消息 1003001000 ========== - ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001001, "没有短信渠道信息, 请初始化sms_channel表数据。"); - ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001002, "没有短信模板信息, 请初始化sms_template表数据。"); - ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001003, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); - ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001004, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); + ErrorCode SMS_CHANNEL_NOT_INIT = new ErrorCode(1003001001, + "短信渠道没有初始化, 请调用SmsClientWrapper#initSmsClient()或SmsClientWrapper#addSmsClient"); + ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001002, "没有短信渠道信息, 请初始化sms_channel表数据。"); + ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001003, "没有短信模板信息, 请初始化sms_template表数据。"); + ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001004, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); + ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001005, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java similarity index 55% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java index ed2c047e8..3040f3bdb 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java @@ -1,11 +1,11 @@ -package cn.iocoder.dashboard.modules.msg.service.sms; +package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import java.util.List; diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java similarity index 66% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java index 70f4d9eeb..d29d7f884 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.service.sms; +package cn.iocoder.dashboard.modules.system.service.sms; /** * 短信渠道Service接口 diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java similarity index 67% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java index 2c1364934..585a22a57 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.msg.service.sms; +package cn.iocoder.dashboard.modules.system.service.sms; /** * 短信渠道Service接口 diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java similarity index 61% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java index e5202f491..ccc47af3c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java @@ -1,21 +1,19 @@ -package cn.iocoder.dashboard.modules.msg.service.sms.impl; +package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.msg.sms.factory.AbstractSmsSenderFactory; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.msg.convert.sms.SmsChannelConvert; -import cn.iocoder.dashboard.modules.msg.convert.sms.SmsTemplateConvert; -import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsChannelMapper; -import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsTemplateMapper; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO; -import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; +import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; +import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsChannelMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsTemplateMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; +import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -76,12 +74,6 @@ public class SmsChannelServiceImpl implements SmsChannelService { @Override public boolean flushChannel() { - AbstractSmsSenderFactory smsSenderFactory = SpringUtil.getBean(AbstractSmsSenderFactory.class); - if (smsSenderFactory == null) { - return false; - } - - smsSenderFactory.flush(listChannelAllEnabledInfo()); return true; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java similarity index 60% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java index f7e348a4d..e54d265c6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java @@ -1,6 +1,6 @@ -package cn.iocoder.dashboard.modules.msg.service.sms.impl; +package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.iocoder.dashboard.modules.msg.service.sms.SmsLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService; import org.springframework.stereotype.Service; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java similarity index 60% rename from src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java index caf6d8e1c..2826d7fca 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java @@ -1,6 +1,6 @@ -package cn.iocoder.dashboard.modules.msg.service.sms.impl; +package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.iocoder.dashboard.modules.msg.service.sms.SmsTemplateService; +import cn.iocoder.dashboard.modules.system.service.sms.SmsTemplateService; import org.springframework.stereotype.Service; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java new file mode 100644 index 000000000..ffb5887bd --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.modules.system.sms; + +import cn.iocoder.dashboard.framework.sms.SmsClient; +import cn.iocoder.dashboard.framework.sms.SmsClientAdapter; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 短信服务配置 + * + * @author guer + */ +@Configuration +@ConditionalOnProperty("sms.enabled") +public class SmsConfiguration { + + @Resource + private SmsChannelService channelService; + + @Bean + public SmsClientAdapter smsClientWrapper() { + List smsChannelAllVOList = channelService.listChannelAllEnabledInfo(); + Map> channelId2SmsClientMap = SmsSenderUtils.init(smsChannelAllVOList); + return new SmsClientAdapter(channelId2SmsClientMap); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java new file mode 100644 index 000000000..ea9c24489 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java @@ -0,0 +1,143 @@ +package cn.iocoder.dashboard.modules.system.sms; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.common.exception.ServiceException; +import cn.iocoder.dashboard.framework.sms.SmsBody; +import cn.iocoder.dashboard.framework.sms.SmsClient; +import cn.iocoder.dashboard.framework.sms.SmsClientAdapter; +import cn.iocoder.dashboard.framework.sms.SmsResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; +import cn.iocoder.dashboard.modules.system.sms.client.AliSmsClient; +import cn.iocoder.dashboard.modules.system.sms.proxy.SmsClientLogProxy; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; + +/** + * 短信发送者工厂 + * + * @author zzf + * @date 2021/1/25 16:18 + */ +public class SmsSenderUtils { + + /** + * 短信渠道id:短信客户端map + * key: channelId + * val: SmsClient + */ + private static final Map> smsSenderMap = new ConcurrentHashMap<>(8); + + /** + * 短信模板code: 短信渠道id map + * key: templateCode + * val: channelId + */ + private static final Map templateCode2ChannelIdMap = new HashMap<>(); + + /** + * 将短信渠道信息初始化成短信客户端 + * + * @param smsChannelAllVOList 短信渠道信息 + * @return 短信渠道id:短信客户端map + */ + public synchronized static Map> init(List smsChannelAllVOList) { + if (ObjectUtil.isEmpty(smsChannelAllVOList)) { + throw new ServiceException(SMS_CHANNEL_NOT_FOUND); + } + addSender(smsChannelAllVOList); + return smsSenderMap; + } + + /** + * 重置短信客户端信息 + * + * @param smsClientAdapter 短信客户端适配器 + * @param smsChannelAllVOList 短信渠道信息集合 + */ + public synchronized static void flush(SmsClientAdapter smsClientAdapter, List smsChannelAllVOList) { + smsSenderMap.clear(); + smsClientAdapter.flushClient(init(smsChannelAllVOList)); + } + + /** + * 发送短信 + * + * @param smsClientAdapter 短信客户端适配器 + * @param smsBody 短信内容 + * @param targetPhones 对象手机集合 + * @return 短信发送结果 + */ + public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, Collection targetPhones) { + Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); + if (channelId == null) { + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + return smsClientAdapter.send(channelId, smsBody, targetPhones); + } + + /** + * 发送短信 + * + * @param smsClientAdapter 短信客户端适配器 + * @param smsBody 短信内容 + * @param targetPhone 对象手机 + * @return 短信发送结果 + */ + public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, String targetPhone) { + Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); + if (channelId == null) { + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + return smsClientAdapter.send(channelId, smsBody, Collections.singletonList(targetPhone)); + } + + /** + * 发送短信 + * + * @param smsClientAdapter 短信客户端适配器 + * @param smsBody 短信内容 + * @param targetPhones 对象手机数组 + * @return 短信发送结果 + */ + public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, String... targetPhones) { + Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); + if (channelId == null) { + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + return smsClientAdapter.send(channelId, smsBody, Arrays.asList(targetPhones)); + } + + + private static void addSender(List smsChannelAllVOList) { + smsChannelAllVOList.forEach(channelAllVO -> addSender(SmsChannelEnum.getByCode(channelAllVO.getCode()), channelAllVO)); + } + + private static void addSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { + if (channelEnum == null) { + throw new ServiceException(INVALID_CHANNEL_CODE); + } + List templateList = channelAllVO.getTemplateList(); + if (ObjectUtil.isEmpty(templateList)) { + throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); + } + SmsClient aliSmsClient = getSender(channelEnum, channelAllVO); + templateList.forEach(smsTemplateVO -> templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), channelAllVO.getId())); + smsSenderMap.put(channelAllVO.getId(), aliSmsClient); + } + + private static SmsClient getSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { + switch (channelEnum) { + case ALI: + return new SmsClientLogProxy<>(new AliSmsClient(channelAllVO)); + // TODO fill more channel + default: + break; + } + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java rename to src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java index fbf6aeceb..f144ec380 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java @@ -1,9 +1,9 @@ -package cn.iocoder.dashboard.framework.msg.sms.impl.ali; +package cn.iocoder.dashboard.modules.system.sms.client; -import cn.iocoder.dashboard.framework.msg.sms.SmsBody; -import cn.iocoder.dashboard.framework.msg.sms.SmsResult; -import cn.iocoder.dashboard.framework.msg.sms.SmsSender; -import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.framework.sms.SmsBody; +import cn.iocoder.dashboard.framework.sms.SmsClient; +import cn.iocoder.dashboard.framework.sms.SmsResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; @@ -23,7 +23,7 @@ import java.util.Collection; * @date 2021/1/25 14:17 */ @Slf4j -public class AliSmsSender implements SmsSender { +public class AliSmsClient implements SmsClient { private static final String OK = "OK"; @@ -42,7 +42,7 @@ public class AliSmsSender implements SmsSender { * * @param channelVO 阿里云短信配置 */ - public AliSmsSender(SmsChannelAllVO channelVO) { + public AliSmsClient(SmsChannelAllVO channelVO) { this.channelVO = channelVO; @@ -83,4 +83,9 @@ public class AliSmsSender implements SmsSender { return failResult(); } + @Override + public SmsResult sendAsync(SmsBody msgBody, Collection targets) { + return null; + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java new file mode 100644 index 000000000..a7d201e6f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java @@ -0,0 +1,48 @@ +package cn.iocoder.dashboard.modules.system.sms.proxy; + +import cn.iocoder.dashboard.framework.sms.SmsBody; +import cn.iocoder.dashboard.framework.sms.SmsClient; +import cn.iocoder.dashboard.framework.sms.SmsResult; +import cn.iocoder.dashboard.util.json.JsonUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; + +/** + * 消息父接口 + * + * @author zzf + * @date 2021/1/22 15:46 + */ +@Slf4j +public class SmsClientLogProxy implements SmsClient { + + private final SmsClient smsClient; + + @Override + public SmsResult send(SmsBody msgBody, Collection targets) { + log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets); + + SmsResult resultBody = smsClient.send(msgBody, targets); + + if (resultBody.getSuccess()) { + // + } else { + log.warn("send sms fail, body: {}, target: {}, resultBody: {}", + JsonUtils.toJsonString(msgBody), + targets, + JsonUtils.toJsonString(resultBody) + ); + } + return resultBody; + } + + @Override + public SmsResult sendAsync(SmsBody msgBody, Collection targets) { + return send(msgBody, targets); + } + + public SmsClientLogProxy(SmsClient smsClient) { + this.smsClient = smsClient; + } +} From 009f33210680bb77a727636732ce23ab5c8c5fb5 Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Mon, 1 Feb 2021 14:25:22 +0800 Subject: [PATCH 03/54] =?UTF-8?q?=E9=87=8D=E6=9E=84=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/ruoyi-vue-pro.sql | 71 --------- sql/sms.sql | 82 ++++++++++ .../dashboard/framework/sms/SmsClient.java | 107 ------------- .../framework/sms/SmsClientAdapter.java | 42 ----- .../sms/client/AbstractSmsClient.java | 32 ++++ .../sms/client/AliyunSmsClient.java} | 35 ++--- .../framework/sms/client/SmsClient.java | 25 +++ .../framework/sms/{ => core}/SmsBody.java | 10 +- .../framework/sms/core/SmsClientFactory.java | 71 +++++++++ .../framework/sms/{ => core}/SmsResult.java | 2 +- .../controller/sms/SmsChannelController.java | 6 - ...elAllVO.java => SmsChannelPropertyVO.java} | 2 +- .../controller/sms/vo/SmsTemplateVO.java | 8 + .../system/convert/sms/SmsChannelConvert.java | 4 +- .../dal/mysql/dao/sms/SmsLogMapper.java | 4 +- .../sms/{SmsLog.java => SmsLogDO.java} | 16 +- .../system/enums/SysErrorCodeConstants.java | 1 + .../system/enums/sms/SmsSendStatusEnum.java | 30 ++++ .../mq/consumer/sms/SmsSendConsumer.java | 31 ++++ .../system/mq/message/sms/SmsSendMessage.java | 25 +++ .../system/mq/producer/sms/SmsProducer.java | 31 ++++ .../system/service/sms/SmsChannelService.java | 37 ++++- .../system/service/sms/SmsLogService.java | 25 +++ .../system/service/sms/SmsService.java | 101 +++++++++++++ .../sms/impl/SmsChannelServiceImpl.java | 47 ++++-- .../service/sms/impl/SmsLogServiceImpl.java | 57 +++++++ .../service/sms/impl/SmsServiceImpl.java | 51 +++++++ .../modules/system/sms/SmsConfiguration.java | 34 ----- .../modules/system/sms/SmsSenderUtils.java | 143 ------------------ .../system/sms/proxy/SmsClientLogProxy.java | 48 ------ .../dashboard/util/string/StrUtils.java | 21 +++ 31 files changed, 701 insertions(+), 498 deletions(-) create mode 100644 sql/sms.sql delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java rename src/main/java/cn/iocoder/dashboard/{modules/system/sms/client/AliSmsClient.java => framework/sms/client/AliyunSmsClient.java} (73%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java rename src/main/java/cn/iocoder/dashboard/framework/sms/{ => core}/SmsBody.java (67%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java rename src/main/java/cn/iocoder/dashboard/framework/sms/{ => core}/SmsResult.java (86%) rename src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/{SmsChannelAllVO.java => SmsChannelPropertyVO.java} (94%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/{SmsLog.java => SmsLogDO.java} (73%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 9355fab64..af7f492f9 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -884,75 +884,4 @@ INSERT INTO `sys_user_role` VALUES (5, 100, 1, '', NULL, '', NULL, b'0'); INSERT INTO `sys_user_role` VALUES (6, 100, 2, '', NULL, '', NULL, b'0'); COMMIT; - --- ---------------------------- --- Table structure for sms_channel --- ---------------------------- -DROP TABLE IF EXISTS `sms_channel`; -CREATE TABLE `sms_channel` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `code` varchar(50) not null COMMENT '编码(来自枚举类 阿里、华为、七牛等)', - `api_key` varchar(100) NOT NULL COMMENT '账号id', - `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', - `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', - `name` varchar(50) not null COMMENT '名称', - `signature` varchar(50) not null COMMENT '签名值', - `remark` varchar(200) NOT NULL COMMENT '备注', - - `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)', - `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠道'; -/* - 优先级值一样时,按照id顺序取值 -*/ - --- ---------------------------- --- Table structure for sms_template --- ---------------------------- -DROP TABLE IF EXISTS `sms_template`; -CREATE TABLE `sms_template` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)', - `channel_id` bigint(20) not null COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', - `type` tinyint(4) NOT NULL default 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]', - `biz_code` varchar(50) not null COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', - `code` varchar(50) not null COMMENT '编码', - `name` varchar(50) not null COMMENT '名称', - `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识', - `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', - `remark` varchar(200) NOT NULL COMMENT '备注', - - `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)', - `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信模板'; - --- ---------------------------- --- Table structure for sms_log --- ---------------------------- -DROP TABLE IF EXISTS `sms_log`; -CREATE TABLE `sms_log` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)', - `api_sms_id` varchar(50) not null COMMENT '实际渠道短信唯一标识', - `template_id` bigint(20) NOT NULL COMMENT '模板id', - `phone` char(11) not null COMMENT '手机号', - `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `remark` varchar(200) NOT NULL COMMENT '备注', - `send_status` tinyint(4) NOT NULL default 0 COMMENT '发送状态(0发送中 1成功 2失败)', - `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信日志'; - SET FOREIGN_KEY_CHECKS = 1; diff --git a/sql/sms.sql b/sql/sms.sql new file mode 100644 index 000000000..82d854155 --- /dev/null +++ b/sql/sms.sql @@ -0,0 +1,82 @@ +/* + --2021.02.01 by fight, sms about table info +*/ + +-- ---------------------------- +-- Table structure for sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS `sms_channel`; +CREATE TABLE `sms_channel` +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `code` varchar(50) NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)', + `api_key` varchar(100) NOT NULL COMMENT '账号id', + `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', + `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', + `name` varchar(50) NOT NULL COMMENT '名称', + `signature` varchar(50) NOT NULL COMMENT '签名值', + `remark` varchar(200) NOT NULL COMMENT '备注', + + `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='短信渠道'; +/* + 优先级值一样时,按照id顺序取值 +*/ + +-- ---------------------------- +-- Table structure for sms_template +-- ---------------------------- +DROP TABLE IF EXISTS `sms_template`; +CREATE TABLE `sms_template` +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', + `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', + `type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]', + `biz_code` varchar(50) NOT NULL COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', + `code` varchar(50) NOT NULL COMMENT '编码', + `name` varchar(50) NOT NULL COMMENT '名称', + `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识', + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', + `remark` varchar(200) NOT NULL COMMENT '备注', + + `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板'; + +-- ---------------------------- +-- Table structure for sms_log +-- ---------------------------- +DROP TABLE IF EXISTS `sms_log`; +CREATE TABLE `sms_log` +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', + `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', + `template_code` varchar(50) NOT NULL COMMENT '渠道编码', + `phones` char(11) NOT NULL COMMENT '手机号(数组json字符串)', + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `remark` varchar(200) DEFAULT NULL COMMENT '备注', + `send_status` tinyint(4) NOT NULL DEFAULT 2 COMMENT '发送状态(1异步推送中 2发送中 3失败 4成功)', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='短信日志'; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java deleted file mode 100644 index bf1a44f57..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.iocoder.dashboard.framework.sms; - -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -/** - * 短信父接口 - * - * @author zzf - * @date 2021/1/25 14:14 - */ -public interface SmsClient { - - /** - * 发送消息 - * - * @param msgBody 消息内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - SmsResult send(SmsBody msgBody, Collection targets); - - /** - * 发送消息 - * - * @param msgBody 消息内容 - * @param target 发送对象 - * @return 是否发送成功 - */ - default SmsResult send(SmsBody msgBody, String target) { - if (StringUtils.isBlank(target)) { - return failResult(); - } - - return send(msgBody, Collections.singletonList(target)); - } - - /** - * 发送消息 - * - * @param msgBody 消息内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - default SmsResult send(SmsBody msgBody, String... targets) { - if (targets == null) { - return failResult(); - } - - return send(msgBody, Arrays.asList(targets)); - } - - - /** - * 异步发送消息 - * - * @param msgBody 消息内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - SmsResult sendAsync(SmsBody msgBody, Collection targets); - - /** - * 异步发送消息 - * - * @param msgBody 消息内容 - * @param target 发送对象 - * @return 是否发送成功 - */ - default SmsResult sendAsync(SmsBody msgBody, String target) { - if (StringUtils.isBlank(target)) { - return failResult("target must not null."); - } - - return sendAsync(msgBody, Collections.singletonList(target)); - } - - /** - * 异步发送消息 - * - * @param msgBody 消息内容 - * @param targets 发送对象列表 - * @return 是否发送成功 - */ - default SmsResult sendAsync(SmsBody msgBody, String... targets) { - if (targets == null) { - return failResult("targets must not null."); - } - - return sendAsync(msgBody, Arrays.asList(targets)); - } - - default SmsResult failResult() { - SmsResult resultBody = new SmsResult<>(); - resultBody.setSuccess(false); - return resultBody; - } - - default SmsResult failResult(String message) { - SmsResult resultBody = failResult(); - resultBody.setMessage(message); - return resultBody; - } -} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java b/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java deleted file mode 100644 index 6edf7646f..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java +++ /dev/null @@ -1,42 +0,0 @@ -package cn.iocoder.dashboard.framework.sms; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.dashboard.common.exception.ServiceException; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_INIT; - -/** - * 抽象短信客户端工厂 - * - * @author zzf - * @date 2021/1/28 14:01 - */ -public class SmsClientAdapter { - - private final Map> smsSenderMap; - - public SmsClientAdapter(Map> smsSenderMap) { - if (ObjectUtil.isEmpty(smsSenderMap)) { - throw new ServiceException(SMS_CHANNEL_NOT_INIT); - } - this.smsSenderMap = smsSenderMap; - } - - public void flushClient(Map> smsSenderMap) { - this.smsSenderMap.clear(); - smsSenderMap.putAll(Collections.unmodifiableMap(smsSenderMap)); - } - - public SmsResult send(Long channelId, SmsBody smsBody, Collection targetPhone) { - SmsClient smsClient = getSmsSender(channelId); - return smsClient.send(smsBody, targetPhone); - } - - private SmsClient getSmsSender(Long channelId) { - return smsSenderMap.get(channelId); - } -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java new file mode 100644 index 000000000..043dd2a50 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -0,0 +1,32 @@ +package cn.iocoder.dashboard.framework.sms.client; + +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; + +/** + * 抽象短息客户端 + * + * @author zzf + * @date 2021/2/1 9:28 + */ +public abstract class AbstractSmsClient implements SmsClient { + + /** + * 短信渠道参数 + */ + protected final SmsChannelPropertyVO channelVO; + + /** + * 构造阿里云短信发送处理 + * + * @param channelVO 阿里云短信配置 + */ + public AbstractSmsClient(SmsChannelPropertyVO channelVO) { + this.channelVO = channelVO; + } + + + public SmsChannelPropertyVO getProperty() { + return channelVO; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index f144ec380..39d359449 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -1,9 +1,8 @@ -package cn.iocoder.dashboard.modules.system.sms.client; +package cn.iocoder.dashboard.framework.sms.client; -import cn.iocoder.dashboard.framework.sms.SmsBody; -import cn.iocoder.dashboard.framework.sms.SmsClient; -import cn.iocoder.dashboard.framework.sms.SmsResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; @@ -23,7 +22,7 @@ import java.util.Collection; * @date 2021/1/25 14:17 */ @Slf4j -public class AliSmsClient implements SmsClient { +public class AliyunSmsClient extends AbstractSmsClient { private static final String OK = "OK"; @@ -33,8 +32,6 @@ public class AliSmsClient implements SmsClient { private static final String ENDPOINT = "cn-hangzhou"; - private final SmsChannelAllVO channelVO; - private final IAcsClient acsClient; /** @@ -42,9 +39,8 @@ public class AliSmsClient implements SmsClient { * * @param channelVO 阿里云短信配置 */ - public AliSmsClient(SmsChannelAllVO channelVO) { - - this.channelVO = channelVO; + public AliyunSmsClient(SmsChannelPropertyVO channelVO) { + super(channelVO); String accessKeyId = channelVO.getApiKey(); String accessKeySecret = channelVO.getApiSecret(); @@ -57,13 +53,13 @@ public class AliSmsClient implements SmsClient { @Override - public SmsResult send(SmsBody msgBody, Collection targets) { + public SmsResult send(SmsBody smsBody, Collection targets) { SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); request.setPhoneNumbers(StringUtils.join(targets, ",")); request.setSignName(channelVO.getApiSignatureId()); - request.setTemplateCode(channelVO.getTemplateByTemplateCode(msgBody.getCode()).getApiTemplateId()); - request.setTemplateParam(msgBody.getParamsStr()); + request.setTemplateCode(channelVO.getTemplateByTemplateCode(smsBody.getTemplateCode()).getApiTemplateId()); + request.setTemplateParam(smsBody.getParamsStr()); try { SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); @@ -78,14 +74,15 @@ public class AliSmsClient implements SmsClient { return resultBody; } catch (Exception e) { log.debug(e.getMessage(), e); + return failResult("发送异常: " + e.getMessage()); } - - return failResult(); } - @Override - public SmsResult sendAsync(SmsBody msgBody, Collection targets) { - return null; + SmsResult failResult(String message) { + SmsResult resultBody = new SmsResult<>(); + resultBody.setSuccess(false); + resultBody.setMessage(message); + return resultBody; } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java new file mode 100644 index 000000000..290d21712 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -0,0 +1,25 @@ +package cn.iocoder.dashboard.framework.sms.client; + +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; + +import java.util.Collection; + +/** + * 短信父接口 + * + * @author zzf + * @date 2021/1/25 14:14 + */ +public interface SmsClient { + + /** + * 发送消息 + * + * @param smsBody 消息内容 + * @param targets 发送对象列表 + * @return 是否发送成功 + */ + SmsResult send(SmsBody smsBody, Collection targets); + +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java similarity index 67% rename from src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java index 48fb2253b..9b132431e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java @@ -1,9 +1,10 @@ -package cn.iocoder.dashboard.framework.sms; +package cn.iocoder.dashboard.framework.sms.core; import cn.iocoder.dashboard.util.json.JsonUtils; import lombok.Data; import java.util.Map; +import java.util.UUID; /** * 消息内容实体类 @@ -11,10 +12,15 @@ import java.util.Map; @Data public class SmsBody { + /** + * 消息日志id + */ + private Long smsLogId; + /** * 模板编码 */ - private String code; + private String templateCode; /** * 参数列表 diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java new file mode 100644 index 000000000..6c1eaf07c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -0,0 +1,71 @@ +package cn.iocoder.dashboard.framework.sms.core; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.common.exception.ServiceException; +import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; + +/** + * 短信客户端工厂 + * + * @author zzf + * @date 2021/1/28 14:01 + */ +@Component +public class SmsClientFactory { + + private final Map> smsSenderMap = new ConcurrentHashMap<>(8); + + /** + * 创建短信客户端 + * + * @param propertyVO 参数对象 + * @return 客户端id(默认channelId) + */ + public Long createClient(SmsChannelPropertyVO propertyVO) { + if (StrUtil.isBlank(propertyVO.getCode())) { + throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道编码"); + } + if (ObjectUtil.isNull(propertyVO.getId())) { + throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道ID"); + } + + AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO); + smsSenderMap.put(propertyVO.getId(), sender); + return propertyVO.getId(); + } + + private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelPropertyVO channelVO) { + if (channelEnum == null) { + throw new ServiceException(INVALID_CHANNEL_CODE); + } + switch (channelEnum) { + case ALI: + return new AliyunSmsClient(channelVO); + // TODO fill more channel + default: + break; + } + throw new ServiceException(SMS_SENDER_NOT_FOUND); + } + + /** + * 获取短信客户端 + * + * @param channelId 渠道id + * @return 短信id + */ + public AbstractSmsClient getClient(Long channelId) { + return smsSenderMap.get(channelId); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java similarity index 86% rename from src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index b994514b6..a626bb759 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.framework.sms; +package cn.iocoder.dashboard.framework.sms.core; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index a75f9e2eb..932097514 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -44,11 +44,5 @@ public class SmsChannelController { return success(service.createChannel(reqVO)); } - @ApiOperation("刷新消息渠道信息") - @PutMapping("/flush") - public CommonResult flushChannel() { - return success(service.flushChannel()); - } - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java similarity index 94% rename from src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java index 042cddaa2..ab4d73594 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java @@ -14,7 +14,7 @@ import java.util.List; */ @Data @EqualsAndHashCode -public class SmsChannelAllVO implements Serializable { +public class SmsChannelPropertyVO implements Serializable { /** * id diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java index c5156a6ae..d9daf7578 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java @@ -17,6 +17,7 @@ public class SmsTemplateVO { * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) */ private String bizCode; + /** * 编码 */ @@ -27,4 +28,11 @@ public class SmsTemplateVO { */ private String apiTemplateId; + /** + * 内容 + */ + private String content; + + + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index af87d2253..985de7576 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; @@ -28,7 +28,7 @@ public interface SmsChannelConvert { List convertEnum(List bean); - List convert(List bean); + List convert(List bean); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java index a5dce01de..2e52b070e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java @@ -1,10 +1,10 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLog; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SmsLogMapper extends BaseMapper { +public interface SmsLogMapper extends BaseMapper { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java index 169369b1e..10ffef478 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; import java.io.Serializable; import java.util.Date; @@ -15,8 +16,9 @@ import java.util.Date; */ @Data @EqualsAndHashCode +@Accessors(chain = true) @TableName(value = "sms_log", autoResultMap = true) -public class SmsLog implements Serializable { +public class SmsLogDO implements Serializable { /** * 自增编号 @@ -29,19 +31,19 @@ public class SmsLog implements Serializable { private String channelCode; /** - * 实际渠道短信唯一标识 + * 短信渠道id */ - private String apiSmsId; + private Long channelId; /** * 模板id */ - private Long templateId; + private String templateCode; /** - * 手机号 + * 手机号(数组json字符串) */ - private String phone; + private String phones; /** * 内容 @@ -54,7 +56,7 @@ public class SmsLog implements Serializable { private String remark; /** - * 发送状态(0发送中 1成功 2失败) + * 发送状态(1异步推送中 2发送中 3失败 4成功) */ private Integer sendStatus; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 05e9e6393..a1fc081c5 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -83,5 +83,6 @@ public interface SysErrorCodeConstants { ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001003, "没有短信模板信息, 请初始化sms_template表数据。"); ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001004, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001005, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); + ErrorCode PARAM_VALUE_IS_NULL = new ErrorCode(1003001006, "参数【{}】不能为空"); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java new file mode 100644 index 000000000..426e4cb80 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java @@ -0,0 +1,30 @@ +package cn.iocoder.dashboard.modules.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信发送状态 + * + * @author zzf + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SmsSendStatusEnum { + + //异步转发中 + ASYNC(1), + + //发送中 + SENDING(2), + + //失败 + FAIL(3), + + //成功 + SUCCESS(4); + + private final int status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java new file mode 100644 index 000000000..5da9703ca --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -0,0 +1,31 @@ +package cn.iocoder.dashboard.modules.system.mq.consumer.sms; + +import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; +import cn.iocoder.dashboard.modules.system.service.sms.SmsService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 针对 {@link SysDeptRefreshMessage} 的消费者 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class SmsSendConsumer extends AbstractChannelMessageListener { + + @Resource + private SmsService smsService; + + @Override + public void onMessage(SmsSendMessage message) { + log.info("[onMessage][收到 发送短信 消息]"); + SmsResult send = smsService.send(message.getSmsBody(), message.getTargetPhones()); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java new file mode 100644 index 000000000..8ca1207fa --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java @@ -0,0 +1,25 @@ +package cn.iocoder.dashboard.modules.system.mq.message.sms; + +import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import lombok.Data; + +import java.util.Collection; +import java.util.List; + +/** + * 部门数据刷新 Message + */ +@Data +public class SmsSendMessage implements ChannelMessage { + + private SmsBody smsBody; + + private List targetPhones; + + @Override + public String getChannel() { + return "sms.send"; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java new file mode 100644 index 000000000..892b333cf --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java @@ -0,0 +1,31 @@ +package cn.iocoder.dashboard.modules.system.mq.producer.sms; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信的 Producer + */ +@Component +public class SmsProducer { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 发送 {@link SmsSendMessage} 消息 + */ + public void sendSmsSendMessage(SmsBody smsBody, List targetPhoneList) { + SmsSendMessage message = new SmsSendMessage(); + message.setSmsBody(smsBody); + message.setTargetPhones(targetPhoneList); + RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java index 3040f3bdb..5fd39c2cf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java @@ -1,7 +1,8 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -17,18 +18,46 @@ import java.util.List; */ public interface SmsChannelService { + /** + * 初始化短信渠道 + */ + void initSmsClient(); + + /** + * 分页查询短信渠道信息 + * + * @param reqVO 参数对象 + * @return 短信渠道分页对象 + */ PageResult pageChannels(SmsChannelPageReqVO reqVO); + /** + * 创建新的渠道信息 + * + * @param reqVO 参数对象 + * @return 渠道id + */ Long createChannel(SmsChannelCreateReqVO reqVO); + /** + * 获取短信渠道枚举/渠道编码 + * + * @return 短信渠道枚举/渠道编码 + */ List getChannelEnums(); + /** + * 根据短信模板编码获取短信客户端 + * + * @param templateCode 短信模板编码 + * @return 短信客户端 + */ + AbstractSmsClient getClient(String templateCode); + /** * 查询渠道(包含名下模块)信息集合 * * @return 渠道(包含名下模块)信息集合 */ - List listChannelAllEnabledInfo(); - - boolean flushChannel(); + List listChannelAllEnabledInfo(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java index d29d7f884..2646dcbfa 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java @@ -1,5 +1,11 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; + +import java.util.List; + /** * 短信渠道Service接口 * @@ -7,4 +13,23 @@ package cn.iocoder.dashboard.modules.system.service.sms; * @date 2021/1/25 9:24 */ public interface SmsLogService { + /** + * 发送短信前的日志处理 + * + * @param smsBody 短信内容 + * @param targetPhones 发送对象手机号集合 + * @param client 短信客户端 + * @param isAsync 是否异步发送 + * @return 生成的日志id + */ + Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync); + + /** + * 发送消息后的日志处理 + * + * @param logId 日志id + * @param result 消息结果 + */ + void afterSendLog(Long logId, SmsResult result); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java new file mode 100644 index 000000000..56dc2dfa9 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java @@ -0,0 +1,101 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * 短信Service接口 + * + * @author zzf + * @date 2021/1/25 9:24 + */ +public interface SmsService { + + /** + * 发送消息 + * + * @param smsBody 消息内容 + * @param targetPhones 发送对象手机号列表 + * @return 是否发送成功 + */ + SmsResult send(SmsBody smsBody, List targetPhones); + + /** + * 发送消息 + * + * @param smsBody 消息内容 + * @param targetPhone 发送对象手机号 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody smsBody, String targetPhone) { + if (StringUtils.isBlank(targetPhone)) { + return failResult("targetPhone must not null."); + } + + return send(smsBody, Collections.singletonList(targetPhone)); + } + + /** + * 发送消息 + * + * @param smsBody 消息内容 + * @param targetPhones 发送对象手机号数组 + * @return 是否发送成功 + */ + default SmsResult send(SmsBody smsBody, String... targetPhones) { + if (targetPhones == null) { + return failResult("targetPhones must not null."); + } + + return send(smsBody, Arrays.asList(targetPhones)); + } + + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param targetPhones 发送对象列表 + */ + void sendAsync(SmsBody msgBody, List targetPhones); + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param targetPhone 发送对象 + */ + default void sendAsync(SmsBody msgBody, String targetPhone) { + if (StringUtils.isBlank(targetPhone)) { + return; + } + sendAsync(msgBody, Collections.singletonList(targetPhone)); + } + + /** + * 异步发送消息 + * + * @param msgBody 消息内容 + * @param targetPhones 发送对象列表 + */ + default void sendAsync(SmsBody msgBody, String... targetPhones) { + if (targetPhones == null) { + return; + } + sendAsync(msgBody, Arrays.asList(targetPhones)); + } + + + default SmsResult failResult(String message) { + SmsResult resultBody = new SmsResult<>(); + resultBody.setSuccess(false); + resultBody.setMessage(message); + return resultBody; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java index ccc47af3c..044a4e561 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java @@ -3,7 +3,9 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -14,12 +16,16 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsTemplateMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * 短信渠道Service实现类 @@ -30,6 +36,30 @@ import java.util.List; @Service public class SmsChannelServiceImpl implements SmsChannelService { + private final Map templateCode2ChannelIdMap = new ConcurrentHashMap<>(32); + + @Autowired + private SmsClientFactory smsClientFactory; + + /** + * 初始化短信客户端 + */ + @PostConstruct + @Override + public void initSmsClient() { + List smsChannelPropertyVOList = listChannelAllEnabledInfo(); + if (ObjectUtil.isEmpty(smsChannelPropertyVOList)) { + return; + } + smsChannelPropertyVOList.forEach(smsChannelPropertyVO -> { + Long clientId = smsClientFactory.createClient(smsChannelPropertyVO); + smsChannelPropertyVO.getTemplateList().forEach(smsTemplateVO -> { + templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), clientId); + }); + }); + } + + @Resource private SmsChannelMapper mapper; @@ -54,12 +84,17 @@ public class SmsChannelServiceImpl implements SmsChannelService { } @Override - public List listChannelAllEnabledInfo() { + public AbstractSmsClient getClient(String templateCode) { + return smsClientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); + } + + @Override + public List listChannelAllEnabledInfo() { List channelDOList = mapper.selectEnabledList(); if (ObjectUtil.isNull(channelDOList)) { return null; } - List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); + List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); channelAllVOList.forEach(smsChannelDO -> { @@ -71,10 +106,4 @@ public class SmsChannelServiceImpl implements SmsChannelService { }); return channelAllVOList; } - - @Override - public boolean flushChannel() { - - return true; - } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java index e54d265c6..651917259 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java @@ -1,8 +1,21 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService; +import cn.iocoder.dashboard.util.json.JsonUtils; +import cn.iocoder.dashboard.util.string.StrUtils; import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.util.List; + /** * 短信日志Service实现类 * @@ -12,4 +25,48 @@ import org.springframework.stereotype.Service; @Service public class SmsLogServiceImpl implements SmsLogService { + @Resource + private SmsLogMapper smsLogMapper; + + @Override + public Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync) { + SmsLogDO smsLog = new SmsLogDO(); + if (smsBody.getSmsLogId() != null) { + smsLog.setId(smsBody.getSmsLogId()); + smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); + smsLogMapper.updateById(smsLog); + return smsBody.getSmsLogId(); + } else { + SmsChannelPropertyVO property = client.getProperty(); + SmsTemplateVO smsTemplate = property.getTemplateByTemplateCode(smsBody.getTemplateCode()); + + smsLog.setChannelCode(property.getCode()) + .setChannelId(property.getId()) + .setTemplateCode(smsTemplate.getCode()) + .setPhones(JsonUtils.toJsonString(targetPhones)) + .setContent(StrUtils.replace(smsTemplate.getContent(), smsBody.getParams())); + + if (isAsync) { + smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); + } else { + smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); + } + smsLogMapper.insert(smsLog); + return smsLog.getId(); + } + } + + @Override + public void afterSendLog(Long logId, SmsResult result) { + SmsLogDO smsLog = new SmsLogDO(); + smsLog.setId(logId); + if (result.getSuccess()) { + smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus()); + } else { + smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus()); + smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult())); + } + smsLogMapper.updateById(smsLog); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java new file mode 100644 index 000000000..4dc090242 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java @@ -0,0 +1,51 @@ +package cn.iocoder.dashboard.modules.system.service.sms.impl; + +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; +import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SmsService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信日志Service实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Service +public class SmsServiceImpl implements SmsService { + + @Resource + private SmsChannelService channelService; + + @Resource + private SmsLogService smsLogService; + + @Resource + private SmsProducer smsProducer; + + @Override + public SmsResult send(SmsBody smsBody, List targetPhones) { + AbstractSmsClient client = channelService.getClient(smsBody.getTemplateCode()); + Long logId = smsLogService.beforeSendLog(smsBody, targetPhones, client, false); + + SmsResult result = client.send(smsBody, targetPhones); + + smsLogService.afterSendLog(logId, result); + + return result; + } + + @Override + public void sendAsync(SmsBody smsBody, List targetPhones) { + AbstractSmsClient client = channelService.getClient(smsBody.getTemplateCode()); + smsLogService.beforeSendLog(smsBody, targetPhones, client, true); + smsProducer.sendSmsSendMessage(smsBody, targetPhones); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java deleted file mode 100644 index ffb5887bd..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.dashboard.modules.system.sms; - -import cn.iocoder.dashboard.framework.sms.SmsClient; -import cn.iocoder.dashboard.framework.sms.SmsClientAdapter; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.annotation.Resource; -import java.util.List; -import java.util.Map; - -/** - * 短信服务配置 - * - * @author guer - */ -@Configuration -@ConditionalOnProperty("sms.enabled") -public class SmsConfiguration { - - @Resource - private SmsChannelService channelService; - - @Bean - public SmsClientAdapter smsClientWrapper() { - List smsChannelAllVOList = channelService.listChannelAllEnabledInfo(); - Map> channelId2SmsClientMap = SmsSenderUtils.init(smsChannelAllVOList); - return new SmsClientAdapter(channelId2SmsClientMap); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java deleted file mode 100644 index ea9c24489..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java +++ /dev/null @@ -1,143 +0,0 @@ -package cn.iocoder.dashboard.modules.system.sms; - -import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.dashboard.common.enums.SmsChannelEnum; -import cn.iocoder.dashboard.common.exception.ServiceException; -import cn.iocoder.dashboard.framework.sms.SmsBody; -import cn.iocoder.dashboard.framework.sms.SmsClient; -import cn.iocoder.dashboard.framework.sms.SmsClientAdapter; -import cn.iocoder.dashboard.framework.sms.SmsResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.system.sms.client.AliSmsClient; -import cn.iocoder.dashboard.modules.system.sms.proxy.SmsClientLogProxy; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; - -/** - * 短信发送者工厂 - * - * @author zzf - * @date 2021/1/25 16:18 - */ -public class SmsSenderUtils { - - /** - * 短信渠道id:短信客户端map - * key: channelId - * val: SmsClient - */ - private static final Map> smsSenderMap = new ConcurrentHashMap<>(8); - - /** - * 短信模板code: 短信渠道id map - * key: templateCode - * val: channelId - */ - private static final Map templateCode2ChannelIdMap = new HashMap<>(); - - /** - * 将短信渠道信息初始化成短信客户端 - * - * @param smsChannelAllVOList 短信渠道信息 - * @return 短信渠道id:短信客户端map - */ - public synchronized static Map> init(List smsChannelAllVOList) { - if (ObjectUtil.isEmpty(smsChannelAllVOList)) { - throw new ServiceException(SMS_CHANNEL_NOT_FOUND); - } - addSender(smsChannelAllVOList); - return smsSenderMap; - } - - /** - * 重置短信客户端信息 - * - * @param smsClientAdapter 短信客户端适配器 - * @param smsChannelAllVOList 短信渠道信息集合 - */ - public synchronized static void flush(SmsClientAdapter smsClientAdapter, List smsChannelAllVOList) { - smsSenderMap.clear(); - smsClientAdapter.flushClient(init(smsChannelAllVOList)); - } - - /** - * 发送短信 - * - * @param smsClientAdapter 短信客户端适配器 - * @param smsBody 短信内容 - * @param targetPhones 对象手机集合 - * @return 短信发送结果 - */ - public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, Collection targetPhones) { - Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); - if (channelId == null) { - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - return smsClientAdapter.send(channelId, smsBody, targetPhones); - } - - /** - * 发送短信 - * - * @param smsClientAdapter 短信客户端适配器 - * @param smsBody 短信内容 - * @param targetPhone 对象手机 - * @return 短信发送结果 - */ - public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, String targetPhone) { - Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); - if (channelId == null) { - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - return smsClientAdapter.send(channelId, smsBody, Collections.singletonList(targetPhone)); - } - - /** - * 发送短信 - * - * @param smsClientAdapter 短信客户端适配器 - * @param smsBody 短信内容 - * @param targetPhones 对象手机数组 - * @return 短信发送结果 - */ - public static SmsResult send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, String... targetPhones) { - Long channelId = templateCode2ChannelIdMap.get(smsBody.getCode()); - if (channelId == null) { - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - return smsClientAdapter.send(channelId, smsBody, Arrays.asList(targetPhones)); - } - - - private static void addSender(List smsChannelAllVOList) { - smsChannelAllVOList.forEach(channelAllVO -> addSender(SmsChannelEnum.getByCode(channelAllVO.getCode()), channelAllVO)); - } - - private static void addSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { - if (channelEnum == null) { - throw new ServiceException(INVALID_CHANNEL_CODE); - } - List templateList = channelAllVO.getTemplateList(); - if (ObjectUtil.isEmpty(templateList)) { - throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); - } - SmsClient aliSmsClient = getSender(channelEnum, channelAllVO); - templateList.forEach(smsTemplateVO -> templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), channelAllVO.getId())); - smsSenderMap.put(channelAllVO.getId(), aliSmsClient); - } - - private static SmsClient getSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) { - switch (channelEnum) { - case ALI: - return new SmsClientLogProxy<>(new AliSmsClient(channelAllVO)); - // TODO fill more channel - default: - break; - } - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java b/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java deleted file mode 100644 index a7d201e6f..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.dashboard.modules.system.sms.proxy; - -import cn.iocoder.dashboard.framework.sms.SmsBody; -import cn.iocoder.dashboard.framework.sms.SmsClient; -import cn.iocoder.dashboard.framework.sms.SmsResult; -import cn.iocoder.dashboard.util.json.JsonUtils; -import lombok.extern.slf4j.Slf4j; - -import java.util.Collection; - -/** - * 消息父接口 - * - * @author zzf - * @date 2021/1/22 15:46 - */ -@Slf4j -public class SmsClientLogProxy implements SmsClient { - - private final SmsClient smsClient; - - @Override - public SmsResult send(SmsBody msgBody, Collection targets) { - log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets); - - SmsResult resultBody = smsClient.send(msgBody, targets); - - if (resultBody.getSuccess()) { - // - } else { - log.warn("send sms fail, body: {}, target: {}, resultBody: {}", - JsonUtils.toJsonString(msgBody), - targets, - JsonUtils.toJsonString(resultBody) - ); - } - return resultBody; - } - - @Override - public SmsResult sendAsync(SmsBody msgBody, Collection targets) { - return send(msgBody, targets); - } - - public SmsClientLogProxy(SmsClient smsClient) { - this.smsClient = smsClient; - } -} diff --git a/src/main/java/cn/iocoder/dashboard/util/string/StrUtils.java b/src/main/java/cn/iocoder/dashboard/util/string/StrUtils.java index 5e98d915b..e0ca605a4 100644 --- a/src/main/java/cn/iocoder/dashboard/util/string/StrUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/string/StrUtils.java @@ -1,7 +1,10 @@ package cn.iocoder.dashboard.util.string; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import java.util.Map; + /** * 字符串工具类 * @@ -13,4 +16,22 @@ public class StrUtils { return StrUtil.maxLength(str, maxLength - 3); // -3 的原因,是该方法会补充 ... 恰好 } + /** + * 指定字符串的 + * @param str + * @param replaceMap + * @return + */ + public static String replace(String str, Map replaceMap) { + assert StrUtil.isNotBlank(str); + if (ObjectUtil.isEmpty(replaceMap)) { + return str; + } + String result = null; + for (String key : replaceMap.keySet()) { + result = str.replace(key, replaceMap.get(key)); + } + return result; + } + } From 0fd757fbbd74b3e068012c25b1b9cdbf4ba14445 Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Thu, 4 Feb 2021 09:42:50 +0800 Subject: [PATCH 04/54] =?UTF-8?q?=E5=A2=9E=E5=8A=A0SmsProperty=E7=B1=BB?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E9=99=A4smsFactory=E5=AF=B9module=E5=B1=82vo?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/client/AbstractSmsClient.java | 12 ++-- .../framework/sms/client/AliyunSmsClient.java | 4 +- .../framework/sms/core/SmsClientFactory.java | 6 +- .../sms/core/property/SmsChannelProperty.java | 58 +++++++++++++++++++ .../core/property/SmsTemplateProperty.java | 38 ++++++++++++ ...elPropertyVO.java => SmsChannelAllVO.java} | 2 +- .../system/convert/sms/SmsChannelConvert.java | 9 ++- .../system/service/sms/SmsChannelService.java | 4 +- .../sms/impl/SmsChannelServiceImpl.java | 18 +++--- .../service/sms/impl/SmsLogServiceImpl.java | 4 +- 10 files changed, 128 insertions(+), 27 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java rename src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/{SmsChannelPropertyVO.java => SmsChannelAllVO.java} (94%) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index 043dd2a50..0b4907fa2 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.framework.sms.client; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; /** * 抽象短息客户端 @@ -13,19 +13,19 @@ public abstract class AbstractSmsClient implements SmsClient { /** * 短信渠道参数 */ - protected final SmsChannelPropertyVO channelVO; + protected final SmsChannelProperty channelVO; /** * 构造阿里云短信发送处理 * - * @param channelVO 阿里云短信配置 + * @param property 阿里云短信配置 */ - public AbstractSmsClient(SmsChannelPropertyVO channelVO) { - this.channelVO = channelVO; + public AbstractSmsClient(SmsChannelProperty property) { + this.channelVO = property; } - public SmsChannelPropertyVO getProperty() { + public SmsChannelProperty getProperty() { return channelVO; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index 39d359449..4a2ee6d70 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.framework.sms.client; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; @@ -39,7 +39,7 @@ public class AliyunSmsClient extends AbstractSmsClient { * * @param channelVO 阿里云短信配置 */ - public AliyunSmsClient(SmsChannelPropertyVO channelVO) { + public AliyunSmsClient(SmsChannelProperty channelVO) { super(channelVO); String accessKeyId = channelVO.getApiKey(); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 6c1eaf07c..35f87bb98 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -7,7 +7,7 @@ import cn.iocoder.dashboard.common.exception.ServiceException; import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import org.springframework.stereotype.Component; import java.util.Map; @@ -32,7 +32,7 @@ public class SmsClientFactory { * @param propertyVO 参数对象 * @return 客户端id(默认channelId) */ - public Long createClient(SmsChannelPropertyVO propertyVO) { + public Long createClient(SmsChannelProperty propertyVO) { if (StrUtil.isBlank(propertyVO.getCode())) { throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道编码"); } @@ -45,7 +45,7 @@ public class SmsClientFactory { return propertyVO.getId(); } - private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelPropertyVO channelVO) { + private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) { if (channelEnum == null) { throw new ServiceException(INVALID_CHANNEL_CODE); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java new file mode 100644 index 000000000..402b0d7e7 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java @@ -0,0 +1,58 @@ +package cn.iocoder.dashboard.framework.sms.core.property; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.List; + +/** + * 渠道(包含模板)信息VO类 + * + * @author zzf + * @date 2021/1/25 17:01 + */ +@Data +@EqualsAndHashCode +public class SmsChannelProperty implements Serializable { + + /** + * id + */ + private Long id; + + /** + * 编码(来自枚举类 阿里、华为、七牛等) + */ + private String code; + + /** + * 渠道账号id + */ + private String apiKey; + + /** + * 渠道账号秘钥 + */ + private String apiSecret; + + /** + * 实际渠道签名唯一标识 + */ + private String apiSignatureId; + + /** + * 签名值 + */ + private String signature; + + /** + * 该渠道名下的短信模板集合 + */ + private List templateList; + + public SmsTemplateProperty getTemplateByTemplateCode(String tempCode) { + return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get(); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java new file mode 100644 index 000000000..8cfb20ba6 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java @@ -0,0 +1,38 @@ +package cn.iocoder.dashboard.framework.sms.core.property; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 渠道模板VO类 + * + * @author zzf + * @date 2021/1/25 17:03 + */ +@Data +@EqualsAndHashCode +public class SmsTemplateProperty { + + /** + * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) + */ + private String bizCode; + + /** + * 编码 + */ + private String code; + + /** + * 实际渠道模板唯一标识 + */ + private String apiTemplateId; + + /** + * 内容 + */ + private String content; + + + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java similarity index 94% rename from src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java index ab4d73594..042cddaa2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelPropertyVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java @@ -14,7 +14,7 @@ import java.util.List; */ @Data @EqualsAndHashCode -public class SmsChannelPropertyVO implements Serializable { +public class SmsChannelAllVO implements Serializable { /** * id diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index 985de7576..b52167ef7 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -2,11 +2,12 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -28,7 +29,9 @@ public interface SmsChannelConvert { List convertEnum(List bean); - List convert(List bean); + List convert(List bean); + + List convertProperty(List list); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java index 5fd39c2cf..f30ea2b88 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -59,5 +59,5 @@ public interface SmsChannelService { * * @return 渠道(包含名下模块)信息集合 */ - List listChannelAllEnabledInfo(); + List listChannelAllEnabledInfo(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java index 044a4e561..db36b86f4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java @@ -5,7 +5,8 @@ import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -47,13 +48,14 @@ public class SmsChannelServiceImpl implements SmsChannelService { @PostConstruct @Override public void initSmsClient() { - List smsChannelPropertyVOList = listChannelAllEnabledInfo(); - if (ObjectUtil.isEmpty(smsChannelPropertyVOList)) { + List smsChannelAllVOList = listChannelAllEnabledInfo(); + if (ObjectUtil.isEmpty(smsChannelAllVOList)) { return; } - smsChannelPropertyVOList.forEach(smsChannelPropertyVO -> { - Long clientId = smsClientFactory.createClient(smsChannelPropertyVO); - smsChannelPropertyVO.getTemplateList().forEach(smsTemplateVO -> { + List channelPropertyList = SmsChannelConvert.INSTANCE.convertProperty(smsChannelAllVOList); + channelPropertyList.forEach(smsChannelProperty -> { + Long clientId = smsClientFactory.createClient(smsChannelProperty); + smsChannelProperty.getTemplateList().forEach(smsTemplateVO -> { templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), clientId); }); }); @@ -89,12 +91,12 @@ public class SmsChannelServiceImpl implements SmsChannelService { } @Override - public List listChannelAllEnabledInfo() { + public List listChannelAllEnabledInfo() { List channelDOList = mapper.selectEnabledList(); if (ObjectUtil.isNull(channelDOList)) { return null; } - List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); + List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); channelAllVOList.forEach(smsChannelDO -> { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java index 651917259..5853463e8 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java @@ -3,7 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelPropertyVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO; @@ -37,7 +37,7 @@ public class SmsLogServiceImpl implements SmsLogService { smsLogMapper.updateById(smsLog); return smsBody.getSmsLogId(); } else { - SmsChannelPropertyVO property = client.getProperty(); + SmsChannelAllVO property = client.getProperty(); SmsTemplateVO smsTemplate = property.getTemplateByTemplateCode(smsBody.getTemplateCode()); smsLog.setChannelCode(property.getCode()) From a50db6bf7ff76dc3b323adedea3ef9ab979b3cd6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 22 Feb 2021 09:44:31 +0800 Subject: [PATCH 05/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=9A=84=20code=20review=202020-02-22?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/iocoder/dashboard/common/enums/SmsChannelEnum.java | 7 +++++-- .../dashboard/framework/sms/client/AliyunSmsClient.java | 2 +- .../dashboard/framework/sms/core/SmsClientFactory.java | 1 + .../cn/iocoder/dashboard/framework/sms/core/SmsResult.java | 4 ++-- .../framework/sms/core/property/SmsTemplateProperty.java | 2 +- .../modules/system/mq/producer/sms/SmsProducer.java | 1 + .../modules/system/service/sms/SmsChannelService.java | 3 +++ .../modules/system/service/sms/SmsLogService.java | 2 ++ .../system/service/sms/impl/SmsChannelServiceImpl.java | 2 +- .../modules/system/service/sms/impl/SmsServiceImpl.java | 1 + 10 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java index fdb80387d..0e6fb6602 100644 --- a/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java @@ -3,8 +3,11 @@ package cn.iocoder.dashboard.common.enums; import lombok.AllArgsConstructor; import lombok.Getter; +import java.util.function.Predicate; +import java.util.stream.Stream; + /** - * 短信渠道枚举 + * 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下 * * @author zzf * @date 2021/1/25 10:56 @@ -16,7 +19,7 @@ public enum SmsChannelEnum { ALI("ALI", "阿里"), HUA_WEI("HUA_WEI", "华为"), QI_NIU("QI_NIU", "七牛"), - TEN_XUN("TEN_XUN", "腾讯"); + TEN_XUN("TEN_XUN", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。 private final String code; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index 4a2ee6d70..60f12f575 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -60,7 +60,7 @@ public class AliyunSmsClient extends AbstractSmsClient { request.setSignName(channelVO.getApiSignatureId()); request.setTemplateCode(channelVO.getTemplateByTemplateCode(smsBody.getTemplateCode()).getApiTemplateId()); request.setTemplateParam(smsBody.getParamsStr()); - + // TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 try { SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 35f87bb98..68864db11 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -33,6 +33,7 @@ public class SmsClientFactory { * @return 客户端id(默认channelId) */ public Long createClient(SmsChannelProperty propertyVO) { + // TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。 if (StrUtil.isBlank(propertyVO.getCode())) { throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道编码"); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index a626bb759..101a1af4a 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -13,7 +13,7 @@ public class SmsResult implements Serializable { /** * 是否成功 */ - private Boolean success; + private Boolean success; // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 /** * 提示 @@ -23,5 +23,5 @@ public class SmsResult implements Serializable { /** * 返回值 */ - private T result; + private T result; // TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶 } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java index 8cfb20ba6..aa0a8c461 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java @@ -4,7 +4,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; /** - * 渠道模板VO类 + * 渠道模板VO类 TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 * * @author zzf * @date 2021/1/25 17:03 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java index 892b333cf..c758a4a15 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java @@ -25,6 +25,7 @@ public class SmsProducer { SmsSendMessage message = new SmsSendMessage(); message.setSmsBody(smsBody); message.setTargetPhones(targetPhoneList); + // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java index f30ea2b88..5cb34a24e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java @@ -18,6 +18,9 @@ import java.util.List; */ public interface SmsChannelService { + // TODO FROM 芋艿 to ZZF:SmsChannelService=》SysSmsChannelService,增加 Sys 前缀,算在系统模块里 + // TODO FROM 芋艿 to ZZF:方法名,保持不去掉 Sms 前缀。虽然长点,嘿嘿 + /** * 初始化短信渠道 */ diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java index 2646dcbfa..bbc50773f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java @@ -22,6 +22,8 @@ public interface SmsLogService { * @param isAsync 是否异步发送 * @return 生成的日志id */ + // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果 + // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync); /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java index db36b86f4..1bc8f7136 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java @@ -61,7 +61,7 @@ public class SmsChannelServiceImpl implements SmsChannelService { }); } - + // TODO FROM 芋艿 to ZZF:channelMapper 嘿,保持命名统一。 @Resource private SmsChannelMapper mapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java index 4dc090242..999649b8f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java @@ -42,6 +42,7 @@ public class SmsServiceImpl implements SmsService { return result; } + // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。 @Override public void sendAsync(SmsBody smsBody, List targetPhones) { AbstractSmsClient client = channelService.getClient(smsBody.getTemplateCode()); From b4be8e987a3dfbee6a830ff90733de7cf6d29f6c Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Tue, 23 Feb 2021 15:33:05 +0800 Subject: [PATCH 06/54] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/client/AbstractSmsClient.java | 47 +++++++++++- .../framework/sms/client/AliyunSmsClient.java | 51 +++++++------ .../framework/sms/client/SmsClient.java | 11 +-- .../framework/sms/core/SmsClientFactory.java | 65 +++++++++++++---- .../framework/sms/core/SmsResult.java | 15 +++- .../framework/sms/core/SmsResultDetail.java | 33 +++++++++ .../sms/core}/enums/SmsChannelEnum.java | 9 +-- .../sms/core/property/SmsChannelProperty.java | 17 ++--- .../core/property/SmsTemplateProperty.java | 17 ++++- .../controller/sms/SmsChannelController.java | 14 ++-- .../system/convert/sms/SmsChannelConvert.java | 14 ++-- .../convert/sms/SmsTemplateConvert.java | 10 +-- .../dal/mysql/dao/sms/SmsTemplateMapper.java | 39 ---------- ...elMapper.java => SysSmsChannelMapper.java} | 20 ++--- ...SmsLogMapper.java => SysSmsLogMapper.java} | 4 +- .../mysql/dao/sms/SysSmsTemplateMapper.java | 39 ++++++++++ ...SmsChannelDO.java => SysSmsChannelDO.java} | 2 +- .../sms/{SmsLogDO.java => SysSmsLogDO.java} | 2 +- ...sTemplateDO.java => SysSmsTemplateDO.java} | 2 +- .../mq/consumer/sms/SmsSendConsumer.java | 6 +- ...Service.java => SysSmsChannelService.java} | 22 ++++-- ...sLogService.java => SysSmsLogService.java} | 10 ++- .../{SmsService.java => SysSmsService.java} | 12 +-- ...ervice.java => SysSmsTemplateService.java} | 2 +- .../service/sms/impl/SmsServiceImpl.java | 52 ------------- ...mpl.java => SysSmsChannelServiceImpl.java} | 73 +++++++++++-------- ...iceImpl.java => SysSmsLogServiceImpl.java} | 35 ++++----- .../service/sms/impl/SysSmsServiceImpl.java | 54 ++++++++++++++ ...pl.java => SysSmsTemplateServiceImpl.java} | 4 +- 29 files changed, 418 insertions(+), 263 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java rename src/main/java/cn/iocoder/dashboard/{common => framework/sms/core}/enums/SmsChannelEnum.java (70%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/{SmsChannelMapper.java => SysSmsChannelMapper.java} (56%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/{SmsLogMapper.java => SysSmsLogMapper.java} (74%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsTemplateMapper.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/{SmsChannelDO.java => SysSmsChannelDO.java} (95%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/{SmsLogDO.java => SysSmsLogDO.java} (95%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/{SmsTemplateDO.java => SysSmsTemplateDO.java} (96%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/{SmsChannelService.java => SysSmsChannelService.java} (73%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/{SmsLogService.java => SysSmsLogService.java} (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/{SmsService.java => SysSmsService.java} (86%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/{SmsTemplateService.java => SysSmsTemplateService.java} (77%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/{SmsChannelServiceImpl.java => SysSmsChannelServiceImpl.java} (50%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/{SmsLogServiceImpl.java => SysSmsLogServiceImpl.java} (60%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/{SmsTemplateServiceImpl.java => SysSmsTemplateServiceImpl.java} (57%) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index 0b4907fa2..14ef40d2c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -1,6 +1,11 @@ package cn.iocoder.dashboard.framework.sms.client; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collection; /** * 抽象短息客户端 @@ -8,7 +13,8 @@ import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; * @author zzf * @date 2021/2/1 9:28 */ -public abstract class AbstractSmsClient implements SmsClient { +@Slf4j +public abstract class AbstractSmsClient implements SmsClient { /** * 短信渠道参数 @@ -29,4 +35,43 @@ public abstract class AbstractSmsClient implements SmsClient { return channelVO; } + @Override + public SmsResult send(String templateApiId, SmsBody smsBody, Collection targets) { + SmsResult result; + try { + beforeSend(templateApiId, smsBody, targets); + result = doSend(templateApiId, smsBody, targets); + afterSend(templateApiId, smsBody, targets, result); + } catch (Exception e) { + // exception handle + log.debug(e.getMessage(), e); + return failResult("发送异常: " + e.getMessage()); + } + return result; + } + + + /** + * 发送消息 + * + * @param templateApiId 短信模板唯一标识 + * @param smsBody 消息内容 + * @param targets 发送对象列表 + * @return 短信发送结果 + */ + public abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; + + protected void beforeSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { + } + + protected void afterSend(String templateApiId, SmsBody smsBody, Collection targets, SmsResult result) throws Exception { + } + + + SmsResult failResult(String message) { + SmsResult resultBody = new SmsResult(); + resultBody.setSuccess(false); + resultBody.setMessage(message); + return resultBody; + } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index 60f12f575..f1976589c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -1,10 +1,14 @@ package cn.iocoder.dashboard.framework.sms.client; +import cn.hutool.core.date.DateUtil; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.http.MethodType; @@ -13,7 +17,9 @@ import com.aliyuncs.profile.IClientProfile; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** * 阿里短信实现类 @@ -22,7 +28,7 @@ import java.util.Collection; * @date 2021/1/25 14:17 */ @Slf4j -public class AliyunSmsClient extends AbstractSmsClient { +public class AliyunSmsClient extends AbstractSmsClient { private static final String OK = "OK"; @@ -53,35 +59,36 @@ public class AliyunSmsClient extends AbstractSmsClient { @Override - public SmsResult send(SmsBody smsBody, Collection targets) { + public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); request.setPhoneNumbers(StringUtils.join(targets, ",")); request.setSignName(channelVO.getApiSignatureId()); - request.setTemplateCode(channelVO.getTemplateByTemplateCode(smsBody.getTemplateCode()).getApiTemplateId()); + request.setTemplateCode(templateApiId); request.setTemplateParam(smsBody.getParamsStr()); - // TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 - try { - SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + // TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 DONE + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); - boolean result = OK.equals(sendSmsResponse.getCode()); - if (!result) { - log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); - } - SmsResult resultBody = new SmsResult<>(); - resultBody.setSuccess(result); - resultBody.setResult(sendSmsResponse); - return resultBody; - } catch (Exception e) { - log.debug(e.getMessage(), e); - return failResult("发送异常: " + e.getMessage()); + boolean result = OK.equals(sendSmsResponse.getCode()); + if (!result) { + log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); } - } + SmsResult resultBody = new SmsResult(); + resultBody.setSuccess(result); + QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest(); + querySendDetailsRequest.setBizId(sendSmsResponse.getBizId()); - SmsResult failResult(String message) { - SmsResult resultBody = new SmsResult<>(); - resultBody.setSuccess(false); - resultBody.setMessage(message); + QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest); + List resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount())); + acsResponse.getSmsSendDetailDTOs().forEach(s -> { + SmsResultDetail resultDetail = new SmsResultDetail(); + resultDetail.setCreateTime(DateUtil.parseDateTime(s.getSendDate())); + resultDetail.setMessage(s.getContent()); + resultDetail.setPhone(s.getPhoneNum()); + resultDetail.setStatus(Math.toIntExact(s.getSendStatus())); + resultDetailList.add(resultDetail); + }); + resultBody.setResult(resultDetailList); return resultBody; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java index 290d21712..94a6de933 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -11,15 +11,16 @@ import java.util.Collection; * @author zzf * @date 2021/1/25 14:14 */ -public interface SmsClient { +public interface SmsClient { /** * 发送消息 * - * @param smsBody 消息内容 - * @param targets 发送对象列表 - * @return 是否发送成功 + * @param templateApiId 短信模板唯一标识 + * @param smsBody 消息内容 + * @param targets 发送对象列表 + * @return 短信发送结果 */ - SmsResult send(SmsBody smsBody, Collection targets); + SmsResult send(String templateApiId, SmsBody smsBody, Collection targets); } \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 68864db11..4cd8e0f89 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -1,15 +1,14 @@ package cn.iocoder.dashboard.framework.sms.core; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.exception.ServiceException; -import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; import org.springframework.stereotype.Component; +import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -24,7 +23,17 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @Component public class SmsClientFactory { - private final Map> smsSenderMap = new ConcurrentHashMap<>(8); + /** + * channelId: client map + * 保存 渠道id: 对应短信客户端 的map + */ + private final Map smsSenderMap = new ConcurrentHashMap<>(8); + + /** + * templateCode: TemplateProperty map + * 保存 模板编码:模板信息 的map + */ + private final Map templatePropertyMap = new ConcurrentHashMap<>(16); /** * 创建短信客户端 @@ -33,20 +42,13 @@ public class SmsClientFactory { * @return 客户端id(默认channelId) */ public Long createClient(SmsChannelProperty propertyVO) { - // TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。 - if (StrUtil.isBlank(propertyVO.getCode())) { - throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道编码"); - } - if (ObjectUtil.isNull(propertyVO.getId())) { - throw ServiceExceptionUtil.exception(PARAM_VALUE_IS_NULL, "短信渠道ID"); - } - - AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO); + // TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。 DONE + AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO); smsSenderMap.put(propertyVO.getId(), sender); return propertyVO.getId(); } - private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) { + private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) { if (channelEnum == null) { throw new ServiceException(INVALID_CHANNEL_CODE); } @@ -66,7 +68,38 @@ public class SmsClientFactory { * @param channelId 渠道id * @return 短信id */ - public AbstractSmsClient getClient(Long channelId) { + public AbstractSmsClient getClient(Long channelId) { return smsSenderMap.get(channelId); } + + + /** + * 添加或修改短信模板信息缓存 + */ + public void addOrUpdateTemplateCache(Collection templateProperties) { + templateProperties.forEach(s -> templatePropertyMap.put(s.getCode(), s)); + } + + + /** + * 添加或修改短信模板信息缓存 + */ + public void addOrUpdateTemplateCache(SmsTemplateProperty templateProperty) { + templatePropertyMap.put(templateProperty.getCode(), templateProperty); + } + + + /** + * 根据短信模板编码获取模板唯一标识 + * + * @param templateCode 短信模板编码 + * @return 短信id + */ + public String getTemplateApiIdByCode(String templateCode) { + SmsTemplateProperty smsTemplateProperty = templatePropertyMap.get(templateCode); + if (smsTemplateProperty == null) { + throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); + } + return smsTemplateProperty.getApiTemplateId(); + } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 101a1af4a..64bbd1e4b 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -3,17 +3,24 @@ package cn.iocoder.dashboard.framework.sms.core; import lombok.Data; import java.io.Serializable; +import java.util.List; /** * 消息内容实体类 */ @Data -public class SmsResult implements Serializable { +public class SmsResult implements Serializable { /** * 是否成功 */ - private Boolean success; // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 + // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 DONE + private Boolean success; + + /** + * 状态码 + */ + private String code; /** * 提示 @@ -23,5 +30,7 @@ public class SmsResult implements Serializable { /** * 返回值 */ - private T result; // TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶 + // TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶 DONE + private List result; + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java new file mode 100644 index 000000000..6ed9fbcae --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -0,0 +1,33 @@ +package cn.iocoder.dashboard.framework.sms.core; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 消息内容实体类 + */ +@Data +public class SmsResultDetail implements Serializable { + + /** + * 状态 1成功 2失败 3等待回执 + */ + private Integer status; + + /** + * 接收手机号 + */ + private String phone; + + /** + * 提示 + */ + private String message; + + /** + * 时间 + */ + private Date createTime; +} diff --git a/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java similarity index 70% rename from src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 0e6fb6602..5aebdfa6d 100644 --- a/src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -1,13 +1,10 @@ -package cn.iocoder.dashboard.common.enums; +package cn.iocoder.dashboard.framework.sms.core.enums; import lombok.AllArgsConstructor; import lombok.Getter; -import java.util.function.Predicate; -import java.util.stream.Stream; - /** - * 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下 + * 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下 DONE * * @author zzf * @date 2021/1/25 10:56 @@ -19,7 +16,7 @@ public enum SmsChannelEnum { ALI("ALI", "阿里"), HUA_WEI("HUA_WEI", "华为"), QI_NIU("QI_NIU", "七牛"), - TEN_XUN("TEN_XUN", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。 + TENCENT("TENCENT", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。 DONE private final String code; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java index 402b0d7e7..95f2a8ce7 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java @@ -3,6 +3,8 @@ package cn.iocoder.dashboard.framework.sms.core.property; import lombok.Data; import lombok.EqualsAndHashCode; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import java.io.Serializable; import java.util.List; @@ -19,40 +21,37 @@ public class SmsChannelProperty implements Serializable { /** * id */ + @NotNull(message = "短信渠道ID不能为空") private Long id; /** * 编码(来自枚举类 阿里、华为、七牛等) */ + @NotEmpty(message = "短信渠道编码不能为空") private String code; /** * 渠道账号id */ + @NotEmpty(message = "渠道账号id不能为空") private String apiKey; /** * 渠道账号秘钥 */ + @NotEmpty(message = "渠道账号秘钥不能为空") private String apiSecret; /** * 实际渠道签名唯一标识 */ + @NotEmpty(message = "实际渠道签名唯一标识不能为空") private String apiSignatureId; /** * 签名值 */ + @NotEmpty(message = "签名值不能为空") private String signature; - /** - * 该渠道名下的短信模板集合 - */ - private List templateList; - - public SmsTemplateProperty getTemplateByTemplateCode(String tempCode) { - return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get(); - } - } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java index aa0a8c461..a613a5453 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java @@ -3,8 +3,12 @@ package cn.iocoder.dashboard.framework.sms.core.property; import lombok.Data; import lombok.EqualsAndHashCode; +import javax.validation.constraints.NotEmpty; + /** - * 渠道模板VO类 TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 + * 渠道模板VO类 + * TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 + * * * @author zzf * @date 2021/1/25 17:03 @@ -13,6 +17,12 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode public class SmsTemplateProperty { + /** + * 渠道id + */ + @NotEmpty(message = "短信渠道编码不能为空") + private Long channelId; + /** * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) */ @@ -21,18 +31,19 @@ public class SmsTemplateProperty { /** * 编码 */ + @NotEmpty(message = "短信模板编码不能为空") private String code; /** * 实际渠道模板唯一标识 */ + @NotEmpty(message = "短信模板唯一标识不能为空") private String apiTemplateId; /** * 内容 */ + @NotEmpty(message = "短信模板内容不能为空") private String content; - - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index 932097514..f32074cbf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -5,8 +5,8 @@ import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; @@ -23,25 +23,25 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success; public class SmsChannelController { @Resource - private SmsChannelService service; + private SysSmsChannelService service; @ApiOperation("获取渠道/签名分页") @GetMapping("/page") - public CommonResult> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { - return success(service.pageChannels(reqVO)); + public CommonResult> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { + return success(service.pageSmsChannels(reqVO)); } @ApiOperation("获取渠道枚举") @GetMapping("/list/channel-enum") public CommonResult> getChannelEnums() { - return success(service.getChannelEnums()); + return success(service.getSmsChannelEnums()); } @ApiOperation("添加消息渠道") @PostMapping("/create") public CommonResult add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { - return success(service.createChannel(reqVO)); + return success(service.createSmsChannel(reqVO)); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index b52167ef7..ad272218e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -1,13 +1,13 @@ package cn.iocoder.dashboard.modules.system.convert.sms; -import cn.iocoder.dashboard.common.enums.SmsChannelEnum; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -21,17 +21,19 @@ public interface SmsChannelConvert { SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); @Mapping(source = "records", target = "list") - PageResult convertPage(IPage page); + PageResult convertPage(IPage page); - SmsChannelDO convert(SmsChannelCreateReqVO bean); + SysSmsChannelDO convert(SmsChannelCreateReqVO bean); - SmsChannelDO convert(SysUserUpdateReqVO bean); + SysSmsChannelDO convert(SysUserUpdateReqVO bean); List convertEnum(List bean); - List convert(List bean); + List convert(List bean); List convertProperty(List list); + List convertProperties(List list); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java index 476b96e0e..aaac0abdf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java @@ -2,8 +2,8 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -17,10 +17,10 @@ public interface SmsTemplateConvert { SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class); @Mapping(source = "records", target = "list") - PageResult convertPage(IPage page); + PageResult convertPage(IPage page); - List convert(List bean); + List convert(List bean); - SmsTemplateVO convert(SmsTemplateDO bean); + SmsTemplateVO convert(SysSmsTemplateDO bean); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java deleted file mode 100644 index fd941ae7a..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; - -import cn.iocoder.dashboard.common.enums.CommonStatusEnum; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -@Mapper -public interface SmsTemplateMapper extends BaseMapper { - - /** - * 根据短信渠道id查询短信模板集合 - * - * @param channelId 渠道id - * @return 模板集合 - */ - default List selectListByChannelId(Long channelId) { - return selectList(new LambdaQueryWrapper() - .eq(SmsTemplateDO::getChannelId, channelId) - .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SmsTemplateDO::getId) - ); - } - - /** - * 查询有效短信模板集合 - * - * @return 有效短信模板集合 - */ - default List selectEnabledList() { - return selectList(new LambdaQueryWrapper() - .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SmsTemplateDO::getId) - ); - } -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsChannelMapper.java similarity index 56% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsChannelMapper.java index d1ce95c62..43b7fe743 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsChannelMapper.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -13,19 +13,19 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper -public interface SmsChannelMapper extends BaseMapper { +public interface SysSmsChannelMapper extends BaseMapper { - default IPage selectChannelPage(SmsChannelPageReqVO reqVO) { - return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper() - .like(StrUtil.isNotBlank(reqVO.getName()), SmsChannelDO::getName, reqVO.getName()) - .like(StrUtil.isNotBlank(reqVO.getSignature()), SmsChannelDO::getName, reqVO.getSignature()) + default IPage selectChannelPage(SmsChannelPageReqVO reqVO) { + return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper() + .like(StrUtil.isNotBlank(reqVO.getName()), SysSmsChannelDO::getName, reqVO.getName()) + .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getName, reqVO.getSignature()) ); } - default List selectEnabledList() { - return selectList(new LambdaQueryWrapper() - .eq(SmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SmsChannelDO::getId) + default List selectEnabledList() { + return selectList(new LambdaQueryWrapper() + .eq(SysSmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SysSmsChannelDO::getId) ); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java similarity index 74% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java index 2e52b070e..cdb6df40b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java @@ -1,10 +1,10 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SmsLogMapper extends BaseMapper { +public interface SysSmsLogMapper extends BaseMapper { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsTemplateMapper.java new file mode 100644 index 000000000..b24c630d4 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsTemplateMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; + +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SysSmsTemplateMapper extends BaseMapper { + + /** + * 根据短信渠道id查询短信模板集合 + * + * @param channelId 渠道id + * @return 模板集合 + */ + default List selectListByChannelId(Long channelId) { + return selectList(new LambdaQueryWrapper() + .eq(SysSmsTemplateDO::getChannelId, channelId) + .eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SysSmsTemplateDO::getId) + ); + } + + /** + * 查询有效短信模板集合 + * + * @return 有效短信模板集合 + */ + default List selectEnabledList() { + return selectList(new LambdaQueryWrapper() + .eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + .orderByAsc(SysSmsTemplateDO::getId) + ); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java similarity index 95% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java index 5cce2ffa4..3e9422e79 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java @@ -15,7 +15,7 @@ import lombok.EqualsAndHashCode; @Data @EqualsAndHashCode(callSuper = true) @TableName(value = "sms_channel", autoResultMap = true) -public class SmsChannelDO extends BaseDO { +public class SysSmsChannelDO extends BaseDO { /** * 自增编号 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java similarity index 95% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java index 10ffef478..97ec6c02e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java @@ -18,7 +18,7 @@ import java.util.Date; @EqualsAndHashCode @Accessors(chain = true) @TableName(value = "sms_log", autoResultMap = true) -public class SmsLogDO implements Serializable { +public class SysSmsLogDO implements Serializable { /** * 自增编号 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java similarity index 96% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java index 360999838..3e8cdc25c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java @@ -16,7 +16,7 @@ import java.util.Date; @Data @EqualsAndHashCode(callSuper = true) @TableName(value = "sms_template", autoResultMap = true) -public class SmsTemplateDO extends BaseDO { +public class SysSmsTemplateDO extends BaseDO { /** * 自增编号 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index 5da9703ca..53cce0bc2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -4,7 +4,7 @@ import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageLi import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import cn.iocoder.dashboard.modules.system.service.sms.SmsService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -20,12 +20,12 @@ import javax.annotation.Resource; public class SmsSendConsumer extends AbstractChannelMessageListener { @Resource - private SmsService smsService; + private SysSmsService sysSmsService; @Override public void onMessage(SmsSendMessage message) { log.info("[onMessage][收到 发送短信 消息]"); - SmsResult send = smsService.send(message.getSmsBody(), message.getTargetPhones()); + SmsResult send = sysSmsService.send(message.getSmsBody(), message.getTargetPhones()); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index 5cb34a24e..d9200f96c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -6,7 +6,7 @@ import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; import java.util.List; @@ -16,7 +16,7 @@ import java.util.List; * @author zzf * @date 2021/1/25 9:24 */ -public interface SmsChannelService { +public interface SysSmsChannelService { // TODO FROM 芋艿 to ZZF:SmsChannelService=》SysSmsChannelService,增加 Sys 前缀,算在系统模块里 // TODO FROM 芋艿 to ZZF:方法名,保持不去掉 Sms 前缀。虽然长点,嘿嘿 @@ -32,7 +32,7 @@ public interface SmsChannelService { * @param reqVO 参数对象 * @return 短信渠道分页对象 */ - PageResult pageChannels(SmsChannelPageReqVO reqVO); + PageResult pageSmsChannels(SmsChannelPageReqVO reqVO); /** * 创建新的渠道信息 @@ -40,14 +40,14 @@ public interface SmsChannelService { * @param reqVO 参数对象 * @return 渠道id */ - Long createChannel(SmsChannelCreateReqVO reqVO); + Long createSmsChannel(SmsChannelCreateReqVO reqVO); /** * 获取短信渠道枚举/渠道编码 * * @return 短信渠道枚举/渠道编码 */ - List getChannelEnums(); + List getSmsChannelEnums(); /** * 根据短信模板编码获取短信客户端 @@ -55,12 +55,20 @@ public interface SmsChannelService { * @param templateCode 短信模板编码 * @return 短信客户端 */ - AbstractSmsClient getClient(String templateCode); + AbstractSmsClient getSmsClient(String templateCode); + + /** + * 根据短信模板编码获取模板唯一标识 + * + * @param templateCode 短信模板编码 + * @return 短信客户端 + */ + String getSmsTemplateApiIdByCode(String templateCode); /** * 查询渠道(包含名下模块)信息集合 * * @return 渠道(包含名下模块)信息集合 */ - List listChannelAllEnabledInfo(); + List listSmsChannelAllEnabledInfo(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java index bbc50773f..431737912 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java @@ -12,7 +12,7 @@ import java.util.List; * @author zzf * @date 2021/1/25 9:24 */ -public interface SmsLogService { +public interface SysSmsLogService { /** * 发送短信前的日志处理 * @@ -22,9 +22,11 @@ public interface SmsLogService { * @param isAsync 是否异步发送 * @return 生成的日志id */ - // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果 + // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果. + // 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。 + // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 - Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync); + Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync); /** * 发送消息后的日志处理 @@ -32,6 +34,6 @@ public interface SmsLogService { * @param logId 日志id * @param result 消息结果 */ - void afterSendLog(Long logId, SmsResult result); + void afterSendLog(Long logId, SmsResult result); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java similarity index 86% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 56dc2dfa9..5b403cb5e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -14,7 +14,7 @@ import java.util.List; * @author zzf * @date 2021/1/25 9:24 */ -public interface SmsService { +public interface SysSmsService { /** * 发送消息 @@ -23,7 +23,7 @@ public interface SmsService { * @param targetPhones 发送对象手机号列表 * @return 是否发送成功 */ - SmsResult send(SmsBody smsBody, List targetPhones); + SmsResult send(SmsBody smsBody, List targetPhones); /** * 发送消息 @@ -32,7 +32,7 @@ public interface SmsService { * @param targetPhone 发送对象手机号 * @return 是否发送成功 */ - default SmsResult send(SmsBody smsBody, String targetPhone) { + default SmsResult send(SmsBody smsBody, String targetPhone) { if (StringUtils.isBlank(targetPhone)) { return failResult("targetPhone must not null."); } @@ -47,7 +47,7 @@ public interface SmsService { * @param targetPhones 发送对象手机号数组 * @return 是否发送成功 */ - default SmsResult send(SmsBody smsBody, String... targetPhones) { + default SmsResult send(SmsBody smsBody, String... targetPhones) { if (targetPhones == null) { return failResult("targetPhones must not null."); } @@ -91,8 +91,8 @@ public interface SmsService { } - default SmsResult failResult(String message) { - SmsResult resultBody = new SmsResult<>(); + default SmsResult failResult(String message) { + SmsResult resultBody = new SmsResult(); resultBody.setSuccess(false); resultBody.setMessage(message); return resultBody; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java similarity index 77% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java index 585a22a57..8ba74b2f6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java @@ -6,5 +6,5 @@ package cn.iocoder.dashboard.modules.system.service.sms; * @author zzf * @date 2021/1/25 9:24 */ -public interface SmsTemplateService { +public interface SysSmsTemplateService { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java deleted file mode 100644 index 999649b8f..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsServiceImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.dashboard.modules.system.service.sms.impl; - -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; -import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService; -import cn.iocoder.dashboard.modules.system.service.sms.SmsService; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 短信日志Service实现类 - * - * @author zzf - * @date 2021/1/25 9:25 - */ -@Service -public class SmsServiceImpl implements SmsService { - - @Resource - private SmsChannelService channelService; - - @Resource - private SmsLogService smsLogService; - - @Resource - private SmsProducer smsProducer; - - @Override - public SmsResult send(SmsBody smsBody, List targetPhones) { - AbstractSmsClient client = channelService.getClient(smsBody.getTemplateCode()); - Long logId = smsLogService.beforeSendLog(smsBody, targetPhones, client, false); - - SmsResult result = client.send(smsBody, targetPhones); - - smsLogService.afterSendLog(logId, result); - - return result; - } - - // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。 - @Override - public void sendAsync(SmsBody smsBody, List targetPhones) { - AbstractSmsClient client = channelService.getClient(smsBody.getTemplateCode()); - smsLogService.beforeSendLog(smsBody, targetPhones, client, true); - smsProducer.sendSmsSendMessage(smsBody, targetPhones); - } -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java similarity index 50% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index 1bc8f7136..b59ed5619 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java @@ -1,10 +1,10 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.util.ObjectUtil; -import cn.iocoder.dashboard.common.enums.SmsChannelEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; @@ -12,11 +12,11 @@ import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageR import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsChannelMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsTemplateMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsTemplateDO; -import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsChannelMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -35,12 +35,12 @@ import java.util.concurrent.ConcurrentHashMap; * @date 2021/1/25 9:25 */ @Service -public class SmsChannelServiceImpl implements SmsChannelService { +public class SysSmsChannelServiceImpl implements SysSmsChannelService { private final Map templateCode2ChannelIdMap = new ConcurrentHashMap<>(32); @Autowired - private SmsClientFactory smsClientFactory; + private SmsClientFactory clientFactory; /** * 初始化短信客户端 @@ -48,51 +48,60 @@ public class SmsChannelServiceImpl implements SmsChannelService { @PostConstruct @Override public void initSmsClient() { - List smsChannelAllVOList = listChannelAllEnabledInfo(); - if (ObjectUtil.isEmpty(smsChannelAllVOList)) { - return; - } - List channelPropertyList = SmsChannelConvert.INSTANCE.convertProperty(smsChannelAllVOList); - channelPropertyList.forEach(smsChannelProperty -> { - Long clientId = smsClientFactory.createClient(smsChannelProperty); - smsChannelProperty.getTemplateList().forEach(smsTemplateVO -> { - templateCode2ChannelIdMap.put(smsTemplateVO.getCode(), clientId); - }); + // 查询有效渠道信息 + List channelDOList = channelMapper.selectEnabledList(); + List propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList); + + // 遍历渠道生成client并获取模板缓存 + propertyList.forEach(channelProperty -> { + Long clientId = clientFactory.createClient(channelProperty); + List templateDOList = templateMapper.selectListByChannelId(channelProperty.getId()); + if (ObjectUtil.isNotEmpty(templateDOList)) { + templateDOList.forEach(template -> { + templateCode2ChannelIdMap.put(template.getCode(), clientId); + }); + SmsTemplateConvert.INSTANCE.convert(templateDOList); + } }); } - // TODO FROM 芋艿 to ZZF:channelMapper 嘿,保持命名统一。 + // TODO FROM 芋艿 to ZZF:channelMapper 嘿,保持命名统一。 DONE @Resource - private SmsChannelMapper mapper; + private SysSmsChannelMapper channelMapper; @Resource - private SmsTemplateMapper templateMapper; + private SysSmsTemplateMapper templateMapper; @Override - public PageResult pageChannels(SmsChannelPageReqVO reqVO) { - return SmsChannelConvert.INSTANCE.convertPage(mapper.selectChannelPage(reqVO)); + public PageResult pageSmsChannels(SmsChannelPageReqVO reqVO) { + return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO)); } @Override - public Long createChannel(SmsChannelCreateReqVO reqVO) { - SmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); - mapper.insert(channelDO); + public Long createSmsChannel(SmsChannelCreateReqVO reqVO) { + SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); + channelMapper.insert(channelDO); return channelDO.getId(); } @Override - public List getChannelEnums() { + public List getSmsChannelEnums() { return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); } @Override - public AbstractSmsClient getClient(String templateCode) { - return smsClientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); + public AbstractSmsClient getSmsClient(String templateCode) { + return clientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); } @Override - public List listChannelAllEnabledInfo() { - List channelDOList = mapper.selectEnabledList(); + public String getSmsTemplateApiIdByCode(String templateCode) { + return clientFactory.getTemplateApiIdByCode(templateCode); + } + + @Override + public List listSmsChannelAllEnabledInfo() { + List channelDOList = channelMapper.selectEnabledList(); if (ObjectUtil.isNull(channelDOList)) { return null; } @@ -100,7 +109,7 @@ public class SmsChannelServiceImpl implements SmsChannelService { channelAllVOList.forEach(smsChannelDO -> { - List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); + List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); if (ObjectUtil.isNull(templateDOList)) { templateDOList = new ArrayList<>(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java similarity index 60% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java index 5853463e8..7accf76db 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java @@ -3,14 +3,12 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SmsLogMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsLogDO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; import cn.iocoder.dashboard.util.json.JsonUtils; -import cn.iocoder.dashboard.util.string.StrUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -23,42 +21,41 @@ import java.util.List; * @date 2021/1/25 9:25 */ @Service -public class SmsLogServiceImpl implements SmsLogService { +public class SysSmsLogServiceImpl implements SysSmsLogService { @Resource - private SmsLogMapper smsLogMapper; + private SysSmsLogMapper logMapper; @Override - public Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync) { - SmsLogDO smsLog = new SmsLogDO(); + public Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync) { + SysSmsLogDO smsLog = new SysSmsLogDO(); if (smsBody.getSmsLogId() != null) { smsLog.setId(smsBody.getSmsLogId()); smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); - smsLogMapper.updateById(smsLog); + logMapper.updateById(smsLog); return smsBody.getSmsLogId(); } else { - SmsChannelAllVO property = client.getProperty(); - SmsTemplateVO smsTemplate = property.getTemplateByTemplateCode(smsBody.getTemplateCode()); + SmsChannelProperty property = client.getProperty(); smsLog.setChannelCode(property.getCode()) .setChannelId(property.getId()) - .setTemplateCode(smsTemplate.getCode()) + .setTemplateCode(smsBody.getTemplateCode()) .setPhones(JsonUtils.toJsonString(targetPhones)) - .setContent(StrUtils.replace(smsTemplate.getContent(), smsBody.getParams())); + .setContent(smsBody.getParams().toString()); if (isAsync) { smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); } else { smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); } - smsLogMapper.insert(smsLog); + logMapper.insert(smsLog); return smsLog.getId(); } } @Override - public void afterSendLog(Long logId, SmsResult result) { - SmsLogDO smsLog = new SmsLogDO(); + public void afterSendLog(Long logId, SmsResult result) { + SysSmsLogDO smsLog = new SysSmsLogDO(); smsLog.setId(logId); if (result.getSuccess()) { smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus()); @@ -66,7 +63,7 @@ public class SmsLogServiceImpl implements SmsLogService { smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus()); smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult())); } - smsLogMapper.updateById(smsLog); + logMapper.updateById(smsLog); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java new file mode 100644 index 000000000..eb4019fee --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -0,0 +1,54 @@ +package cn.iocoder.dashboard.modules.system.service.sms.impl; + +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信日志Service实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Service +public class SysSmsServiceImpl implements SysSmsService { + + @Resource + private SysSmsChannelService channelService; + + @Resource + private SysSmsLogService logService; + + @Resource + private SmsProducer smsProducer; + + @Override + public SmsResult send(SmsBody smsBody, List targetPhones) { + AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); + String templateApiId = channelService.getSmsTemplateApiIdByCode(smsBody.getTemplateCode()); + Long logId = logService.beforeSendLog(smsBody, targetPhones, client, false); + + SmsResult result = client.send(templateApiId, smsBody, targetPhones); + + logService.afterSendLog(logId, result); + + return result; + } + + // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。 + // 我的想法是1、很多短信,比如验证码,总还是需要知道是否发送成功的。2、别人可以不用,我们不能没有。3、实现挺简单的,个人觉得无需纠结。 + @Override + public void sendAsync(SmsBody smsBody, List targetPhones) { + AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); + logService.beforeSendLog(smsBody, targetPhones, client, true); + smsProducer.sendSmsSendMessage(smsBody, targetPhones); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java similarity index 57% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index 2826d7fca..0bf7ca1a0 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.iocoder.dashboard.modules.system.service.sms.SmsTemplateService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import org.springframework.stereotype.Service; /** @@ -10,5 +10,5 @@ import org.springframework.stereotype.Service; * @date 2021/1/25 9:25 */ @Service -public class SmsTemplateServiceImpl implements SmsTemplateService { +public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { } From 2a4d9f43eb57d78f6dbabb9956aa393644730f29 Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Wed, 24 Feb 2021 14:59:28 +0800 Subject: [PATCH 07/54] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/client/AliyunSmsClient.java | 13 ++++++++++++- .../dashboard/framework/sms/core/SmsResult.java | 2 +- .../framework/sms/core/SmsResultDetail.java | 2 +- .../sms/core/property/SmsTemplateProperty.java | 2 +- .../modules/system/enums/sms/SmsSendStatusEnum.java | 5 ++++- .../service/sms/impl/SysSmsLogServiceImpl.java | 8 ++++++++ 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index f1976589c..ef6ed73f3 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -5,6 +5,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest; @@ -85,11 +86,21 @@ public class AliyunSmsClient extends AbstractSmsClient { resultDetail.setCreateTime(DateUtil.parseDateTime(s.getSendDate())); resultDetail.setMessage(s.getContent()); resultDetail.setPhone(s.getPhoneNum()); - resultDetail.setStatus(Math.toIntExact(s.getSendStatus())); + resultDetail.setStatus(statusConvert(s.getSendStatus())); resultDetailList.add(resultDetail); }); resultBody.setResult(resultDetailList); return resultBody; } + private int statusConvert(Long aliSendStatus) { + if (aliSendStatus == 1L) { + return SmsSendStatusEnum.SUCCESS.getStatus(); + } + if (aliSendStatus == 2L) { + return SmsSendStatusEnum.FAIL.getStatus(); + } + return SmsSendStatusEnum.WAITING.getStatus(); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 64bbd1e4b..9abffa4e8 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -12,7 +12,7 @@ import java.util.List; public class SmsResult implements Serializable { /** - * 是否成功 + * 是否成功(发送短信的请求是否成功) */ // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 DONE private Boolean success; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java index 6ed9fbcae..67de28938 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -12,7 +12,7 @@ import java.util.Date; public class SmsResultDetail implements Serializable { /** - * 状态 1成功 2失败 3等待回执 + * 短信发送状态 {@link cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum} */ private Integer status; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java index a613a5453..961863cc9 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java @@ -7,7 +7,7 @@ import javax.validation.constraints.NotEmpty; /** * 渠道模板VO类 - * TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 + * TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 DONE * * * @author zzf diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java index 426e4cb80..846c70967 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java @@ -22,8 +22,11 @@ public enum SmsSendStatusEnum { //失败 FAIL(3), + //等待回执 + WAITING(4), + //成功 - SUCCESS(4); + SUCCESS(5); private final int status; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java index 7accf76db..a89f80ff7 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java @@ -59,6 +59,14 @@ public class SysSmsLogServiceImpl implements SysSmsLogService { smsLog.setId(logId); if (result.getSuccess()) { smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus()); + SysSmsLogDO smsLogDO = logMapper.selectById(logId); + result.getResult().forEach(s -> { + smsLogDO.setPhones(s.getPhone()); + smsLogDO.setSendStatus(s.getStatus()); + smsLogDO.setRemark(s.getMessage()); + smsLogDO.setCreateTime(s.getCreateTime()); + logMapper.insert(smsLogDO); + }); } else { smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus()); smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult())); From cd2a01819b98cd43bcee34db0e48d23f9d3b810a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 25 Feb 2021 01:24:06 +0800 Subject: [PATCH 08/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=20code=20review=202020?= =?UTF-8?q?-02-25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/client/AbstractSmsClient.java | 9 ++++----- .../dashboard/framework/sms/client/AliyunSmsClient.java | 6 ++---- .../dashboard/framework/sms/core/SmsClientFactory.java | 4 ++-- .../iocoder/dashboard/framework/sms/core/SmsResult.java | 2 -- .../framework/sms/core/enums/SmsChannelEnum.java | 5 +++-- .../framework/sms/core/property/SmsTemplateProperty.java | 2 -- .../system/controller/sms/SmsChannelController.java | 2 -- .../modules/system/mq/consumer/sms/SmsSendConsumer.java | 2 +- .../modules/system/service/sms/SysSmsChannelService.java | 3 --- .../service/sms/impl/SysSmsChannelServiceImpl.java | 2 +- 10 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index 14ef40d2c..b5e2dbdb9 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -22,7 +22,7 @@ public abstract class AbstractSmsClient implements SmsClient { protected final SmsChannelProperty channelVO; /** - * 构造阿里云短信发送处理 + * 构造阿里云短信发送处理 TODO FROM 芋艿 to zzf:貌似注释不对 * * @param property 阿里云短信配置 */ @@ -30,13 +30,12 @@ public abstract class AbstractSmsClient implements SmsClient { this.channelVO = property; } - public SmsChannelProperty getProperty() { return channelVO; } @Override - public SmsResult send(String templateApiId, SmsBody smsBody, Collection targets) { + public final SmsResult send(String templateApiId, SmsBody smsBody, Collection targets) { SmsResult result; try { beforeSend(templateApiId, smsBody, targets); @@ -50,13 +49,13 @@ public abstract class AbstractSmsClient implements SmsClient { return result; } - /** * 发送消息 * * @param templateApiId 短信模板唯一标识 * @param smsBody 消息内容 * @param targets 发送对象列表 + * @throws Exception 调用发送失败,抛出异常 * @return 短信发送结果 */ public abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; @@ -67,7 +66,7 @@ public abstract class AbstractSmsClient implements SmsClient { protected void afterSend(String templateApiId, SmsBody smsBody, Collection targets, SmsResult result) throws Exception { } - + // TODO FROM 芋艿 to zzf:可以考虑抽到 SmsResult 里 SmsResult failResult(String message) { SmsResult resultBody = new SmsResult(); resultBody.setSuccess(false); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index ef6ed73f3..a2cbbdfd5 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -58,16 +58,14 @@ public class AliyunSmsClient extends AbstractSmsClient { acsClient = new DefaultAcsClient(profile); } - @Override public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); - request.setPhoneNumbers(StringUtils.join(targets, ",")); + request.setPhoneNumbers(StringUtils.join(targets, ",")); // TODO FROM 芋艿 to zzf:统一使用 Hutool 工具类嘿。 request.setSignName(channelVO.getApiSignatureId()); request.setTemplateCode(templateApiId); request.setTemplateParam(smsBody.getParamsStr()); - // TODO FROM 芋艿 TO zzf:try catch 咱是不是可以交给 abstract 来做。这样,异常处理,重试,限流等等,都可以酱紫 DONE SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); boolean result = OK.equals(sendSmsResponse.getCode()); @@ -78,7 +76,7 @@ public class AliyunSmsClient extends AbstractSmsClient { resultBody.setSuccess(result); QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest(); querySendDetailsRequest.setBizId(sendSmsResponse.getBizId()); - + // TODO FROM 芋艿 to zzf:发送完之后,基于短信平台回调,去更新回执状态。短信发送是否成功,和最终用户收到,是两个维度。这块有困惑,可以微信,我给个截图哈。 QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest); List resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount())); acsResponse.getSmsSendDetailDTOs().forEach(s -> { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 4cd8e0f89..a54952701 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -42,7 +42,6 @@ public class SmsClientFactory { * @return 客户端id(默认channelId) */ public Long createClient(SmsChannelProperty propertyVO) { - // TODO FROM 芋艿 TO zzf:参数的校验,可以考虑统一使用 validation。 DONE AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO); smsSenderMap.put(propertyVO.getId(), sender); return propertyVO.getId(); @@ -77,7 +76,7 @@ public class SmsClientFactory { * 添加或修改短信模板信息缓存 */ public void addOrUpdateTemplateCache(Collection templateProperties) { - templateProperties.forEach(s -> templatePropertyMap.put(s.getCode(), s)); + templateProperties.forEach(s -> addOrUpdateTemplateCache(templateProperties)); } @@ -102,4 +101,5 @@ public class SmsClientFactory { } return smsTemplateProperty.getApiTemplateId(); } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 9abffa4e8..dbc976421 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -14,7 +14,6 @@ public class SmsResult implements Serializable { /** * 是否成功(发送短信的请求是否成功) */ - // TODO FROM 芋艿 to zzf:未来要加一个 code,将不同平台的短信失败的情况,做一次统一的收敛。 DONE private Boolean success; /** @@ -30,7 +29,6 @@ public class SmsResult implements Serializable { /** * 返回值 */ - // TODO FROM 芋艿 to zzf:是不是统一各个平台的返回结果,这样对调用方来说统一。因为作为统一的短信客户端,最好让上层不太需要知道太具体。黑河诶 DONE private List result; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 5aebdfa6d..255a705fd 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 短信渠道枚举 TODO FROM 芋艿 TO zzf:属于短信的枚举类,可以放到 framework/sms 下 DONE + * 短信渠道枚举 * * @author zzf * @date 2021/1/25 10:56 @@ -16,7 +16,7 @@ public enum SmsChannelEnum { ALI("ALI", "阿里"), HUA_WEI("HUA_WEI", "华为"), QI_NIU("QI_NIU", "七牛"), - TENCENT("TENCENT", "腾讯"); // TODO FROM 芋艿 to zzf:TEN 有后鼻音哈,要被马爸爸打了。。。 DONE + TENCENT("TENCENT", "腾讯"); private final String code; @@ -30,4 +30,5 @@ public enum SmsChannelEnum { } return null; } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java index 961863cc9..ebd3a7a95 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java @@ -7,8 +7,6 @@ import javax.validation.constraints.NotEmpty; /** * 渠道模板VO类 - * TODO FROM 芋艿 TO zzf:模板是不是不要提供到 client 里面,而是交给 factory 统一维护就好。不然,模板修改时候,刷新 client 会比较麻烦。 DONE - * * * @author zzf * @date 2021/1/25 17:03 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index f32074cbf..ddc492c23 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -37,12 +37,10 @@ public class SmsChannelController { return success(service.getSmsChannelEnums()); } - @ApiOperation("添加消息渠道") @PostMapping("/create") public CommonResult add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { return success(service.createSmsChannel(reqVO)); } - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index 53cce0bc2..61c81f54c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -24,7 +24,7 @@ public class SmsSendConsumer extends AbstractChannelMessageListener Date: Fri, 26 Feb 2021 11:30:37 +0800 Subject: [PATCH 09/54] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/client/AbstractSmsClient.java | 15 ++---- .../framework/sms/client/AliyunSmsClient.java | 4 +- .../framework/sms/core/SmsClientFactory.java | 2 +- .../framework/sms/core/SmsResult.java | 7 +++ .../convert/sms/SmsTemplateConvert.java | 3 ++ .../mq/consumer/sms/SmsSendConsumer.java | 2 +- .../service/sms/SysSmsChannelService.java | 4 +- .../sms/impl/SysSmsChannelServiceImpl.java | 51 +++++++++---------- 8 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index b5e2dbdb9..d40d636e4 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -22,9 +22,9 @@ public abstract class AbstractSmsClient implements SmsClient { protected final SmsChannelProperty channelVO; /** - * 构造阿里云短信发送处理 TODO FROM 芋艿 to zzf:貌似注释不对 + * 短信客户端有参构造函数 * - * @param property 阿里云短信配置 + * @param property 短信配置 */ public AbstractSmsClient(SmsChannelProperty property) { this.channelVO = property; @@ -44,7 +44,7 @@ public abstract class AbstractSmsClient implements SmsClient { } catch (Exception e) { // exception handle log.debug(e.getMessage(), e); - return failResult("发送异常: " + e.getMessage()); + return SmsResult.failResult("发送异常: " + e.getMessage()); } return result; } @@ -55,8 +55,8 @@ public abstract class AbstractSmsClient implements SmsClient { * @param templateApiId 短信模板唯一标识 * @param smsBody 消息内容 * @param targets 发送对象列表 - * @throws Exception 调用发送失败,抛出异常 * @return 短信发送结果 + * @throws Exception 调用发送失败,抛出异常 */ public abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; @@ -66,11 +66,4 @@ public abstract class AbstractSmsClient implements SmsClient { protected void afterSend(String templateApiId, SmsBody smsBody, Collection targets, SmsResult result) throws Exception { } - // TODO FROM 芋艿 to zzf:可以考虑抽到 SmsResult 里 - SmsResult failResult(String message) { - SmsResult resultBody = new SmsResult(); - resultBody.setSuccess(false); - resultBody.setMessage(message); - return resultBody; - } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index a2cbbdfd5..f88d6f291 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -1,6 +1,8 @@ package cn.iocoder.dashboard.framework.sms.client; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; @@ -62,7 +64,7 @@ public class AliyunSmsClient extends AbstractSmsClient { public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); - request.setPhoneNumbers(StringUtils.join(targets, ",")); // TODO FROM 芋艿 to zzf:统一使用 Hutool 工具类嘿。 + request.setPhoneNumbers(ArrayUtil.join(targets, ",")); request.setSignName(channelVO.getApiSignatureId()); request.setTemplateCode(templateApiId); request.setTemplateParam(smsBody.getParamsStr()); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index a54952701..88c02cb87 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -76,7 +76,7 @@ public class SmsClientFactory { * 添加或修改短信模板信息缓存 */ public void addOrUpdateTemplateCache(Collection templateProperties) { - templateProperties.forEach(s -> addOrUpdateTemplateCache(templateProperties)); + templateProperties.forEach(this::addOrUpdateTemplateCache); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index dbc976421..46306322d 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -31,4 +31,11 @@ public class SmsResult implements Serializable { */ private List result; + + public static SmsResult failResult(String message) { + SmsResult resultBody = new SmsResult(); + resultBody.setSuccess(false); + resultBody.setMessage(message); + return resultBody; + } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java index aaac0abdf..febac15fc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java @@ -1,6 +1,7 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; @@ -23,4 +24,6 @@ public interface SmsTemplateConvert { SmsTemplateVO convert(SysSmsTemplateDO bean); + List convertProperty(List bean); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index 61c81f54c..f5f9109e2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -24,7 +24,7 @@ public class SmsSendConsumer extends AbstractChannelMessageListener templateCode2ChannelIdMap = new ConcurrentHashMap<>(32); - @Autowired + @Resource private SmsClientFactory clientFactory; - // TODO FROM 芋艿 to zzf:方法要放在成员变量下面; - /** - * 初始化短信客户端 - */ - @PostConstruct - @Override - public void initSmsClient() { - // 查询有效渠道信息 - List channelDOList = channelMapper.selectEnabledList(); - List propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList); - - // 遍历渠道生成client并获取模板缓存 - propertyList.forEach(channelProperty -> { - Long clientId = clientFactory.createClient(channelProperty); - List templateDOList = templateMapper.selectListByChannelId(channelProperty.getId()); - if (ObjectUtil.isNotEmpty(templateDOList)) { - templateDOList.forEach(template -> { - templateCode2ChannelIdMap.put(template.getCode(), clientId); - }); - SmsTemplateConvert.INSTANCE.convert(templateDOList); - } - }); - } - @Resource private SysSmsChannelMapper channelMapper; @Resource private SysSmsTemplateMapper templateMapper; + + @PostConstruct + @Override + public void initSmsClientAndCacheSmsTemplate() { + // 查询有效渠道信息 + List channelDOList = channelMapper.selectEnabledList(); + List propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList); + + // 遍历渠道生成client、获取模板并缓存 + propertyList.forEach(channelProperty -> { + List templateDOList = templateMapper.selectListByChannelId(channelProperty.getId()); + if (ObjectUtil.isNotEmpty(templateDOList)) { + Long clientId = clientFactory.createClient(channelProperty); + templateDOList.forEach(template -> templateCode2ChannelIdMap.put(template.getCode(), clientId)); + + List templatePropertyList = SmsTemplateConvert.INSTANCE.convertProperty(templateDOList); + clientFactory.addOrUpdateTemplateCache(templatePropertyList); + } + }); + } + @Override public PageResult pageSmsChannels(SmsChannelPageReqVO reqVO) { return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO)); @@ -106,9 +105,7 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { return null; } List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); - channelAllVOList.forEach(smsChannelDO -> { - List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); if (ObjectUtil.isNull(templateDOList)) { templateDOList = new ArrayList<>(); From 767cd90279e2247e704156f7c028b0b97560f663 Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Mon, 8 Mar 2021 09:15:52 +0800 Subject: [PATCH 10/54] =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=8F=91=E9=80=81?= =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 16 ++- sql/sms.sql | 42 ++++-- .../common/enums/DefaultBitFieldEnum.java | 27 ++++ .../sms/client/AbstractSmsClient.java | 2 +- .../framework/sms/client/AliyunSmsClient.java | 37 +++-- .../sms/client/HadCallbackSmsClient.java | 25 ++++ .../client/NeedQuerySendResultSmsClient.java | 24 ++++ .../framework/sms/client/SmsClient.java | 5 + .../sms/client/YunpianSmsClient.java | 132 ++++++++++++++++++ .../dashboard/framework/sms/core/SmsBody.java | 6 +- .../framework/sms/core/SmsConstants.java | 18 +++ .../framework/sms/core/SmsResult.java | 13 +- .../framework/sms/core/SmsResultDetail.java | 4 +- .../sms/core/property/SmsChannelProperty.java | 11 ++ .../sms/SmsDefaultCallbackController.java | 27 ++++ .../mysql/dao/sms/SysSmsQueryLogMapper.java | 27 ++++ ...ogMapper.java => SysSmsSendLogMapper.java} | 4 +- .../mysql/dataobject/sms/SysSmsChannelDO.java | 10 ++ .../dataobject/sms/SysSmsQueryLogDO.java | 94 +++++++++++++ ...{SysSmsLogDO.java => SysSmsSendLogDO.java} | 27 ++-- .../system/enums/sms/SmsSendStatusEnum.java | 24 ++-- .../mq/consumer/sms/SmsSendConsumer.java | 18 ++- ...ervice.java => SysSmsQueryLogService.java} | 7 +- .../service/sms/SysSmsSendLogService.java | 13 ++ .../system/service/sms/SysSmsService.java | 69 ++------- .../sms/impl/SysSmsLogServiceImpl.java | 77 ---------- .../sms/impl/SysSmsQueryLogServiceImpl.java | 59 ++++++++ .../sms/impl/SysSmsSendLogServiceImpl.java | 109 +++++++++++++++ .../service/sms/impl/SysSmsServiceImpl.java | 28 ++-- .../dashboard/util/json/JsonUtils.java | 10 +- 30 files changed, 735 insertions(+), 230 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/{SysSmsLogMapper.java => SysSmsSendLogMapper.java} (71%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/{SysSmsLogDO.java => SysSmsSendLogDO.java} (66%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/{SysSmsLogService.java => SysSmsQueryLogService.java} (84%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java diff --git a/pom.xml b/pom.xml index 163aa1941..52c3e85dc 100644 --- a/pom.xml +++ b/pom.xml @@ -183,12 +183,6 @@ ${jjwt.version} - - org.projectlombok - lombok - ${lombok.version} - - org.mapstruct mapstruct @@ -222,17 +216,25 @@ ${easyexcel.verion} + + + + com.yunpian.sdk + yunpian-java-sdk + 1.2.7 + + com.aliyun aliyun-java-sdk-core 4.5.18 - com.aliyun aliyun-java-sdk-dysmsapi 2.1.0 + diff --git a/sql/sms.sql b/sql/sms.sql index 82d854155..027052779 100644 --- a/sql/sms.sql +++ b/sql/sms.sql @@ -12,6 +12,8 @@ CREATE TABLE `sms_channel` `code` varchar(50) NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)', `api_key` varchar(100) NOT NULL COMMENT '账号id', `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', + `had_callback` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数', + `callback_url` varchar(100) NOT NULL default '' COMMENT '回调请求路径', `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', `name` varchar(50) NOT NULL COMMENT '名称', `signature` varchar(50) NOT NULL COMMENT '签名值', @@ -60,23 +62,47 @@ CREATE TABLE `sms_template` AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板'; +-- ---------------------------- +-- Table structure for sms_query_log +-- ---------------------------- +DROP TABLE IF EXISTS `sms_query_log`; +CREATE TABLE `sms_query_log` +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `api_id` varchar(100) NOT NULL COMMENT '第三方唯一标识', + `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', + `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', + `template_code` varchar(50) NOT NULL COMMENT '渠道编码', + `phones` varchar(2000) NOT NULL COMMENT '手机号(数组json字符串)', + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `send_result_param` varchar(200) NOT NULL DEFAULT '' COMMENT '查询短信发送结果的参数', + `send_status` tinyint(1) NOT NULL DEFAULT 2 COMMENT '发送状态(0本地异步中 1发送请求失败 2发送请求成功)', + `got_result` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否获取发送结果', + `had_callback` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志'; + -- ---------------------------- -- Table structure for sms_log -- ---------------------------- -DROP TABLE IF EXISTS `sms_log`; -CREATE TABLE `sms_log` +DROP TABLE IF EXISTS `sms_send_log`; +CREATE TABLE `sms_send_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `phones` char(11) NOT NULL COMMENT '手机号(数组json字符串)', + `query_log_id` bigint(20) NOT NULL COMMENT '请求日志id', + `phone` char(11) NOT NULL COMMENT '手机号', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `remark` varchar(200) DEFAULT NULL COMMENT '备注', - `send_status` tinyint(4) NOT NULL DEFAULT 2 COMMENT '发送状态(1异步推送中 2发送中 3失败 4成功)', - `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `remark` varchar(200) DEFAULT NULL COMMENT '备注', + `success` tinyint(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + `send_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信日志'; + DEFAULT CHARSET = utf8mb4 COMMENT ='短信发送日志'; diff --git a/src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java b/src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java new file mode 100644 index 000000000..7738d40a2 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java @@ -0,0 +1,27 @@ +package cn.iocoder.dashboard.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通用状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum DefaultBitFieldEnum { + + NO(0, "否"), + YES(1, "是"); + + /** + * 状态值 + */ + private final Integer val; + /** + * 状态名 + */ + private final String name; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index d40d636e4..150b994bb 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -58,7 +58,7 @@ public abstract class AbstractSmsClient implements SmsClient { * @return 短信发送结果 * @throws Exception 调用发送失败,抛出异常 */ - public abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; + protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; protected void beforeSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java index f88d6f291..fff2d162d 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.framework.sms.client; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; @@ -14,11 +13,11 @@ import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest; import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Collection; @@ -31,7 +30,7 @@ import java.util.List; * @date 2021/1/25 14:17 */ @Slf4j -public class AliyunSmsClient extends AbstractSmsClient { +public class AliyunSmsClient extends AbstractSmsClient implements NeedQuerySendResultSmsClient { private static final String OK = "OK"; @@ -70,35 +69,43 @@ public class AliyunSmsClient extends AbstractSmsClient { request.setTemplateParam(smsBody.getParamsStr()); SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); - boolean result = OK.equals(sendSmsResponse.getCode()); - if (!result) { + boolean success = OK.equals(sendSmsResponse.getCode()); + if (!success) { log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); } - SmsResult resultBody = new SmsResult(); - resultBody.setSuccess(result); + return new SmsResult() + .setSuccess(success) + .setMessage(sendSmsResponse.getMessage()) + .setCode(sendSmsResponse.getCode()) + .setApiId(sendSmsResponse.getBizId()) + .setSendResultParam(sendSmsResponse.getBizId()); + } + + + @Override + public List getSmsSendResult(String param) throws ClientException { QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest(); - querySendDetailsRequest.setBizId(sendSmsResponse.getBizId()); - // TODO FROM 芋艿 to zzf:发送完之后,基于短信平台回调,去更新回执状态。短信发送是否成功,和最终用户收到,是两个维度。这块有困惑,可以微信,我给个截图哈。 + querySendDetailsRequest.setBizId(param); + // TODO FROM 芋艿 to zzf:发送完之后,基于短信平台回调,去更新回执状态。短信发送是否成功,和最终用户收到,是两个维度。这块有困惑,可以微信,我给个截图哈。 DONE QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest); List resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount())); acsResponse.getSmsSendDetailDTOs().forEach(s -> { SmsResultDetail resultDetail = new SmsResultDetail(); - resultDetail.setCreateTime(DateUtil.parseDateTime(s.getSendDate())); + resultDetail.setSendTime(DateUtil.parseDateTime(s.getSendDate())); resultDetail.setMessage(s.getContent()); resultDetail.setPhone(s.getPhoneNum()); - resultDetail.setStatus(statusConvert(s.getSendStatus())); + resultDetail.setSendStatus(statusConvert(s.getSendStatus())); resultDetailList.add(resultDetail); }); - resultBody.setResult(resultDetailList); - return resultBody; + return resultDetailList; } private int statusConvert(Long aliSendStatus) { if (aliSendStatus == 1L) { - return SmsSendStatusEnum.SUCCESS.getStatus(); + return SmsSendStatusEnum.SEND_SUCCESS.getStatus(); } if (aliSendStatus == 2L) { - return SmsSendStatusEnum.FAIL.getStatus(); + return SmsSendStatusEnum.SEND_FAIL.getStatus(); } return SmsSendStatusEnum.WAITING.getStatus(); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java new file mode 100644 index 000000000..1df4261d3 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java @@ -0,0 +1,25 @@ +package cn.iocoder.dashboard.framework.sms.client; + +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; + +import javax.servlet.ServletRequest; +import java.io.UnsupportedEncodingException; +import java.util.List; + +/** + * 需要发送请求获取短信发送结果的短信客户端 + * + * @author zzf + * @date 2021/3/4 17:20 + */ +public interface HadCallbackSmsClient { + + /** + * 获取短信发送结果 + * + * @param request 请求 + * @return 短信发送结果 + */ + List getSmsSendResult(ServletRequest request) throws Exception; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java new file mode 100644 index 000000000..37352235f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java @@ -0,0 +1,24 @@ +package cn.iocoder.dashboard.framework.sms.client; + +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import com.aliyuncs.exceptions.ClientException; + +import java.util.List; + +/** + * 需要发送请求获取短信发送结果的短信客户端 + * + * @author zzf + * @date 2021/3/4 17:20 + */ +public interface NeedQuerySendResultSmsClient { + + /** + * 获取短信发送结果 + * + * @param param 参数 + * @return 短信发送结果 + */ + List getSmsSendResult(String param) throws Exception; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java index 94a6de933..803e3b16f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -2,8 +2,10 @@ package cn.iocoder.dashboard.framework.sms.client; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import java.util.Collection; +import java.util.List; /** * 短信父接口 @@ -23,4 +25,7 @@ public interface SmsClient { */ SmsResult send(String templateApiId, SmsBody smsBody, Collection targets); + + //List getSmsSendResult(String jsonObjectParam); + } \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java new file mode 100644 index 000000000..77cd45f06 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java @@ -0,0 +1,132 @@ +package cn.iocoder.dashboard.framework.sms.client; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsConstants; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.util.json.JsonUtils; +import com.fasterxml.jackson.core.type.TypeReference; +import com.yunpian.sdk.YunpianClient; +import com.yunpian.sdk.constant.Code; +import com.yunpian.sdk.constant.YunpianConstant; +import com.yunpian.sdk.model.Result; +import com.yunpian.sdk.model.SmsBatchSend; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.*; + +/** + * 云片短信实现类 + * + * @author zzf + * @date 9:48 2021/3/5 + */ +@Slf4j +public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSmsClient { + + private final YunpianClient client; + + private final TypeReference>> callbackType = new TypeReference>>() { + }; + + /** + * 构造云片短信发送处理 + * + * @param channelVO 阿里云短信配置 + */ + public YunpianSmsClient(SmsChannelProperty channelVO) { + super(channelVO); + client = new YunpianClient(channelVO.getApiKey()); + } + + @Override + public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) { + Map paramMap = new HashMap<>(); + paramMap.put("apikey", getProperty().getApiKey()); + paramMap.put("mobile", String.join(SmsConstants.COMMA, targets)); + paramMap.put("text", formatContent(smsBody)); + paramMap.put("callback", getProperty().getCallbackUrl()); + + Result sendResult = client.sms().batch_send(paramMap); + boolean success = sendResult.getCode().equals(Code.OK); + + if (!success) { + log.debug("send fail[code={}, message={}]", sendResult.getCode(), sendResult.getDetail()); + } + return new SmsResult() + .setSuccess(success) + .setMessage(sendResult.getDetail()) + .setCode(sendResult.getCode().toString()) + .setApiId(sendResult.getData().getData().get(0).getSid().toString()); + } + + + /** + * 格式化短信内容,将参数注入到模板中 + * + * @param smsBody 短信信息 + * @return 格式化后的短信内容 + */ + private String formatContent(SmsBody smsBody) { + StringBuilder result = new StringBuilder(smsBody.getTemplateContent()); + smsBody.getParams().forEach((key, val) -> { + String param = parseParamToPlaceholder(key); + result.replace(result.indexOf(param), result.indexOf(param + param.length()), val); + }); + return result.toString(); + } + + /** + * 将指定参数改成对应的占位字符 + *

+ * 云片的是 #param# 的形式作为占位符 + * + * @param key 参数名 + * @return 对应的占位字符 + */ + private String parseParamToPlaceholder(String key) { + return SmsConstants.JING_HAO + key + SmsConstants.JING_HAO; + } + + + @Override + public List getSmsSendResult(ServletRequest request) throws UnsupportedEncodingException { + List> stringStringMap = getSendResult(request); + List resultDetailList = new ArrayList<>(stringStringMap.size()); + stringStringMap.forEach(map -> { + SmsResultDetail detail = new SmsResultDetail(); + + detail.setPhone(map.get("mobile")); + detail.setMessage(map.get("error_msg")); + detail.setSendTime(DateUtil.parseTime(map.get("user_receive_time"))); + String reportStatus = map.get("report_status"); + detail.setSendStatus(reportStatus.equals(SmsConstants.SUCCESS) + ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SmsSendStatusEnum.SEND_FAIL.getStatus() + ); + resultDetailList.add(detail); + }); + return resultDetailList; + } + + /** + * 从 request 中获取请求中传入的短信发送结果信息 + * + * @param request 回调请求 + * @return 短信发送结果信息 + * @throws UnsupportedEncodingException 解码异常 + */ + private List> getSendResult(ServletRequest request) throws UnsupportedEncodingException { + Map parameterMap = request.getParameterMap(); + String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); + String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); + return JsonUtils.parseByType(encode, callbackType); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java index 9b132431e..f82f0e142 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java @@ -4,7 +4,6 @@ import cn.iocoder.dashboard.util.json.JsonUtils; import lombok.Data; import java.util.Map; -import java.util.UUID; /** * 消息内容实体类 @@ -22,6 +21,11 @@ public class SmsBody { */ private String templateCode; + /** + * 模板编码 + */ + private String templateContent; + /** * 参数列表 */ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java new file mode 100644 index 000000000..e519306f3 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java @@ -0,0 +1,18 @@ +package cn.iocoder.dashboard.framework.sms.core; + +/** + * 短信相关常量类 + * + * @author zzf + * @date 2021/3/5 10:42 + */ +public interface SmsConstants { + + String OK = "OK"; + + String JING_HAO = "#"; + + String COMMA = ","; + + String SUCCESS = "SUCCESS"; +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 46306322d..694005482 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -1,14 +1,15 @@ package cn.iocoder.dashboard.framework.sms.core; import lombok.Data; +import lombok.experimental.Accessors; import java.io.Serializable; -import java.util.List; /** * 消息内容实体类 */ @Data +@Accessors(chain = true) public class SmsResult implements Serializable { /** @@ -16,6 +17,11 @@ public class SmsResult implements Serializable { */ private Boolean success; + /** + * 第三方唯一标识 + */ + private String apiId; + /** * 状态码 */ @@ -27,10 +33,9 @@ public class SmsResult implements Serializable { private String message; /** - * 返回值 + * 用于查询发送结果的参数 */ - private List result; - + private String sendResultParam; public static SmsResult failResult(String message) { SmsResult resultBody = new SmsResult(); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java index 67de28938..fcca0a0be 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -14,7 +14,7 @@ public class SmsResultDetail implements Serializable { /** * 短信发送状态 {@link cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum} */ - private Integer status; + private Integer sendStatus; /** * 接收手机号 @@ -29,5 +29,5 @@ public class SmsResultDetail implements Serializable { /** * 时间 */ - private Date createTime; + private Date sendTime; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java index 95f2a8ce7..1c7ff2305 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java @@ -54,4 +54,15 @@ public class SmsChannelProperty implements Serializable { @NotEmpty(message = "签名值不能为空") private String signature; + /** + * 是否拥有回调函数(0否 1是) + */ + @NotNull(message = "是否拥有回调函数不能为空") + private Integer hadCallback; + + /** + * 短信发送回调url + */ + private String callbackUrl; + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java new file mode 100644 index 000000000..94f0fc81d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java @@ -0,0 +1,27 @@ +package cn.iocoder.dashboard.modules.system.controller.sms; + +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.ServletRequest; + +/** + * 短信默认回调接口 + * + * @author zzf + * @date 2021/3/5 8:59 + */ +@RestController("/sms/callback") +public class SmsDefaultCallbackController { + + @Resource + private SysSmsService smsService; + + @RequestMapping("/sms-send") + public Object sendSmsCallback(ServletRequest request){ + return smsService.smsSendCallbackHandle(request); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java new file mode 100644 index 000000000..7472f481e --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java @@ -0,0 +1,27 @@ +package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; + +import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface SysSmsQueryLogMapper extends BaseMapper { + + /** + * 查询还没有获取发送结果的短信请求信息 + * + * @return + */ + default List selectNoResultQueryLogList() { + return this.selectList(new LambdaQueryWrapper() + .eq(SysSmsQueryLogDO::getSendStatus, SmsSendStatusEnum.QUERY_SUCCESS) + .eq(SysSmsQueryLogDO::getGotResult, DefaultBitFieldEnum.NO) + .eq(SysSmsQueryLogDO::getHadCallback, DefaultBitFieldEnum.NO) + ); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsSendLogMapper.java similarity index 71% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsSendLogMapper.java index cdb6df40b..eebb48fcc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsSendLogMapper.java @@ -1,10 +1,10 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsSendLogDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SysSmsLogMapper extends BaseMapper { +public interface SysSmsSendLogMapper extends BaseMapper { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java index 3e9422e79..3f212dbda 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java @@ -27,6 +27,16 @@ public class SysSmsChannelDO extends BaseDO { */ private String code; + /** + * 是否拥有回答(0否 1是) + */ + private Integer had_callback; + + /** + * 短信发送回调url + */ + private String callback_url; + /** * 渠道账号id */ diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java new file mode 100644 index 000000000..fce137d2c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java @@ -0,0 +1,94 @@ +package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 短信日志 + * + * @author zzf + * @since 2021-01-25 + */ +@Data +@EqualsAndHashCode +@Accessors(chain = true) +@TableName(value = "sms_query_log", autoResultMap = true) +public class SysSmsQueryLogDO implements Serializable { + + /** + * 自增编号 + */ + private Long id; + + /** + * 短信渠道编码(来自枚举类) + */ + private String channelCode; + + /** + * 短信渠道id + */ + private Long channelId; + + /** + * 模板id + */ + private String templateCode; + + /** + * 手机号 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List phones; + + /** + * 内容 + */ + private String content; + + /** + * 发送状态 + * + * @see cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum + */ + private Integer sendStatus; + + /** + * 是否获取过结果[0否 1是] + */ + private Integer gotResult; + + /** + * 是否拥有回调函数(0否 1是) + */ + private Integer hadCallback; + + /** + * 结果(对象json字符串) + */ + private String sendResultParam; + + /** + * 备注 + */ + private String remark; + + /** + * 创建人 + */ + private String createBy; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java similarity index 66% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java index 97ec6c02e..f85416dba 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,8 +18,8 @@ import java.util.Date; @Data @EqualsAndHashCode @Accessors(chain = true) -@TableName(value = "sms_log", autoResultMap = true) -public class SysSmsLogDO implements Serializable { +@TableName(value = "sms_send_log", autoResultMap = true) +public class SysSmsSendLogDO implements Serializable { /** * 自增编号 @@ -41,14 +42,9 @@ public class SysSmsLogDO implements Serializable { private String templateCode; /** - * 手机号(数组json字符串) + * 手机号 */ - private String phones; - - /** - * 内容 - */ - private String content; + private String phone; /** * 备注 @@ -56,18 +52,15 @@ public class SysSmsLogDO implements Serializable { private String remark; /** - * 发送状态(1异步推送中 2发送中 3失败 4成功) + * 发送状态 + * + * @see SmsSendStatusEnum */ private Integer sendStatus; /** - * 创建者 + * 发送时间 */ - private String createBy; - - /** - * 创建时间 - */ - private Date createTime; + private Date sendTime; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java index 846c70967..4e4121083 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java @@ -13,20 +13,26 @@ import lombok.Getter; @AllArgsConstructor public enum SmsSendStatusEnum { + //请求发送结果时失败 + QUERY_SEND_FAIL(-3), + + //短信发送失败 + SEND_FAIL(-2), + + //短信请求失败 + QUERY_FAIL(-1), + //异步转发中 - ASYNC(1), + ASYNC(0), - //发送中 - SENDING(2), + //请求成功 + QUERY_SUCCESS(1), - //失败 - FAIL(3), + //短信成功 + SEND_SUCCESS(2), //等待回执 - WAITING(4), - - //成功 - SUCCESS(5); + WAITING(3); private final int status; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index f5f9109e2..f962bf372 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -1,10 +1,12 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -20,12 +22,20 @@ import javax.annotation.Resource; public class SmsSendConsumer extends AbstractChannelMessageListener { @Resource - private SysSmsService sysSmsService; + private SysSmsChannelService smsChannelService; + + @Resource + private SysSmsQueryLogService smsQueryLogService; @Override public void onMessage(SmsSendMessage message) { - log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); - SmsResult send = sysSmsService.send(message.getSmsBody(), message.getTargetPhones()); + log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); + AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); + String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); + + SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhones()); + + smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java similarity index 84% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java index 431737912..7312e2355 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java @@ -7,26 +7,25 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResult; import java.util.List; /** - * 短信渠道Service接口 + * 短信请求日志服务接口 * * @author zzf * @date 2021/1/25 9:24 */ -public interface SysSmsLogService { +public interface SysSmsQueryLogService { /** * 发送短信前的日志处理 * * @param smsBody 短信内容 * @param targetPhones 发送对象手机号集合 * @param client 短信客户端 - * @param isAsync 是否异步发送 * @return 生成的日志id */ // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果. // 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。 // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 - Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync); + void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client); /** * 发送消息后的日志处理 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java new file mode 100644 index 000000000..fe6f5e973 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java @@ -0,0 +1,13 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +/** + * 短信发送日志服务接口 + * + * @author zzf + * @date 13:48 2021/3/2 + */ +public interface SysSmsSendLogService { + + void getAndSaveSmsSendLog(); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 5b403cb5e..6d851d4f6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -1,15 +1,15 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import org.apache.commons.lang3.StringUtils; +import javax.servlet.ServletRequest; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * 短信Service接口 + * 只支持异步,因此没有返回值 * * @author zzf * @date 2021/1/25 9:24 @@ -21,23 +21,17 @@ public interface SysSmsService { * * @param smsBody 消息内容 * @param targetPhones 发送对象手机号列表 - * @return 是否发送成功 */ - SmsResult send(SmsBody smsBody, List targetPhones); + void send(SmsBody smsBody, List targetPhones); /** * 发送消息 * * @param smsBody 消息内容 * @param targetPhone 发送对象手机号 - * @return 是否发送成功 */ - default SmsResult send(SmsBody smsBody, String targetPhone) { - if (StringUtils.isBlank(targetPhone)) { - return failResult("targetPhone must not null."); - } - - return send(smsBody, Collections.singletonList(targetPhone)); + default void send(SmsBody smsBody, String targetPhone) { + send(smsBody, Collections.singletonList(targetPhone)); } /** @@ -45,57 +39,16 @@ public interface SysSmsService { * * @param smsBody 消息内容 * @param targetPhones 发送对象手机号数组 - * @return 是否发送成功 */ - default SmsResult send(SmsBody smsBody, String... targetPhones) { - if (targetPhones == null) { - return failResult("targetPhones must not null."); - } - - return send(smsBody, Arrays.asList(targetPhones)); - } - - - /** - * 异步发送消息 - * - * @param msgBody 消息内容 - * @param targetPhones 发送对象列表 - */ - void sendAsync(SmsBody msgBody, List targetPhones); - - /** - * 异步发送消息 - * - * @param msgBody 消息内容 - * @param targetPhone 发送对象 - */ - default void sendAsync(SmsBody msgBody, String targetPhone) { - if (StringUtils.isBlank(targetPhone)) { - return; - } - sendAsync(msgBody, Collections.singletonList(targetPhone)); + default void send(SmsBody smsBody, String... targetPhones) { + send(smsBody, Arrays.asList(targetPhones)); } /** - * 异步发送消息 + * 处理短信发送回调函数 * - * @param msgBody 消息内容 - * @param targetPhones 发送对象列表 + * @param request 请求 + * @return 响应数据 */ - default void sendAsync(SmsBody msgBody, String... targetPhones) { - if (targetPhones == null) { - return; - } - sendAsync(msgBody, Arrays.asList(targetPhones)); - } - - - default SmsResult failResult(String message) { - SmsResult resultBody = new SmsResult(); - resultBody.setSuccess(false); - resultBody.setMessage(message); - return resultBody; - } - + Object smsSendCallbackHandle(ServletRequest request); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java deleted file mode 100644 index a89f80ff7..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.dashboard.modules.system.service.sms.impl; - -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsLogMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsLogDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; -import cn.iocoder.dashboard.util.json.JsonUtils; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 短信日志Service实现类 - * - * @author zzf - * @date 2021/1/25 9:25 - */ -@Service -public class SysSmsLogServiceImpl implements SysSmsLogService { - - @Resource - private SysSmsLogMapper logMapper; - - @Override - public Long beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client, Boolean isAsync) { - SysSmsLogDO smsLog = new SysSmsLogDO(); - if (smsBody.getSmsLogId() != null) { - smsLog.setId(smsBody.getSmsLogId()); - smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); - logMapper.updateById(smsLog); - return smsBody.getSmsLogId(); - } else { - SmsChannelProperty property = client.getProperty(); - - smsLog.setChannelCode(property.getCode()) - .setChannelId(property.getId()) - .setTemplateCode(smsBody.getTemplateCode()) - .setPhones(JsonUtils.toJsonString(targetPhones)) - .setContent(smsBody.getParams().toString()); - - if (isAsync) { - smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); - } else { - smsLog.setSendStatus(SmsSendStatusEnum.SENDING.getStatus()); - } - logMapper.insert(smsLog); - return smsLog.getId(); - } - } - - @Override - public void afterSendLog(Long logId, SmsResult result) { - SysSmsLogDO smsLog = new SysSmsLogDO(); - smsLog.setId(logId); - if (result.getSuccess()) { - smsLog.setSendStatus(SmsSendStatusEnum.SUCCESS.getStatus()); - SysSmsLogDO smsLogDO = logMapper.selectById(logId); - result.getResult().forEach(s -> { - smsLogDO.setPhones(s.getPhone()); - smsLogDO.setSendStatus(s.getStatus()); - smsLogDO.setRemark(s.getMessage()); - smsLogDO.setCreateTime(s.getCreateTime()); - logMapper.insert(smsLogDO); - }); - } else { - smsLog.setSendStatus(SmsSendStatusEnum.FAIL.getStatus()); - smsLog.setRemark(result.getMessage() + JsonUtils.toJsonString(result.getResult())); - } - logMapper.updateById(smsLog); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java new file mode 100644 index 000000000..7264f550c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -0,0 +1,59 @@ +package cn.iocoder.dashboard.modules.system.service.sms.impl; + +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +import cn.iocoder.dashboard.util.json.JsonUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信请求日志服务实现类 + * + * @author zzf + * @date 13:50 2021/3/2 + */ +@Service +public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { + + @Resource + private SysSmsQueryLogMapper logMapper; + + @Override + public void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client) { + SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); + SmsChannelProperty property = client.getProperty(); + + smsLog.setChannelCode(property.getCode()) + .setChannelId(property.getId()) + .setTemplateCode(smsBody.getTemplateCode()) + .setPhones(targetPhones) + .setContent(smsBody.getParams().toString()); + + smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); + logMapper.insert(smsLog); + smsBody.setSmsLogId(smsLog.getId()); + } + + @Override + public void afterSendLog(Long logId, SmsResult result) { + SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); + smsLog.setId(logId); + if (result.getSuccess()) { + smsLog.setSendStatus(SmsSendStatusEnum.QUERY_SUCCESS.getStatus()); + smsLog.setSendResultParam(result.getSendResultParam()); + } else { + smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); + smsLog.setRemark(result.getMessage()); + } + logMapper.updateById(smsLog); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java new file mode 100644 index 000000000..03ef5575d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -0,0 +1,109 @@ +package cn.iocoder.dashboard.modules.system.service.sms.impl; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.client.NeedQuerySendResultSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsSendLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 短信发送日志服务实现类 + * + * @author zzf + * @date 2021/1/25 9:25 + */ +@Slf4j +@Service +public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { + + @Resource + private SysSmsQueryLogMapper smsQueryLogMapper; + + @Resource + private SysSmsSendLogMapper smsSendLogMapper; + + @Resource + private SysSmsChannelService smsChannelService; + + /** + * 定时执行 {@link #getSmsSendResultJob()} 的周期 + */ + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + + + @Override + public void getAndSaveSmsSendLog() { + + List noResultQueryLogList = smsQueryLogMapper.selectNoResultQueryLogList(); + + if (CollectionUtil.isEmpty(noResultQueryLogList)) { + return; + } + //用于添加的发送日志对象 + SysSmsSendLogDO insertSendLog = new SysSmsSendLogDO(); + //用于修改状态的请求日志对象 + SysSmsQueryLogDO updateQueryLog = new SysSmsQueryLogDO(); + + noResultQueryLogList.forEach(queryLog -> { + AbstractSmsClient smsClient = smsChannelService.getSmsClient(queryLog.getTemplateCode()); + + updateQueryLog.setId(queryLog.getId()); + + // 只处理实现了获取发送结果方法的短信客户端,理论上这里都是满足条件的,以防万一加个判断。 + if (smsClient instanceof NeedQuerySendResultSmsClient) { + //初始化点字段值 + queryLog2SendLong(insertSendLog, queryLog); + + NeedQuerySendResultSmsClient querySendResultSmsClient = (NeedQuerySendResultSmsClient) smsClient; + try { + List smsSendResult = querySendResultSmsClient.getSmsSendResult(queryLog.getRemark()); + smsSendResult.forEach(resultDetail -> { + insertSendLog.setPhone(resultDetail.getPhone()); + insertSendLog.setSendStatus(resultDetail.getSendStatus()); + insertSendLog.setSendTime(resultDetail.getSendTime()); + insertSendLog.setRemark(resultDetail.getMessage()); + smsSendLogMapper.insert(insertSendLog); + }); + } catch (Exception e) { + //exception handle + log.error("query send result fail, exception: " + e.getMessage()); + + updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); + updateQueryLog.setRemark(e.getMessage()); + smsQueryLogMapper.updateById(updateQueryLog); + return; + } + } else { + //理论上这里都是满足条件的,以防万一加个判断。 + updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); + smsQueryLogMapper.updateById(updateQueryLog); + } + updateQueryLog.setSendStatus(SmsSendStatusEnum.SEND_SUCCESS.getStatus()); + updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId())); + smsQueryLogMapper.updateById(updateQueryLog); + }); + } + + private void queryLog2SendLong(SysSmsSendLogDO insertSendLog, SysSmsQueryLogDO queryLog) { + insertSendLog.setChannelCode(queryLog.getChannelCode()); + insertSendLog.setChannelId(queryLog.getChannelId()); + insertSendLog.setTemplateCode(queryLog.getTemplateCode()); + } + + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) + public void getSmsSendResultJob() { + getAndSaveSmsSendLog(); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index eb4019fee..81371e575 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -2,11 +2,11 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -25,30 +25,18 @@ public class SysSmsServiceImpl implements SysSmsService { private SysSmsChannelService channelService; @Resource - private SysSmsLogService logService; + private SysSmsQueryLogService logService; @Resource private SmsProducer smsProducer; @Override - public SmsResult send(SmsBody smsBody, List targetPhones) { + public void send(SmsBody smsBody, List targetPhones) { AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); - String templateApiId = channelService.getSmsTemplateApiIdByCode(smsBody.getTemplateCode()); - Long logId = logService.beforeSendLog(smsBody, targetPhones, client, false); - - SmsResult result = client.send(templateApiId, smsBody, targetPhones); - - logService.afterSendLog(logId, result); - - return result; - } - - // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果。 - // 我的想法是1、很多短信,比如验证码,总还是需要知道是否发送成功的。2、别人可以不用,我们不能没有。3、实现挺简单的,个人觉得无需纠结。 - @Override - public void sendAsync(SmsBody smsBody, List targetPhones) { - AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); - logService.beforeSendLog(smsBody, targetPhones, client, true); + logService.beforeSendLog(smsBody, targetPhones, client); smsProducer.sendSmsSendMessage(smsBody, targetPhones); } + + // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果. + } diff --git a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java index f6727459c..2a735e214 100644 --- a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java @@ -20,7 +20,7 @@ public class JsonUtils { /** * 初始化 objectMapper 属性 - * + *

* 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean * * @param objectMapper ObjectMapper 对象 @@ -67,4 +67,12 @@ public class JsonUtils { } } + public static T parseByType(String text, TypeReference typeReference) { + try { + return objectMapper.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } From 225664550f3cd23b4c26a9aded828cf39c2ec0eb Mon Sep 17 00:00:00 2001 From: zengzefeng <986510453@qq.com> Date: Fri, 12 Mar 2021 11:32:04 +0800 Subject: [PATCH 11/54] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E9=80=9A=E8=BF=87redis=20stream=E5=BC=82=E6=AD=A5=E5=8F=91?= =?UTF-8?q?=E9=80=81=EF=BC=8C=E5=AE=9E=E7=8E=B0=E7=9F=AD=E4=BF=A1callback?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/sms.sql | 19 +- .../dashboard/DashboardApplication.java | 30 +-- .../redis/core/util/RedisStreamUtils.java | 29 +++ .../config/SecurityConfiguration.java | 1 + .../sms/client/AbstractSmsClient.java | 18 +- .../framework/sms/client/AliyunSmsClient.java | 113 ---------- .../sms/client/HadCallbackSmsClient.java | 25 --- .../client/NeedQuerySendResultSmsClient.java | 24 -- .../framework/sms/client/SmsClient.java | 13 +- .../sms/client/impl/ali/AliyunSmsClient.java | 212 ++++++++++++++++++ .../{ => impl/yunpian}/YunpianSmsClient.java | 102 ++++++--- .../framework/sms/core/SmsClientFactory.java | 31 ++- .../framework/sms/core/SmsResult.java | 5 - .../framework/sms/core/SmsResultDetail.java | 10 + .../sms/core/enums/SmsChannelEnum.java | 2 +- .../controller/redis/RedisController.java | 136 +++++------ .../sms/SmsDefaultCallbackController.java | 32 ++- .../mysql/dao/sms/SysSmsQueryLogMapper.java | 13 +- .../mysql/dataobject/sms/SysSmsChannelDO.java | 5 - .../dataobject/sms/SysSmsQueryLogDO.java | 26 +-- .../system/dal/redis/RedisKeyConstants.java | 2 +- .../mq/consumer/sms/SmsSendConsumer.java | 41 ---- .../system/mq/message/sms/SmsSendMessage.java | 25 --- .../system/mq/producer/sms/SmsProducer.java | 32 --- .../consumer/dept/SysDeptRefreshConsumer.java | 4 +- .../dict/SysDictDataRefreshConsumer.java | 4 +- .../permission/SysMenuRefreshConsumer.java | 4 +- .../SysRoleMenuRefreshConsumer.java | 4 +- .../permission/SysRoleRefreshConsumer.java | 4 +- .../mq/consumer/sms/SmsSendConsumer.java | 56 +++++ .../message/dept/SysDeptRefreshMessage.java | 2 +- .../dict/SysDictDataRefreshMessage.java | 2 +- .../permission/SysMenuRefreshMessage.java | 2 +- .../permission/SysRoleMenuRefreshMessage.java | 2 +- .../permission/SysRoleRefreshMessage.java | 2 +- .../mq/producer/dept/SysDeptProducer.java | 4 +- .../mq/producer/dict/SysDictDataProducer.java | 4 +- .../producer/permission/SysMenuProducer.java | 4 +- .../permission/SysPermissionProducer.java | 4 +- .../producer/permission/SysRoleProducer.java | 4 +- .../redis/mq/producer/sms/SmsProducer.java | 31 +++ .../redis/stream/StreamConsumerRunner.java | 93 ++++++++ .../redis/stream/sms/SmsSendMessage.java | 16 ++ .../stream/sms/SmsSendStreamConsumer.java | 43 ++++ .../stream/sms/SmsSendStreamProducer.java | 35 +++ .../service/dept/impl/SysDeptServiceImpl.java | 2 +- .../dict/impl/SysDictDataServiceImpl.java | 2 +- .../permission/impl/SysMenuServiceImpl.java | 2 +- .../impl/SysPermissionServiceImpl.java | 2 +- .../permission/impl/SysRoleServiceImpl.java | 2 +- .../service/sms/SysSmsChannelService.java | 2 + .../service/sms/SysSmsQueryLogService.java | 10 +- .../system/service/sms/SysSmsService.java | 21 +- .../sms/impl/SysSmsQueryLogServiceImpl.java | 26 ++- .../sms/impl/SysSmsSendLogServiceImpl.java | 5 +- .../service/sms/impl/SysSmsServiceImpl.java | 25 ++- 56 files changed, 877 insertions(+), 492 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java rename src/main/java/cn/iocoder/dashboard/framework/sms/client/{ => impl/yunpian}/YunpianSmsClient.java (53%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/dept/SysDeptRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/dict/SysDictDataRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysMenuRefreshConsumer.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysRoleMenuRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/consumer/permission/SysRoleRefreshConsumer.java (81%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/dept/SysDeptRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/dict/SysDictDataRefreshMessage.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysMenuRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysRoleMenuRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/message/permission/SysRoleRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/dept/SysDeptProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/dict/SysDictDataProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysMenuProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysPermissionProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{ => redis}/mq/producer/permission/SysRoleProducer.java (79%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java diff --git a/sql/sms.sql b/sql/sms.sql index 027052779..6d9c3c8e5 100644 --- a/sql/sms.sql +++ b/sql/sms.sql @@ -12,7 +12,6 @@ CREATE TABLE `sms_channel` `code` varchar(50) NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)', `api_key` varchar(100) NOT NULL COMMENT '账号id', `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', - `had_callback` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数', `callback_url` varchar(100) NOT NULL default '' COMMENT '回调请求路径', `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', `name` varchar(50) NOT NULL COMMENT '名称', @@ -61,7 +60,7 @@ CREATE TABLE `sms_template` ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板'; - +/* -- ---------------------------- -- Table structure for sms_query_log -- ---------------------------- @@ -73,7 +72,7 @@ CREATE TABLE `sms_query_log` `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `phones` varchar(2000) NOT NULL COMMENT '手机号(数组json字符串)', + `phone` char(11) NOT NULL COMMENT '手机号', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', `send_result_param` varchar(200) NOT NULL DEFAULT '' COMMENT '查询短信发送结果的参数', `send_status` tinyint(1) NOT NULL DEFAULT 2 COMMENT '发送状态(0本地异步中 1发送请求失败 2发送请求成功)', @@ -84,24 +83,26 @@ CREATE TABLE `sms_query_log` PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志'; + DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志';*/ -- ---------------------------- -- Table structure for sms_log -- ---------------------------- -DROP TABLE IF EXISTS `sms_send_log`; -CREATE TABLE `sms_send_log` +DROP TABLE IF EXISTS `sms_query_log`; +CREATE TABLE `sms_query_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', + `api_id` varchar(100) NOT NULL COMMENT '第三方唯一标识', `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `query_log_id` bigint(20) NOT NULL COMMENT '请求日志id', `phone` char(11) NOT NULL COMMENT '手机号', `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', + `send_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '发送状态 详情见:SmsSendStatusEnum', `remark` varchar(200) DEFAULT NULL COMMENT '备注', - `success` tinyint(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', - `send_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `send_time` datetime DEFAULT NULL COMMENT '发送时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 diff --git a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java index 498bf63c7..32783aa8c 100644 --- a/src/main/java/cn/iocoder/dashboard/DashboardApplication.java +++ b/src/main/java/cn/iocoder/dashboard/DashboardApplication.java @@ -1,15 +1,15 @@ -//package cn.iocoder.dashboard; -// -//import de.codecentric.boot.admin.server.config.EnableAdminServer; -//import org.springframework.boot.SpringApplication; -//import org.springframework.boot.autoconfigure.SpringBootApplication; -// -//@SpringBootApplication -//@EnableAdminServer -//public class DashboardApplication { -// -// public static void main(String[] args) { -// SpringApplication.run(DashboardApplication.class, args); -// } -// -//} +package cn.iocoder.dashboard; + +import de.codecentric.boot.admin.server.config.EnableAdminServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableAdminServer +public class DashboardApplication { + + public static void main(String[] args) { + SpringApplication.run(DashboardApplication.class, args); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java b/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java new file mode 100644 index 000000000..590c84209 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java @@ -0,0 +1,29 @@ +package cn.iocoder.dashboard.framework.redis.core.util; + +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +import org.springframework.data.redis.connection.stream.StreamRecords; +import org.springframework.data.redis.core.RedisTemplate; + +/** + * Redis 消息工具类 + * + * @author 芋道源码 + */ +public class RedisStreamUtils { + + public static final String KEY_SMS_SEND = "stream_sms_send"; + + public static final String GROUP_SMS_SEND = "group_sms_send"; + + /** + * 发送 Redis 消息,基于 Redis pub/sub 实现 + * + * @param redisTemplate Redis 操作模板 + * @param message 消息 + */ + public static void sendChannelMessage(RedisTemplate redisTemplate, SmsSendMessage message) { + + redisTemplate.opsForStream().add(StreamRecords.newRecord().ofObject(message).withStreamKey(KEY_SMS_SEND)); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java index 2898023e2..7b853ce35 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java +++ b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java @@ -134,6 +134,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .antMatchers(webProperties.getApiPrefix() + "/system/file/get/**").anonymous() // TODO .antMatchers("/swagger-ui.html").anonymous() + .antMatchers("/**").anonymous() .antMatchers("/swagger-resources/**").anonymous() .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java index 150b994bb..fbeceea10 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java @@ -5,8 +5,6 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import lombok.extern.slf4j.Slf4j; -import java.util.Collection; - /** * 抽象短息客户端 * @@ -35,12 +33,12 @@ public abstract class AbstractSmsClient implements SmsClient { } @Override - public final SmsResult send(String templateApiId, SmsBody smsBody, Collection targets) { + public final SmsResult send(String templateApiId, SmsBody smsBody, String target) { SmsResult result; try { - beforeSend(templateApiId, smsBody, targets); - result = doSend(templateApiId, smsBody, targets); - afterSend(templateApiId, smsBody, targets, result); + beforeSend(templateApiId, smsBody, target); + result = doSend(templateApiId, smsBody, target); + afterSend(templateApiId, smsBody, target, result); } catch (Exception e) { // exception handle log.debug(e.getMessage(), e); @@ -54,16 +52,16 @@ public abstract class AbstractSmsClient implements SmsClient { * * @param templateApiId 短信模板唯一标识 * @param smsBody 消息内容 - * @param targets 发送对象列表 + * @param targetPhone 发送对象手机号 * @return 短信发送结果 * @throws Exception 调用发送失败,抛出异常 */ - protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception; + protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception; - protected void beforeSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { + protected void beforeSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { } - protected void afterSend(String templateApiId, SmsBody smsBody, Collection targets, SmsResult result) throws Exception { + protected void afterSend(String templateApiId, SmsBody smsBody, String targetPhone, SmsResult result) throws Exception { } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java deleted file mode 100644 index fff2d162d..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AliyunSmsClient.java +++ /dev/null @@ -1,113 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; -import com.aliyuncs.DefaultAcsClient; -import com.aliyuncs.IAcsClient; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; -import com.aliyuncs.exceptions.ClientException; -import com.aliyuncs.http.MethodType; -import com.aliyuncs.profile.DefaultProfile; -import com.aliyuncs.profile.IClientProfile; -import lombok.extern.slf4j.Slf4j; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * 阿里短信实现类 - * - * @author zzf - * @date 2021/1/25 14:17 - */ -@Slf4j -public class AliyunSmsClient extends AbstractSmsClient implements NeedQuerySendResultSmsClient { - - private static final String OK = "OK"; - - private static final String PRODUCT = "Dysmsapi"; - - private static final String DOMAIN = "dysmsapi.aliyuncs.com"; - - private static final String ENDPOINT = "cn-hangzhou"; - - private final IAcsClient acsClient; - - /** - * 构造阿里云短信发送处理 - * - * @param channelVO 阿里云短信配置 - */ - public AliyunSmsClient(SmsChannelProperty channelVO) { - super(channelVO); - - String accessKeyId = channelVO.getApiKey(); - String accessKeySecret = channelVO.getApiSecret(); - - IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); - DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); - - acsClient = new DefaultAcsClient(profile); - } - - @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) throws Exception { - SendSmsRequest request = new SendSmsRequest(); - request.setSysMethod(MethodType.POST); - request.setPhoneNumbers(ArrayUtil.join(targets, ",")); - request.setSignName(channelVO.getApiSignatureId()); - request.setTemplateCode(templateApiId); - request.setTemplateParam(smsBody.getParamsStr()); - SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); - - boolean success = OK.equals(sendSmsResponse.getCode()); - if (!success) { - log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); - } - return new SmsResult() - .setSuccess(success) - .setMessage(sendSmsResponse.getMessage()) - .setCode(sendSmsResponse.getCode()) - .setApiId(sendSmsResponse.getBizId()) - .setSendResultParam(sendSmsResponse.getBizId()); - } - - - @Override - public List getSmsSendResult(String param) throws ClientException { - QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest(); - querySendDetailsRequest.setBizId(param); - // TODO FROM 芋艿 to zzf:发送完之后,基于短信平台回调,去更新回执状态。短信发送是否成功,和最终用户收到,是两个维度。这块有困惑,可以微信,我给个截图哈。 DONE - QuerySendDetailsResponse acsResponse = acsClient.getAcsResponse(querySendDetailsRequest); - List resultDetailList = new ArrayList<>(Integer.parseInt(acsResponse.getTotalCount())); - acsResponse.getSmsSendDetailDTOs().forEach(s -> { - SmsResultDetail resultDetail = new SmsResultDetail(); - resultDetail.setSendTime(DateUtil.parseDateTime(s.getSendDate())); - resultDetail.setMessage(s.getContent()); - resultDetail.setPhone(s.getPhoneNum()); - resultDetail.setSendStatus(statusConvert(s.getSendStatus())); - resultDetailList.add(resultDetail); - }); - return resultDetailList; - } - - private int statusConvert(Long aliSendStatus) { - if (aliSendStatus == 1L) { - return SmsSendStatusEnum.SEND_SUCCESS.getStatus(); - } - if (aliSendStatus == 2L) { - return SmsSendStatusEnum.SEND_FAIL.getStatus(); - } - return SmsSendStatusEnum.WAITING.getStatus(); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java deleted file mode 100644 index 1df4261d3..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/HadCallbackSmsClient.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; - -import javax.servlet.ServletRequest; -import java.io.UnsupportedEncodingException; -import java.util.List; - -/** - * 需要发送请求获取短信发送结果的短信客户端 - * - * @author zzf - * @date 2021/3/4 17:20 - */ -public interface HadCallbackSmsClient { - - /** - * 获取短信发送结果 - * - * @param request 请求 - * @return 短信发送结果 - */ - List getSmsSendResult(ServletRequest request) throws Exception; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java deleted file mode 100644 index 37352235f..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/NeedQuerySendResultSmsClient.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import com.aliyuncs.exceptions.ClientException; - -import java.util.List; - -/** - * 需要发送请求获取短信发送结果的短信客户端 - * - * @author zzf - * @date 2021/3/4 17:20 - */ -public interface NeedQuerySendResultSmsClient { - - /** - * 获取短信发送结果 - * - * @param param 参数 - * @return 短信发送结果 - */ - List getSmsSendResult(String param) throws Exception; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java index 803e3b16f..b3861f159 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -4,8 +4,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import java.util.Collection; -import java.util.List; +import javax.servlet.ServletRequest; /** * 短信父接口 @@ -23,9 +22,15 @@ public interface SmsClient { * @param targets 发送对象列表 * @return 短信发送结果 */ - SmsResult send(String templateApiId, SmsBody smsBody, Collection targets); + SmsResult send(String templateApiId, SmsBody smsBody, String targets); - //List getSmsSendResult(String jsonObjectParam); + /** + * 短信发送回调请求处理 + * + * @param request 请求 + * @return 短信发送结果 + */ + SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; } \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java new file mode 100644 index 000000000..49feb8dd2 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java @@ -0,0 +1,212 @@ +package cn.iocoder.dashboard.framework.sms.client.impl.ali; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.util.json.JsonUtils; +import com.aliyuncs.DefaultAcsClient; +import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.http.MethodType; +import com.aliyuncs.profile.DefaultProfile; +import com.aliyuncs.profile.IClientProfile; +import com.fasterxml.jackson.core.type.TypeReference; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ServletRequest; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 阿里短信实现类 + * + * @author zzf + * @date 2021/1/25 14:17 + */ +@Slf4j +public class AliyunSmsClient extends AbstractSmsClient { + + private static final String OK = "OK"; + + private static final String PRODUCT = "Dystopi"; + + private static final String DOMAIN = "dysmsapi.aliyuncs.com"; + + private static final String ENDPOINT = "cn-hangzhou"; + + private final IAcsClient acsClient; + + /** + * 构造阿里云短信发送处理 + * + * @param channelVO 阿里云短信配置 + */ + public AliyunSmsClient(SmsChannelProperty channelVO) { + super(channelVO); + + String accessKeyId = channelVO.getApiKey(); + String accessKeySecret = channelVO.getApiSecret(); + + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); + DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); + + acsClient = new DefaultAcsClient(profile); + } + + @Override + public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { + SendSmsRequest request = new SendSmsRequest(); + request.setSysMethod(MethodType.POST); + request.setPhoneNumbers(targetPhone); + request.setSignName(channelVO.getApiSignatureId()); + request.setTemplateCode(templateApiId); + request.setTemplateParam(smsBody.getParamsStr()); + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); + + boolean success = OK.equals(sendSmsResponse.getCode()); + if (!success) { + log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); + } + return new SmsResult() + .setSuccess(success) + .setMessage(sendSmsResponse.getMessage()) + .setCode(sendSmsResponse.getCode()) + .setApiId(sendSmsResponse.getBizId()); + } + + /** + * [{ + * "send_time" : "2017-08-30 00:00:00", + * "report_time" : "2017-08-30 00:00:00", + * "success" : true, + * "err_msg" : "用户接收成功", + * "err_code" : "DELIVERED", + * "phone_number" : "18612345678", + * "sms_size" : "1", + * "biz_id" : "932702304080415357^0", + * "out_id" : "1184585343" + * }] + * + * @param request 请求 + * @return + * @throws Exception + */ + @Override + public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception { + BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); + String paramStr = reader.readLine(); + List> params = JsonUtils.parseByType(paramStr, new TypeReference>>() { + }); + if (CollectionUtil.isNotEmpty(params)) { + Map sendResultParamMap = params.get(0); + return CallbackHelper.of(sendResultParamMap).toResultDetail(); + } + return null; + } + + /** + * 短信发送回调辅助类 + */ + private static class CallbackHelper { + + private final Map sendResultParamMap; + + private CallbackHelper(Map sendResultParamMap) { + this.sendResultParamMap = sendResultParamMap; + } + + public static CallbackHelper of(Map sendResultParamMap) { + return new CallbackHelper(sendResultParamMap); + } + + public Integer getSendStatus() { + return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) + ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SmsSendStatusEnum.SEND_FAIL.getStatus(); + } + + public String getBizId() { + return sendResultParamMap.get(CallbackField.BIZ_ID).toString(); + } + + public String getErrMsg() { + return sendResultParamMap.get(CallbackField.ERR_MSG).toString(); + } + + public String getErrCode() { + return sendResultParamMap.get(CallbackField.ERR_CODE).toString(); + } + + public Date getSendTime() { + return DateUtil.parseTime(sendResultParamMap.get(CallbackField.SEND_TIME).toString()); + } + + public String getPhoneNumber() { + return sendResultParamMap.get(CallbackField.PHONE_NUMBER).toString(); + } + + public String getOutId() { + return sendResultParamMap.get(CallbackField.OUT_ID).toString(); + } + + public SmsResultDetail toResultDetail() { + SmsResultDetail resultDetail = new SmsResultDetail(); + resultDetail.setSendStatus(getSendStatus()); + resultDetail.setApiId(getBizId()); + resultDetail.setSendTime(getSendTime()); + resultDetail.setPhone(getPhoneNumber()); + resultDetail.setMessage(getErrMsg()); + + resultDetail.setCallbackResponseBody(generateSuccessResponseBody()); + return resultDetail; + } + + /** + * 生成回调成功的返回对象 + */ + private Map generateSuccessResponseBody() { + Map result = new HashMap<>(); + result.put("code", 0); + result.put("msg", "成功"); + return result; + } + + } + + /** + * 回调接口字段定义 + */ + private interface CallbackField { + //是否成功 boolean + String SUCCESS = "success"; + + //发送时间 + String SEND_TIME = "send_time"; + + //错误信息 + String ERR_MSG = "err_msg"; + + //错误编码 + String ERR_CODE = "err_code"; + + //手机号 + String PHONE_NUMBER = "phone_number"; + + //用户序列号 out_id + String OUT_ID = "out_id"; + + //biz_id 即 apiId 唯一标识 + String BIZ_ID = "biz_id"; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java similarity index 53% rename from src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java index 77cd45f06..72b03a45e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java @@ -1,7 +1,9 @@ -package cn.iocoder.dashboard.framework.sms.client; +package cn.iocoder.dashboard.framework.sms.client.impl.yunpian; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsResult; @@ -14,13 +16,15 @@ import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.constant.Code; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; -import com.yunpian.sdk.model.SmsBatchSend; +import com.yunpian.sdk.model.SmsSingleSend; import lombok.extern.slf4j.Slf4j; import javax.servlet.ServletRequest; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * 云片短信实现类 @@ -29,7 +33,7 @@ import java.util.*; * @date 9:48 2021/3/5 */ @Slf4j -public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSmsClient { +public class YunpianSmsClient extends AbstractSmsClient { private final YunpianClient client; @@ -47,14 +51,14 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm } @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, Collection targets) { + public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) { Map paramMap = new HashMap<>(); - paramMap.put("apikey", getProperty().getApiKey()); - paramMap.put("mobile", String.join(SmsConstants.COMMA, targets)); - paramMap.put("text", formatContent(smsBody)); - paramMap.put("callback", getProperty().getCallbackUrl()); + paramMap.put(YunpianConstant.APIKEY, getProperty().getApiKey()); + paramMap.put(YunpianConstant.MOBILE, String.join(SmsConstants.COMMA, targetPhone)); + paramMap.put(YunpianConstant.TEXT, formatContent(smsBody)); + paramMap.put(Helper.CALLBACK, getProperty().getCallbackUrl()); - Result sendResult = client.sms().batch_send(paramMap); + Result sendResult = client.sms().single_send(paramMap); boolean success = sendResult.getCode().equals(Code.OK); if (!success) { @@ -64,7 +68,7 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm .setSuccess(success) .setMessage(sendResult.getDetail()) .setCode(sendResult.getCode().toString()) - .setApiId(sendResult.getData().getData().get(0).getSid().toString()); + .setApiId(sendResult.getData().getSid().toString()); } @@ -96,26 +100,16 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm } + /** + * 云片的比较复杂,又是加密又是套娃的 + */ @Override - public List getSmsSendResult(ServletRequest request) throws UnsupportedEncodingException { - List> stringStringMap = getSendResult(request); - List resultDetailList = new ArrayList<>(stringStringMap.size()); - stringStringMap.forEach(map -> { - SmsResultDetail detail = new SmsResultDetail(); - - detail.setPhone(map.get("mobile")); - detail.setMessage(map.get("error_msg")); - detail.setSendTime(DateUtil.parseTime(map.get("user_receive_time"))); - String reportStatus = map.get("report_status"); - detail.setSendStatus(reportStatus.equals(SmsConstants.SUCCESS) - ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SmsSendStatusEnum.SEND_FAIL.getStatus() - ); - resultDetailList.add(detail); - }); - return resultDetailList; + public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws UnsupportedEncodingException { + Map map = getRequestParams(request); + return Helper.getSmsResultDetailByParam(map); } + /** * 从 request 中获取请求中传入的短信发送结果信息 * @@ -123,10 +117,58 @@ public class YunpianSmsClient extends AbstractSmsClient implements HadCallbackSm * @return 短信发送结果信息 * @throws UnsupportedEncodingException 解码异常 */ - private List> getSendResult(ServletRequest request) throws UnsupportedEncodingException { + private Map getRequestParams(ServletRequest request) throws UnsupportedEncodingException { Map parameterMap = request.getParameterMap(); String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); - return JsonUtils.parseByType(encode, callbackType); + List> paramList = JsonUtils.parseByType(encode, callbackType); + if (CollectionUtil.isNotEmpty(paramList)) { + return paramList.get(0); + } + throw new IllegalArgumentException("YunpianSmsClient getRequestParams fail! can't format RequestParam: " + + JsonUtils.toJsonString(request.getParameterMap())); + } + + /** + * 云片的回调函数的一些辅助方法 + */ + private static class Helper { + + //短信唯一标识 + private final static String API_ID = "sid"; + + //回调地址· + private final static String CALLBACK = "callback"; + + //手机号 + private final static String MOBILE = "mobile"; + + //错误信息 + private final static String ERROR_MSG = "error_msg"; + + //用户接收时间 字符串 标准格式 + private final static String USER_RECEIVE_TIME = "user_receive_time"; + + //发送状态 + private final static String REPORT_STATUS = "report_status"; + + private static int getSendStatus(Map map) { + String reportStatus = map.get(REPORT_STATUS); + return SmsConstants.SUCCESS.equals(reportStatus) + ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SmsSendStatusEnum.SEND_FAIL.getStatus(); + } + + public static SmsResultDetail getSmsResultDetailByParam(Map map) { + SmsResultDetail detail = new SmsResultDetail(); + detail.setPhone(map.get(MOBILE)); + detail.setMessage(map.get(ERROR_MSG)); + detail.setSendTime(DateUtil.parseTime(map.get(USER_RECEIVE_TIME))); + detail.setSendStatus(getSendStatus(map)); + detail.setApiId(API_ID); + + detail.setCallbackResponseBody(SmsConstants.SUCCESS); + return detail; + } } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index 88c02cb87..b4b4428ec 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -2,12 +2,15 @@ package cn.iocoder.dashboard.framework.sms.core; import cn.iocoder.dashboard.common.exception.ServiceException; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.client.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.client.impl.ali.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.client.impl.yunpian.YunpianSmsClient; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; +import cn.iocoder.dashboard.util.json.JsonUtils; import org.springframework.stereotype.Component; +import javax.servlet.ServletRequest; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -54,6 +57,8 @@ public class SmsClientFactory { switch (channelEnum) { case ALI: return new AliyunSmsClient(channelVO); + case YUN_PIAN: + return new YunpianSmsClient(channelVO); // TODO fill more channel default: break; @@ -102,4 +107,28 @@ public class SmsClientFactory { return smsTemplateProperty.getApiTemplateId(); } + + /** + * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId + * + * @param callbackRequest 短信发送回调函数请求 + * @return 第三方平台短信唯一标识 + */ + public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) { + + for (Long channelId : smsSenderMap.keySet()) { + AbstractSmsClient smsClient = smsSenderMap.get(channelId); + try { + SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest); + if (smsSendResult != null) { + return smsSendResult; + } + } catch (Exception ignored) { + } + } + throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: " + + JsonUtils.toJsonString(callbackRequest.getParameterMap())); + } + + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 694005482..228630348 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -32,11 +32,6 @@ public class SmsResult implements Serializable { */ private String message; - /** - * 用于查询发送结果的参数 - */ - private String sendResultParam; - public static SmsResult failResult(String message) { SmsResult resultBody = new SmsResult(); resultBody.setSuccess(false); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java index fcca0a0be..aab4af217 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -11,6 +11,11 @@ import java.util.Date; @Data public class SmsResultDetail implements Serializable { + /** + * 唯一标识 + */ + private String apiId; + /** * 短信发送状态 {@link cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum} */ @@ -30,4 +35,9 @@ public class SmsResultDetail implements Serializable { * 时间 */ private Date sendTime; + + /** + * 接口返回值 + */ + private Object callbackResponseBody; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 255a705fd..0265f455e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -14,8 +14,8 @@ import lombok.Getter; public enum SmsChannelEnum { ALI("ALI", "阿里"), + YUN_PIAN("YUN_PIAN", "云片"), HUA_WEI("HUA_WEI", "华为"), - QI_NIU("QI_NIU", "七牛"), TENCENT("TENCENT", "腾讯"); private final String code; diff --git a/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java index b40f95aea..d089d2ccc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/infra/controller/redis/RedisController.java @@ -1,68 +1,68 @@ -package cn.iocoder.dashboard.modules.infra.controller.redis; - -import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.common.pojo.CommonResult; -import cn.iocoder.dashboard.framework.redis.core.RedisKeyRegistry; -import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO; -import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO; -import org.springframework.data.redis.connection.RedisServerCommands; -import org.springframework.data.redis.core.RedisCallback; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.stream.Collectors; - -import static cn.iocoder.dashboard.common.pojo.CommonResult.success; - -@RestController -@RequestMapping("/infra/redis") -public class RedisController { - - @Resource - private StringRedisTemplate stringRedisTemplate; - -// @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") - @GetMapping("/get-monitor-info") - public CommonResult getRedisMonitorInfo() { - // 获得 Redis 统计信息 - Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); - Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); - Properties commandStats = stringRedisTemplate.execute(( - RedisCallback) connection -> connection.info("commandstats")); - assert commandStats != null; // 断言,避免警告 - - // 拼接结果返回 - InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize) - .commandStats(new ArrayList<>(commandStats.size())).build(); - commandStats.forEach((key, value) -> { - respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder() - .command(StrUtil.subAfter((String) key, "cmdstat_", false)) - .calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) - .usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) - .build()); - }); - return success(respVO); - } - -// @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") - @GetMapping("/get-key-list") - public CommonResult> getKeyList() { - List respVOList = RedisKeyRegistry.list().stream() - .map(define -> InfRedisKeyRespVO.builder() - .keyTemplate(define.getKeyTemplate()) - .keyType(define.getKeyType().name()) - .valueType(define.getValueType().getName()) - .timeoutType(define.getTimeoutType().getType()) - .timeout((int) define.getTimeout().getSeconds()) - .build()) - .collect(Collectors.toList()); - return success(respVOList); - } - -} +//package cn.iocoder.dashboard.modules.infra.controller.redis; +// +//import cn.hutool.core.util.StrUtil; +//import cn.iocoder.dashboard.common.pojo.CommonResult; +//import cn.iocoder.dashboard.framework.redis.core.RedisKeyRegistry; +//import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisKeyRespVO; +//import cn.iocoder.dashboard.modules.infra.controller.redis.vo.InfRedisMonitorRespVO; +//import org.springframework.data.redis.connection.RedisServerCommands; +//import org.springframework.data.redis.core.RedisCallback; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.web.bind.annotation.GetMapping; +//import org.springframework.web.bind.annotation.RequestMapping; +//import org.springframework.web.bind.annotation.RestController; +// +//import javax.annotation.Resource; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Properties; +//import java.util.stream.Collectors; +// +//import static cn.iocoder.dashboard.common.pojo.CommonResult.success; +// +//@RestController +//@RequestMapping("/infra/redis") +//public class RedisController { +// +// @Resource +// private StringRedisTemplate stringRedisTemplate; +// +//// @PreAuthorize("@ss.hasPermission('infra:redis:get-monitor-info')") +// @GetMapping("/get-monitor-info") +// public CommonResult getRedisMonitorInfo() { +// // 获得 Redis 统计信息 +// Properties info = stringRedisTemplate.execute((RedisCallback) RedisServerCommands::info); +// Long dbSize = stringRedisTemplate.execute(RedisServerCommands::dbSize); +// Properties commandStats = stringRedisTemplate.execute(( +// RedisCallback) connection -> connection.info("commandstats")); +// assert commandStats != null; // 断言,避免警告 +// +// // 拼接结果返回 +// InfRedisMonitorRespVO respVO = InfRedisMonitorRespVO.builder().info(info).dbSize(dbSize) +// .commandStats(new ArrayList<>(commandStats.size())).build(); +// commandStats.forEach((key, value) -> { +// respVO.getCommandStats().add(InfRedisMonitorRespVO.CommandStat.builder() +// .command(StrUtil.subAfter((String) key, "cmdstat_", false)) +// .calls(Integer.valueOf(StrUtil.subBetween((String) value, "calls=", ","))) +// .usec(Integer.valueOf(StrUtil.subBetween((String) value, "usec=", ","))) +// .build()); +// }); +// return success(respVO); +// } +// +//// @PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')") +// @GetMapping("/get-key-list") +// public CommonResult> getKeyList() { +// List respVOList = RedisKeyRegistry.list().stream() +// .map(define -> InfRedisKeyRespVO.builder() +// .keyTemplate(define.getKeyTemplate()) +// .keyType(define.getKeyType().name()) +// .valueType(define.getValueType().getName()) +// .timeoutType(define.getTimeoutType().getType()) +// .timeout((int) define.getTimeout().getSeconds()) +// .build()) +// .collect(Collectors.toList()); +// return success(respVOList); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java index 94f0fc81d..0a33e8b0e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java @@ -1,11 +1,19 @@ package cn.iocoder.dashboard.modules.system.controller.sms; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.ServletRequest; +import java.util.Arrays; +import java.util.Map; /** * 短信默认回调接口 @@ -13,15 +21,33 @@ import javax.servlet.ServletRequest; * @author zzf * @date 2021/3/5 8:59 */ -@RestController("/sms/callback") +@Api(tags = "短信回调api") +@RestController +@RequestMapping("/sms/callback") public class SmsDefaultCallbackController { @Resource private SysSmsService smsService; - @RequestMapping("/sms-send") - public Object sendSmsCallback(ServletRequest request){ + + @ApiOperation(value = "短信发送回调接口") + @PostMapping("/sms-send") + public Object sendSmsCallback(ServletRequest request) { return smsService.smsSendCallbackHandle(request); } +/* + @Resource + private SmsSendStreamProducer smsSendStreamProducer; + + @ApiOperation("redis stream测试") + @GetMapping("/test/redis/stream") + public void test() { + SmsBody smsBody = new SmsBody(); + smsBody.setSmsLogId(1L); + smsBody.setTemplateCode("sdf"); + smsBody.setTemplateContent("sdf"); + smsSendStreamProducer.sendSmsSendMessage(smsBody, "18216466755"); + }*/ + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java index 7472f481e..535afa667 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SysSmsQueryLogMapper.java @@ -14,14 +14,21 @@ public interface SysSmsQueryLogMapper extends BaseMapper { /** * 查询还没有获取发送结果的短信请求信息 - * - * @return */ default List selectNoResultQueryLogList() { return this.selectList(new LambdaQueryWrapper() .eq(SysSmsQueryLogDO::getSendStatus, SmsSendStatusEnum.QUERY_SUCCESS) .eq(SysSmsQueryLogDO::getGotResult, DefaultBitFieldEnum.NO) - .eq(SysSmsQueryLogDO::getHadCallback, DefaultBitFieldEnum.NO) ); } + + + /** + * 根据APIId修改对象 + */ + default boolean updateByApiId(SysSmsQueryLogDO queryLogDO, String apiId) { + return update(queryLogDO, new LambdaQueryWrapper() + .eq(SysSmsQueryLogDO::getApiId, apiId) + ) > 0; + } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java index 3f212dbda..d38c1bc07 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java @@ -27,11 +27,6 @@ public class SysSmsChannelDO extends BaseDO { */ private String code; - /** - * 是否拥有回答(0否 1是) - */ - private Integer had_callback; - /** * 短信发送回调url */ diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java index fce137d2c..ebb170ded 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java @@ -1,15 +1,12 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; import java.util.Date; -import java.util.List; /** * 短信日志 @@ -28,6 +25,11 @@ public class SysSmsQueryLogDO implements Serializable { */ private Long id; + /** + * 第三方唯一标识 + */ + private String apiId; + /** * 短信渠道编码(来自枚举类) */ @@ -46,8 +48,7 @@ public class SysSmsQueryLogDO implements Serializable { /** * 手机号 */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List phones; + private String phone; /** * 内容 @@ -66,16 +67,6 @@ public class SysSmsQueryLogDO implements Serializable { */ private Integer gotResult; - /** - * 是否拥有回调函数(0否 1是) - */ - private Integer hadCallback; - - /** - * 结果(对象json字符串) - */ - private String sendResultParam; - /** * 备注 */ @@ -91,4 +82,9 @@ public class SysSmsQueryLogDO implements Serializable { */ private Date createTime; + /** + * 发送时间 + */ + private Date sendTime; + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java index c5ca44578..20f5aba32 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/redis/RedisKeyConstants.java @@ -28,6 +28,6 @@ public interface RedisKeyConstants { * key 的 format 的参数是 uuid */ RedisKeyDefine CAPTCHA_CODE = new RedisKeyDefine("captcha_code:%s", STRING, String.class, - RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); + Duration.ofMinutes(30)); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java deleted file mode 100644 index f962bf372..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.sms; - -import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; -import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 针对 {@link SysDeptRefreshMessage} 的消费者 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class SmsSendConsumer extends AbstractChannelMessageListener { - - @Resource - private SysSmsChannelService smsChannelService; - - @Resource - private SysSmsQueryLogService smsQueryLogService; - - @Override - public void onMessage(SmsSendMessage message) { - log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); - AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); - String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); - - SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhones()); - - smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java deleted file mode 100644 index 8ca1207fa..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SmsSendMessage.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.message.sms; - -import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import lombok.Data; - -import java.util.Collection; -import java.util.List; - -/** - * 部门数据刷新 Message - */ -@Data -public class SmsSendMessage implements ChannelMessage { - - private SmsBody smsBody; - - private List targetPhones; - - @Override - public String getChannel() { - return "sms.send"; - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java deleted file mode 100644 index c758a4a15..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsProducer.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.sms; - -import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.modules.system.mq.message.sms.SmsSendMessage; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.List; - -/** - * 短信的 Producer - */ -@Component -public class SmsProducer { - - @Resource - private StringRedisTemplate stringRedisTemplate; - - /** - * 发送 {@link SmsSendMessage} 消息 - */ - public void sendSmsSendMessage(SmsBody smsBody, List targetPhoneList) { - SmsSendMessage message = new SmsSendMessage(); - message.setSmsBody(smsBody); - message.setTargetPhones(targetPhoneList); - // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 - RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java index e6fa5a98d..7e4852dff 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java index 12bf134a3..87c898984 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java index 36152424c..5f4442769 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java index 6927e1464..60861ba58 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java index a5e77f7e5..0a71fca7e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java new file mode 100644 index 000000000..db8d727ad --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java @@ -0,0 +1,56 @@ +//package cn.iocoder.dashboard.modules.system.redis.mq.consumer.sms; +// +//import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; +//import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +//import cn.iocoder.dashboard.framework.sms.core.SmsResult; +//import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; +//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.data.redis.connection.stream.Consumer; +//import org.springframework.data.redis.connection.stream.ObjectRecord; +//import org.springframework.data.redis.connection.stream.ReadOffset; +//import org.springframework.data.redis.connection.stream.StreamOffset; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.Resource; +// +///** +// * 针对 {@link SysDeptRefreshMessage} 的消费者 +// * +// * @author 芋道源码 +// */ +//@Component +//@Slf4j +//public class SmsSendConsumer extends AbstractChannelMessageListener { +// +// @Resource +// private SysSmsChannelService smsChannelService; +// +// @Resource +// private SysSmsQueryLogService smsQueryLogService; +// +// @Autowired +// StringRedisTemplate redisTemplate; +// +// @Override +// public void onMessage(SmsSendMessage message) { +// +// redisTemplate.opsForStream().add(ObjectRecord.create("String", message)); +// +// redisTemplate.opsForStream().read(Consumer.from("",""), StreamOffset.create("", ReadOffset.lastConsumed())); +// +// +// +// log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); +// AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); +// String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); +// +// SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhone()); +// smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java index a78b1250f..0c069e319 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.message.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java index 7fad277c4..2d4342423 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.message.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java index 159682a98..8f72705ee 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java index 491c9b0d2..b1c303dbe 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java index b99401021..ac46d181e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.mq.message.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java index 4ad7db4b8..3ce859fa4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.dept; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.dept; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java index 2ccfc51d2..af9daae84 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.dict; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.dict; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java index 6d664c725..9a760ad2d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java index f9eded668..67a4769a1 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java index e11945dfe..f1be4b87b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java new file mode 100644 index 000000000..3e4681715 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java @@ -0,0 +1,31 @@ +//package cn.iocoder.dashboard.modules.system.redis.mq.producer.sms; +// +//import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; +//import cn.iocoder.dashboard.framework.sms.core.SmsBody; +//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.Resource; +// +///** +// * 短信的 Producer +// */ +//@Component +//public class SmsProducer { +// +// @Resource +// private StringRedisTemplate stringRedisTemplate; +// +// /** +// * 发送 {@link SmsSendMessage} 消息 +// */ +// public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { +// SmsSendMessage message = new SmsSendMessage(); +// message.setSmsBody(smsBody); +// message.setTargetPhone(targetPhone); +// // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 +// RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); +// } +// +//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java new file mode 100644 index 000000000..7cd9d2486 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java @@ -0,0 +1,93 @@ +package cn.iocoder.dashboard.modules.system.redis.stream; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamConsumer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.stream.*; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer.StreamMessageListenerContainerOptions; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; +import org.springframework.util.ErrorHandler; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.time.Duration; + + +@Slf4j +@Component +public class StreamConsumerRunner implements ApplicationRunner, DisposableBean { + + @Resource + RedisConnectionFactory redisConnectionFactory; + + @Resource + ThreadPoolTaskExecutor threadPoolTaskExecutor; + + @Resource + SmsSendStreamConsumer streamMessageListener; + + @Resource + StringRedisTemplate stringRedisTemplate; + + private StreamMessageListenerContainer> streamMessageListenerContainer; + + @Override + public void run(ApplicationArguments args) throws UnknownHostException { + + StreamInfo.XInfoGroups groups = stringRedisTemplate.opsForStream().groups(RedisStreamUtils.KEY_SMS_SEND); + if (groups.isEmpty()) { + stringRedisTemplate.opsForStream().createGroup(RedisStreamUtils.KEY_SMS_SEND, RedisStreamUtils.GROUP_SMS_SEND); + } + + + // 创建配置对象 + StreamMessageListenerContainerOptions> streamMessageListenerContainerOptions = StreamMessageListenerContainerOptions + .builder() + // 一次性最多拉取多少条消息 + .batchSize(10) + // 执行消息轮询的执行器 + .executor(this.threadPoolTaskExecutor) + // 消息消费异常的handler + .errorHandler(new ErrorHandler() { + @Override + public void handleError(Throwable t) { + // throw new RuntimeException(t); + t.printStackTrace(); + } + }) + // 超时时间,设置为0,表示不超时(超时后会抛出异常) + .pollTimeout(Duration.ZERO) + // 序列化器 + .serializer(new StringRedisSerializer()) + .targetType(SmsSendMessage.class) + .build(); + + // 根据配置对象创建监听容器对象 + StreamMessageListenerContainer> streamMessageListenerContainer = StreamMessageListenerContainer + .create(this.redisConnectionFactory, streamMessageListenerContainerOptions); + + // 使用监听容器对象开始监听消费(使用的是手动确认方式) + streamMessageListenerContainer.receive(Consumer.from(RedisStreamUtils.GROUP_SMS_SEND, InetAddress.getLocalHost().getHostName()), + StreamOffset.create(RedisStreamUtils.KEY_SMS_SEND, ReadOffset.lastConsumed()), this.streamMessageListener); + + this.streamMessageListenerContainer = streamMessageListenerContainer; + // 启动监听 + this.streamMessageListenerContainer.start(); + + } + + @Override + public void destroy() throws Exception { + this.streamMessageListenerContainer.stop(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java new file mode 100644 index 000000000..a8aeff23f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java @@ -0,0 +1,16 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import lombok.Data; + +/** + * 部门数据刷新 Message + */ +@Data +public class SmsSendMessage { + + private SmsBody smsBody; + + private String targetPhone; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java new file mode 100644 index 000000000..0ab531b43 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java @@ -0,0 +1,43 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +import cn.iocoder.dashboard.util.json.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.stream.ObjectRecord; +import org.springframework.data.redis.stream.StreamListener; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 短信发送流消息监听器 + * + * @author zzf + * @date 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsSendStreamConsumer implements StreamListener> { + + @Resource + private SysSmsChannelService smsChannelService; + + @Resource + private SysSmsQueryLogService smsQueryLogService; + + @Override + public void onMessage(ObjectRecord record) { + SmsSendMessage message = record.getValue(); + SmsBody body = message.getSmsBody(); + log.info("[onMessage][收到 发送短信 消息], content: " + JsonUtils.toJsonString(body)); + AbstractSmsClient smsClient = smsChannelService.getSmsClient(body.getTemplateCode()); + String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(body.getTemplateCode()); + + SmsResult result = smsClient.send(templateApiId, body, message.getTargetPhone()); + smsQueryLogService.afterSendLog(body.getSmsLogId(), result); + } +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java new file mode 100644 index 000000000..069534251 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java @@ -0,0 +1,35 @@ +package cn.iocoder.dashboard.modules.system.redis.stream.sms; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; +import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 短信发送流消息监听器 + * + * @author zzf + * @date 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsSendStreamProducer { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 发送 {@link SmsSendMessage} 消息 + */ + public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { + SmsSendMessage message = new SmsSendMessage(); + message.setSmsBody(smsBody); + message.setTargetPhone(targetPhone); + + RedisStreamUtils.sendChannelMessage(stringRedisTemplate, message); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java index d3ff381ef..caa16e94b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.convert.dept.SysDeptConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dept.SysDeptMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dept.SysDeptDO; import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dept.SysDeptProducer; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java index 6e8f02388..49e5beabf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -13,7 +13,7 @@ import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict.SysDictDataMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictTypeDO; -import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; import com.google.common.collect.ImmutableTable; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java index 60a4015b5..31c0991c9 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysMenuMappe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysMenuProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.util.collection.CollectionUtils; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java index 3b3647fc4..5746357a6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysUserRoleDO; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysPermissionProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java index a40896b97..6fbb2bae8 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMappe import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.enums.permission.RoleCodeEnum; import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysRoleProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index a2ebf13b2..3ce83fe78 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -2,12 +2,14 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import javax.servlet.ServletRequest; import java.util.List; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java index 7312e2355..e5ec2fa3c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import java.util.List; @@ -16,16 +17,16 @@ public interface SysSmsQueryLogService { /** * 发送短信前的日志处理 * - * @param smsBody 短信内容 - * @param targetPhones 发送对象手机号集合 - * @param client 短信客户端 + * @param smsBody 短信内容 + * @param targetPhone 发送对象手机号 + * @param client 短信客户端 * @return 生成的日志id */ // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果. // 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。 // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 - void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client); + void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client); /** * 发送消息后的日志处理 @@ -35,4 +36,5 @@ public interface SysSmsQueryLogService { */ void afterSendLog(Long logId, SmsResult result); + void updateSendLogByResultDetail(SmsResultDetail smsResultDetail); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 6d851d4f6..93a467d62 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -1,10 +1,12 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ArrayUtil; import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import javax.servlet.ServletRequest; import java.util.Arrays; -import java.util.Collections; import java.util.List; /** @@ -22,7 +24,12 @@ public interface SysSmsService { * @param smsBody 消息内容 * @param targetPhones 发送对象手机号列表 */ - void send(SmsBody smsBody, List targetPhones); + default void send(SmsBody smsBody, List targetPhones) { + if (CollectionUtil.isEmpty(targetPhones)) { + return; + } + targetPhones.forEach(s -> this.send(smsBody, s)); + } /** * 发送消息 @@ -30,9 +37,7 @@ public interface SysSmsService { * @param smsBody 消息内容 * @param targetPhone 发送对象手机号 */ - default void send(SmsBody smsBody, String targetPhone) { - send(smsBody, Collections.singletonList(targetPhone)); - } + void send(SmsBody smsBody, String targetPhone); /** * 发送消息 @@ -41,14 +46,18 @@ public interface SysSmsService { * @param targetPhones 发送对象手机号数组 */ default void send(SmsBody smsBody, String... targetPhones) { + if (ArrayUtil.isEmpty(targetPhones)) { + return; + } send(smsBody, Arrays.asList(targetPhones)); } /** * 处理短信发送回调函数 * - * @param request 请求 + * @param request 请求 * @return 响应数据 */ Object smsSendCallbackHandle(ServletRequest request); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java index 7264f550c..a08a7bb76 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -3,16 +3,15 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import cn.iocoder.dashboard.util.json.JsonUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; /** * 短信请求日志服务实现类 @@ -27,14 +26,14 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { private SysSmsQueryLogMapper logMapper; @Override - public void beforeSendLog(SmsBody smsBody, List targetPhones, AbstractSmsClient client) { + public void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client) { SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); SmsChannelProperty property = client.getProperty(); smsLog.setChannelCode(property.getCode()) .setChannelId(property.getId()) .setTemplateCode(smsBody.getTemplateCode()) - .setPhones(targetPhones) + .setPhone(targetPhone) .setContent(smsBody.getParams().toString()); smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); @@ -46,14 +45,19 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { public void afterSendLog(Long logId, SmsResult result) { SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); smsLog.setId(logId); - if (result.getSuccess()) { - smsLog.setSendStatus(SmsSendStatusEnum.QUERY_SUCCESS.getStatus()); - smsLog.setSendResultParam(result.getSendResultParam()); - } else { - smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); - smsLog.setRemark(result.getMessage()); - } + smsLog.setApiId(result.getApiId()); + smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); + smsLog.setRemark(result.getCode() + ": " + result.getMessage()); logMapper.updateById(smsLog); } + @Override + public void updateSendLogByResultDetail(SmsResultDetail smsResultDetail) { + SysSmsQueryLogDO queryLogDO = new SysSmsQueryLogDO(); + queryLogDO.setSendStatus(smsResultDetail.getSendStatus()); + queryLogDO.setSendTime(smsResultDetail.getSendTime()); + queryLogDO.setRemark(smsResultDetail.getMessage()); + logMapper.updateByApiId(queryLogDO, smsResultDetail.getApiId()); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index 03ef5575d..c58ce5ca7 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.client.NeedQuerySendResultSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsSendLogMapper; @@ -62,7 +61,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { updateQueryLog.setId(queryLog.getId()); // 只处理实现了获取发送结果方法的短信客户端,理论上这里都是满足条件的,以防万一加个判断。 - if (smsClient instanceof NeedQuerySendResultSmsClient) { + /*if (smsClient instanceof NeedQuerySendResultSmsClient) { //初始化点字段值 queryLog2SendLong(insertSendLog, queryLog); @@ -89,7 +88,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { //理论上这里都是满足条件的,以防万一加个判断。 updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); smsQueryLogMapper.updateById(updateQueryLog); - } + }*/ updateQueryLog.setSendStatus(SmsSendStatusEnum.SEND_SUCCESS.getStatus()); updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId())); smsQueryLogMapper.updateById(updateQueryLog); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 81371e575..c679a8c81 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -2,15 +2,16 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsProducer; +import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; +import javax.servlet.ServletRequest; /** * 短信日志Service实现类 @@ -28,15 +29,23 @@ public class SysSmsServiceImpl implements SysSmsService { private SysSmsQueryLogService logService; @Resource - private SmsProducer smsProducer; + private SmsSendStreamProducer smsProducer; + + @Resource + private SmsClientFactory smsClientFactory; @Override - public void send(SmsBody smsBody, List targetPhones) { + public void send(SmsBody smsBody, String targetPhone) { AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); - logService.beforeSendLog(smsBody, targetPhones, client); - smsProducer.sendSmsSendMessage(smsBody, targetPhones); + logService.beforeSendLog(smsBody, targetPhone, client); + smsProducer.sendSmsSendMessage(smsBody, targetPhone); } - // TODO FROM 芋艿 to ZZF:可能要讨论下,对于短信发送来说,貌似只提供异步发送即可。对于业务来说,一定不能依赖短信的发送结果. + @Override + public Object smsSendCallbackHandle(ServletRequest request) { + SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); + logService.updateSendLogByResultDetail(smsResultDetail); + return smsResultDetail.getCallbackResponseBody(); + } } From 0fedc8fece4cb47a4b74fbcc47e0af759b92a10e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 14 Mar 2021 19:21:14 +0800 Subject: [PATCH 12/54] =?UTF-8?q?=E5=90=88=E5=B9=B6=20master=20=E5=88=86?= =?UTF-8?q?=E6=94=AF=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/client/SmsClient.java | 4 +- .../framework/sms/core/SmsClientFactory.java | 1 - .../controller/sms/SmsTemplateController.java | 74 +------------------ .../dict/impl/SysDictDataServiceImpl.java | 4 - .../impl/SysPermissionServiceImpl.java | 8 -- .../service/dept/SysDeptServiceTest.java | 2 +- .../service/dict/SysDictDataServiceTest.java | 2 +- 7 files changed, 6 insertions(+), 89 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java index b3861f159..ff8e6e72f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java @@ -24,7 +24,7 @@ public interface SmsClient { */ SmsResult send(String templateApiId, SmsBody smsBody, String targets); - + // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX /** * 短信发送回调请求处理 * @@ -33,4 +33,4 @@ public interface SmsClient { */ SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; -} \ No newline at end of file +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index b4b4428ec..d55c7cb99 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -115,7 +115,6 @@ public class SmsClientFactory { * @return 第三方平台短信唯一标识 */ public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) { - for (Long channelId : smsSenderMap.keySet()) { AbstractSmsClient smsClient = smsSenderMap.get(channelId); try { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java index 9fdf98440..53eefad46 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java @@ -1,84 +1,14 @@ package cn.iocoder.dashboard.modules.system.controller.sms; -import cn.iocoder.dashboard.common.enums.CommonStatusEnum; -import cn.iocoder.dashboard.common.pojo.CommonResult; -import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginReqVO; -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginRespVO; -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO; -import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO; -import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO; -import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; -import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService; -import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; -import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; -import cn.iocoder.dashboard.modules.system.service.user.SysUserService; -import cn.iocoder.dashboard.util.collection.SetUtils; import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.validation.Valid; -import java.util.List; - -import static cn.iocoder.dashboard.common.pojo.CommonResult.success; -import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId; -import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; @Api("认证 API") @RestController @RequestMapping("/sms/template") public class SmsTemplateController { - @Resource - private SysAuthService authService; - @Resource - private SysUserService userService; - @Resource - private SysRoleService roleService; - @Resource - private SysPermissionService permissionService; - @ApiOperation("使用账号密码登录") - @PostMapping("/login") - @OperateLog(enable = false) // 避免 Post 请求被记录操作日志 - public CommonResult login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { - String token = authService.login(reqVO.getUsername(), reqVO.getPassword(), reqVO.getUuid(), reqVO.getCode()); - // 返回结果 - return success(SysAuthLoginRespVO.builder().token(token).build()); - } - - @ApiOperation("获取登陆用户的权限信息") - @GetMapping("/get-permission-info") - public CommonResult getPermissionInfo() { - // 获得用户信息 - SysUserDO user = userService.getUser(getLoginUserId()); - if (user == null) { - return null; - } - // 获得角色列表 - List roleList = roleService.listRolesFromCache(getLoginUserRoleIds()); - // 获得菜单列表 - List menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(), - SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()), - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); - // 拼接结果返回 - return success(SysAuthConvert.INSTANCE.convert(user, roleList, menuList)); - } - - @ApiOperation("获得登陆用户的菜单列表") - @GetMapping("list-menus") - public CommonResult> listMenus() { - // 获得用户拥有的菜单列表 - List menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(), - SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 - // 转换成 Tree 结构返回 - return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList)); - } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java index 0bcd1ad32..c618f0e1a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -12,10 +12,6 @@ import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper; -import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.dict.SysDictDataMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictDataDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.dict.SysDictTypeDO; import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java index 78cebabbd..0b979e033 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java @@ -11,14 +11,6 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleMenuDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysUserRoleDO; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; -import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMenuMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysUserRoleMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysUserRoleDO; import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysPermissionProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java index ca0165c0f..2b70615b4 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java @@ -8,7 +8,7 @@ import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptUpdate import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysDeptMapper; import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum; -import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dept.SysDeptProducer; import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl; import cn.iocoder.dashboard.util.collection.ArrayUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java index 79c89518d..31f3b3610 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java @@ -10,7 +10,7 @@ import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataUp import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper; -import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; +import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictDataServiceImpl; import cn.iocoder.dashboard.util.collection.ArrayUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; From ee75b2e28f13fa56b4fc595aaf82208b1b3ef7c1 Mon Sep 17 00:00:00 2001 From: timfruit Date: Wed, 17 Mar 2021 23:03:11 +0800 Subject: [PATCH 13/54] =?UTF-8?q?=E5=AF=B9SysMenuServiceImpl#CreateMenu?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/SysMenuServiceTest.java | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java new file mode 100644 index 000000000..668ce9b79 --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java @@ -0,0 +1,109 @@ +package cn.iocoder.dashboard.modules.system.service.permission; + +import cn.iocoder.dashboard.BaseDbUnitTest; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysMenuMapper; +import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; +import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl; +import cn.iocoder.dashboard.util.AssertUtils; +import cn.iocoder.dashboard.util.RandomUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.MENU_PARENT_NOT_DIR_OR_MENU; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.MENU_PARENT_NOT_EXISTS; +import static cn.iocoder.dashboard.util.RandomUtils.randomLongId; +import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; +import static org.mockito.Mockito.verify; + +@Import(SysMenuServiceImpl.class) +public class SysMenuServiceTest extends BaseDbUnitTest { + + + @Resource + private SysMenuServiceImpl sysMenuService; + + @MockBean + private SysPermissionService sysPermissionService; + + @MockBean + private SysMenuProducer sysMenuProducer; + + @Resource + private SysMenuMapper menuMapper; + + + @Test + public void testCreateMenu_success() { + //构造父目录 + SysMenuDO menuDO = createParentMenuDO(MenuTypeEnum.MENU); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + //调用 + SysMenuCreateReqVO vo = createReqVO(parentId); + Long menuId = sysMenuService.createMenu(vo); + + //断言 + Assertions.assertNotNull(menuId); + // 校验记录的属性是否正确 + SysMenuDO ret = menuMapper.selectById(menuId); + AssertUtils.assertPojoEquals(vo, ret); + // 校验调用 + verify(sysMenuProducer).sendMenuRefreshMessage(); + } + + @Test + public void testCreateMenu_checkParentExist() { + Long parentId = RandomUtils.randomLongId(); + + // 调用 + SysMenuCreateReqVO vo = createReqVO(parentId); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_EXISTS); + } + + @Test + public void testCreateMenu_checkParentIsDirOrMenu() { + //构造父目录 + SysMenuDO menuDO = createParentMenuDO(MenuTypeEnum.BUTTON); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + // 调用 + SysMenuCreateReqVO vo = createReqVO(parentId); + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); + } + + + private SysMenuCreateReqVO createReqVO(Long parentId) { + SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { + o.setParentId(parentId); + o.setName("testSonName"); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + return vo; + } + + private SysMenuDO createParentMenuDO(MenuTypeEnum typeEnum) { + SysMenuDO menuDO = randomPojo(SysMenuDO.class, o -> { + o.setName("testParentName"); + o.setType(typeEnum.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + return menuDO; + } + +} From 310a436c124869617e8de77e43b6a73b1c73a597 Mon Sep 17 00:00:00 2001 From: timfruit Date: Sat, 20 Mar 2021 13:05:40 +0800 Subject: [PATCH 14/54] =?UTF-8?q?=E5=AE=8C=E6=88=90menu=E5=8D=95=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/impl/SysMenuServiceImpl.java | 4 - .../permission/SysMenuServiceTest.java | 407 ++++++++++++++++-- .../dashboard/util/AopTargetUtils.java | 63 +++ 3 files changed, 434 insertions(+), 40 deletions(-) create mode 100644 src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java index 9ed27d085..43d5fc132 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java @@ -168,10 +168,6 @@ public class SysMenuServiceImpl implements SysMenuService { */ @Transactional(rollbackFor = Exception.class) public void deleteMenu(Long menuId) { - // 校验更新的菜单是否存在 - if (menuMapper.selectById(menuId) == null) { - throw ServiceExceptionUtil.exception(MENU_NOT_EXISTS); - } // 校验是否还有子菜单 if (menuMapper.selectCountByParentId(menuId) > 0) { throw ServiceExceptionUtil.exception(MENU_EXISTS_CHILDREN); diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java index 668ce9b79..e6c861272 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java @@ -1,33 +1,38 @@ package cn.iocoder.dashboard.modules.system.service.permission; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Assert; import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuListReqVO; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysMenuMapper; import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; -import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl; +import cn.iocoder.dashboard.util.AopTargetUtils; import cn.iocoder.dashboard.util.AssertUtils; import cn.iocoder.dashboard.util.RandomUtils; +import cn.iocoder.dashboard.util.object.ObjectUtils; +import com.google.common.collect.Multimap; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.MENU_PARENT_NOT_DIR_OR_MENU; -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.MENU_PARENT_NOT_EXISTS; -import static cn.iocoder.dashboard.util.RandomUtils.randomLongId; +import java.util.*; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; @Import(SysMenuServiceImpl.class) public class SysMenuServiceTest extends BaseDbUnitTest { - @Resource private SysMenuServiceImpl sysMenuService; @@ -40,16 +45,47 @@ public class SysMenuServiceTest extends BaseDbUnitTest { @Resource private SysMenuMapper menuMapper; + @Test + public void testInitLocalCache_success() throws Exception { + SysMenuDO menuDO1 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L); + menuMapper.insert(menuDO1); + SysMenuDO menuDO2 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L); + menuMapper.insert(menuDO2); + + //调用 + sysMenuService.initLocalCache(); + + // 获取代理对象 + SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService); + + Map menuCache = (Map) BeanUtil.getFieldValue(target, "menuCache"); + Assert.isTrue(menuCache.size()==2); + AssertUtils.assertPojoEquals(menuDO1,menuCache.get(menuDO1.getId())); + AssertUtils.assertPojoEquals(menuDO2,menuCache.get(menuDO2.getId())); + + Multimap permissionMenuCache = (Multimap) BeanUtil.getFieldValue(target, "permissionMenuCache"); + Assert.isTrue(permissionMenuCache.size()==2); + AssertUtils.assertPojoEquals(menuDO1,permissionMenuCache.get(menuDO1.getPermission())); + AssertUtils.assertPojoEquals(menuDO2,permissionMenuCache.get(menuDO2.getPermission())); + + Date maxUpdateTime = (Date) BeanUtil.getFieldValue(target, "maxUpdateTime"); + assertEquals(ObjectUtils.max(menuDO1.getUpdateTime(), menuDO2.getUpdateTime()), maxUpdateTime); + } @Test public void testCreateMenu_success() { //构造父目录 - SysMenuDO menuDO = createParentMenuDO(MenuTypeEnum.MENU); + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); menuMapper.insert(menuDO); Long parentId = menuDO.getId(); //调用 - SysMenuCreateReqVO vo = createReqVO(parentId); + SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { + o.setParentId(parentId); + o.setName("testSonName"); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); Long menuId = sysMenuService.createMenu(vo); //断言 @@ -66,44 +102,343 @@ public class SysMenuServiceTest extends BaseDbUnitTest { Long parentId = RandomUtils.randomLongId(); // 调用 - SysMenuCreateReqVO vo = createReqVO(parentId); - - // 调用, 并断言异常 - AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_EXISTS); - } - - @Test - public void testCreateMenu_checkParentIsDirOrMenu() { - //构造父目录 - SysMenuDO menuDO = createParentMenuDO(MenuTypeEnum.BUTTON); - menuMapper.insert(menuDO); - Long parentId = menuDO.getId(); - - // 调用 - SysMenuCreateReqVO vo = createReqVO(parentId); - - // 调用, 并断言异常 - AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); - } - - - private SysMenuCreateReqVO createReqVO(Long parentId) { SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { o.setParentId(parentId); o.setName("testSonName"); o.setType(MenuTypeEnum.MENU.getType()); o.setStatus(RandomUtils.randomCommonStatus()); }); - return vo; + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_EXISTS); } - private SysMenuDO createParentMenuDO(MenuTypeEnum typeEnum) { - SysMenuDO menuDO = randomPojo(SysMenuDO.class, o -> { - o.setName("testParentName"); - o.setType(typeEnum.getType()); + @Test + public void testCreateMenu_checkParentTypeError() { + //构造父目录 + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + // 调用 + SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { + o.setParentId(parentId); + o.setName("testSonName"); + o.setType(MenuTypeEnum.MENU.getType()); o.setStatus(RandomUtils.randomCommonStatus()); }); - return menuDO; + + // 调用, 并断言异常 + AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); } + @Test + public void testUpdateMenu_success() { + //构造父子目录 + SysMenuDO sonMenuDO = initParentAndSonMenuDO(); + Long sonId = sonMenuDO.getId(); + Long parentId = sonMenuDO.getParentId(); + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(parentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + o.setName("pppppp"); //修改名字 + }); + sysMenuService.updateMenu(vo); + + //断言 + // 校验记录的属性是否正确 + SysMenuDO ret = menuMapper.selectById(sonId); + AssertUtils.assertPojoEquals(vo, ret); + // 校验调用 + verify(sysMenuProducer).sendMenuRefreshMessage(); + } + + @Test + public void testUpdateMenu_sonIdNotExist() { + Long sonId = 99999L; + Long parentId = 10000L; + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(parentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + //断言 + AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NOT_EXISTS); + } + + @Test + public void testUpdateMenu_canNotSetSelfToBeParent() { + //构造父子目录 + SysMenuDO sonMenuDO = initParentAndSonMenuDO(); + Long sonId = sonMenuDO.getId(); + + long updateParentId = sonId; + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(updateParentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + //断言 + AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_ERROR); + } + + @Test + public void testUpdateMenu_parentNotExist() { + //构造父子目录 + SysMenuDO sonMenuDO = initParentAndSonMenuDO(); + Long sonId = sonMenuDO.getId(); + + long updateParentId = -999999; + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(updateParentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + //断言 + AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_NOT_EXISTS); + } + + @Test + public void testUpdateMenu_parentTypeError() { + SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "son", 999L); + menuMapper.insert(sonMenuDO); + Long sonId = sonMenuDO.getId(); + + //button类型 + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(parentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + }); + //断言 + AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); + } + + @Test + public void testUpdateMenu_sonMenuNameDuplicate() { + SysMenuDO parent = createMenuDO(MenuTypeEnum.MENU, "parent", 999L); + menuMapper.insert(parent); + Long parentId = parent.getId(); + + + SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "son", parentId); + menuMapper.insert(sonMenuDO); + + SysMenuDO sonMenuDO2 = createMenuDO(MenuTypeEnum.MENU, "son2", parentId); + menuMapper.insert(sonMenuDO2); + + Long sonId = sonMenuDO.getId(); + String updateName = sonMenuDO2.getName(); + + //调用 + SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { + o.setId(sonId); + o.setParentId(parentId); + o.setType(MenuTypeEnum.MENU.getType()); + o.setStatus(RandomUtils.randomCommonStatus()); + o.setName(updateName); + }); + //断言 + AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NAME_DUPLICATE); + } + + @Test + public void testDeleteMenu_success() { + SysMenuDO sonMenuDO = initParentAndSonMenuDO(); + + Long sonId = sonMenuDO.getId(); + //调用 + sysMenuService.deleteMenu(sonId); + + //断言 + SysMenuDO menuDO = menuMapper.selectById(sonId); + Assert.isNull(menuDO); + verify(sysPermissionService).processMenuDeleted(sonId); + verify(sysMenuProducer).sendMenuRefreshMessage(); + } + + @Test + public void testDeleteMenu_menuNotExist() { + Long sonId = 99999L; + + AssertUtils.assertServiceException(() -> sysMenuService.deleteMenu(sonId), MENU_NOT_EXISTS); + } + + @Test + public void testDeleteMenu_existChildren() { + SysMenuDO sonMenu = initParentAndSonMenuDO(); + Long parentId = sonMenu.getParentId(); + + AssertUtils.assertServiceException(() -> sysMenuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN); + } + + @Test + public void testGetMenus_success() { + Map idMenuMap = new HashMap<>(); + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); + menuMapper.insert(menuDO); + idMenuMap.put(menuDO.getId(), menuDO); + + SysMenuDO sonMenu = createMenuDO(MenuTypeEnum.MENU, "son", menuDO.getId()); + menuMapper.insert(sonMenu); + idMenuMap.put(sonMenu.getId(), sonMenu); + + //调用 + List menuDOS = sysMenuService.getMenus(); + + //断言 + Assert.isTrue(menuDOS.size() == idMenuMap.size()); + for (SysMenuDO menu : menuDOS) { + AssertUtils.assertPojoEquals(idMenuMap.get(menu.getId()), menu); + } + } + + + @Test + public void testGetMenusReqVo_success() { + Map idMenuMap = new HashMap<>(); + SysMenuDO menu = createMenuDO(MenuTypeEnum.MENU, "name2", 0L, 1); + menuMapper.insert(menu); + idMenuMap.put(menu.getId(), menu); + + menu = createMenuDO(MenuTypeEnum.MENU, "11name111", 0L, 1); + menuMapper.insert(menu); + idMenuMap.put(menu.getId(), menu); + + menu = createMenuDO(MenuTypeEnum.MENU, "name", 0L, 1); + menuMapper.insert(menu); + idMenuMap.put(menu.getId(), menu); + + + menu = createMenuDO(MenuTypeEnum.MENU, "xxxxxx", 0L, 1); + menuMapper.insert(menu); + menu = createMenuDO(MenuTypeEnum.MENU, "name", 0L, 2); + menuMapper.insert(menu); + + + //调用 + SysMenuListReqVO reqVO = new SysMenuListReqVO(); + reqVO.setStatus(1); + reqVO.setName("name"); + List menuDOS = sysMenuService.getMenus(reqVO); + + //断言 + Assert.isTrue(menuDOS.size() == idMenuMap.size()); + for (SysMenuDO m : menuDOS) { + AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); + } + } + + @Test + public void testListMenusFromCache_success() throws Exception { + Map mockCacheMap = new HashMap<>(); + //获取代理对象 + SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService); + BeanUtil.setFieldValue(target, "menuCache", mockCacheMap); + + Map idMenuMap = new HashMap<>(); + SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + idMenuMap.put(menuDO.getId(), menuDO); + + menuDO = createMenuDO(2L, MenuTypeEnum.MENU, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + idMenuMap.put(menuDO.getId(), menuDO); + + + menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); + mockCacheMap.put(menuDO.getId(), menuDO); + + List menuDOS = sysMenuService.listMenusFromCache(Arrays.asList(MenuTypeEnum.MENU.getType()), Arrays.asList(1)); + Assert.isTrue(menuDOS.size() == idMenuMap.size()); + for (SysMenuDO m : menuDOS) { + AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); + } + } + + + @Test + public void testListMenusFromCache2_success() throws Exception { + Map mockCacheMap = new HashMap<>(); + //获取代理对象 + SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService); + BeanUtil.setFieldValue(target, "menuCache", mockCacheMap); + + Map idMenuMap = new HashMap<>(); + SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + idMenuMap.put(menuDO.getId(), menuDO); + + menuDO = createMenuDO(2L, MenuTypeEnum.MENU, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1); + mockCacheMap.put(menuDO.getId(), menuDO); + menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); + mockCacheMap.put(menuDO.getId(), menuDO); + + List menuDOS = sysMenuService.listMenusFromCache(Arrays.asList(1L), + Arrays.asList(MenuTypeEnum.MENU.getType()), Arrays.asList(1)); + Assert.isTrue(menuDOS.size() == idMenuMap.size()); + for (SysMenuDO m : menuDOS) { + AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); + } + } + + /** + * 构造父子目录,返回子目录 + * + * @return + */ + private SysMenuDO initParentAndSonMenuDO() { + //构造父子目录 + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "testSonName", parentId); + menuMapper.insert(sonMenuDO); + return sonMenuDO; + } + + private SysMenuDO createMenuDO(MenuTypeEnum typeEnum, String menuName, Long parentId) { + return createMenuDO(typeEnum, menuName, parentId, RandomUtils.randomCommonStatus()); + } + + private SysMenuDO createMenuDO(MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) { + return createMenuDO(null, typeEnum, menuName, parentId, status); + } + + private SysMenuDO createMenuDO(Long id, MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) { + SysMenuDO sonMenuDO = RandomUtils.randomPojo(SysMenuDO.class, o -> { + o.setId(id); + o.setParentId(parentId); + o.setType(typeEnum.getType()); + o.setStatus(status); + o.setName(menuName); + }); + return sonMenuDO; + } + + } diff --git a/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java b/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java new file mode 100644 index 000000000..376e47069 --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java @@ -0,0 +1,63 @@ +package cn.iocoder.dashboard.util; + +import org.springframework.aop.framework.AdvisedSupport; +import org.springframework.aop.framework.AopProxy; +import org.springframework.aop.support.AopUtils; + +import java.lang.reflect.Field; + +/** + * http://www.bubuko.com/infodetail-3471885.html + */ +public class AopTargetUtils { + + + /** + * 获取 目标对象 + * + * @param proxy 代理对象 + * @return + * @throws Exception + */ + public static Object getTarget(Object proxy) throws Exception { + + if (!AopUtils.isAopProxy(proxy)) { + return proxy; //不是代理对象 + } + + if (AopUtils.isJdkDynamicProxy(proxy)) { + return getJdkDynamicProxyTargetObject(proxy); + } else { //cglib + return getCglibProxyTargetObject(proxy); + } + + } + + + private static Object getCglibProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); + h.setAccessible(true); + Object dynamicAdvisedInterceptor = h.get(proxy); + + Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + + Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); + + return target; + } + + private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); + h.setAccessible(true); + AopProxy aopProxy = (AopProxy) h.get(proxy); + + Field advised = aopProxy.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + + Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget(); + + return target; + } + +} \ No newline at end of file From d2e773e84946aa445cdbd95a107e834ee633f184 Mon Sep 17 00:00:00 2001 From: timfruit Date: Sun, 21 Mar 2021 22:55:15 +0800 Subject: [PATCH 15/54] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E8=89=BF=E8=89=BF?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../permission/impl/SysMenuServiceImpl.java | 7 +- .../permission/SysMenuServiceTest.java | 226 ++++++------------ .../dashboard/util/AopTargetUtils.java | 30 +-- 3 files changed, 87 insertions(+), 176 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java index 43d5fc132..ec4ea5a9b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java @@ -15,6 +15,7 @@ import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProduce import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.util.collection.CollectionUtils; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; @@ -246,7 +247,8 @@ public class SysMenuServiceImpl implements SysMenuService { * @param parentId 父菜单编号 * @param childId 当前菜单编号 */ - private void checkParentResource(Long parentId, Long childId) { + @VisibleForTesting + public void checkParentResource(Long parentId, Long childId) { if (parentId == null || MenuIdEnum.ROOT.getId().equals(parentId)) { return; } @@ -275,7 +277,8 @@ public class SysMenuServiceImpl implements SysMenuService { * @param parentId 父菜单编号 * @param id 菜单编号 */ - private void checkResource(Long parentId, String name, Long id) { + @VisibleForTesting + public void checkResource(Long parentId, String name, Long id) { SysMenuDO menu = menuMapper.selectByParentIdAndName(parentId, name); if (menu == null) { return; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java index e6c861272..35a88e741 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java @@ -26,7 +26,9 @@ import javax.annotation.Resource; import java.util.*; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; -import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; +import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; +import static cn.iocoder.dashboard.util.RandomUtils.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.verify; @@ -59,14 +61,14 @@ public class SysMenuServiceTest extends BaseDbUnitTest { SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService); Map menuCache = (Map) BeanUtil.getFieldValue(target, "menuCache"); - Assert.isTrue(menuCache.size()==2); - AssertUtils.assertPojoEquals(menuDO1,menuCache.get(menuDO1.getId())); - AssertUtils.assertPojoEquals(menuDO2,menuCache.get(menuDO2.getId())); + Assert.isTrue(menuCache.size() == 2); + assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId())); + assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId())); Multimap permissionMenuCache = (Multimap) BeanUtil.getFieldValue(target, "permissionMenuCache"); - Assert.isTrue(permissionMenuCache.size()==2); - AssertUtils.assertPojoEquals(menuDO1,permissionMenuCache.get(menuDO1.getPermission())); - AssertUtils.assertPojoEquals(menuDO2,permissionMenuCache.get(menuDO2.getPermission())); + Assert.isTrue(permissionMenuCache.size() == 2); + assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission())); + assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission())); Date maxUpdateTime = (Date) BeanUtil.getFieldValue(target, "maxUpdateTime"); assertEquals(ObjectUtils.max(menuDO1.getUpdateTime(), menuDO2.getUpdateTime()), maxUpdateTime); @@ -92,46 +94,11 @@ public class SysMenuServiceTest extends BaseDbUnitTest { Assertions.assertNotNull(menuId); // 校验记录的属性是否正确 SysMenuDO ret = menuMapper.selectById(menuId); - AssertUtils.assertPojoEquals(vo, ret); + assertPojoEquals(vo, ret); // 校验调用 verify(sysMenuProducer).sendMenuRefreshMessage(); } - @Test - public void testCreateMenu_checkParentExist() { - Long parentId = RandomUtils.randomLongId(); - - // 调用 - SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { - o.setParentId(parentId); - o.setName("testSonName"); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - }); - - // 调用, 并断言异常 - AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_EXISTS); - } - - @Test - public void testCreateMenu_checkParentTypeError() { - //构造父目录 - SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); - menuMapper.insert(menuDO); - Long parentId = menuDO.getId(); - - // 调用 - SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> { - o.setParentId(parentId); - o.setName("testSonName"); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - }); - - // 调用, 并断言异常 - AssertUtils.assertServiceException(() -> sysMenuService.createMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); - } - @Test public void testUpdateMenu_success() { //构造父子目录 @@ -152,7 +119,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { //断言 // 校验记录的属性是否正确 SysMenuDO ret = menuMapper.selectById(sonId); - AssertUtils.assertPojoEquals(vo, ret); + assertPojoEquals(vo, ret); // 校验调用 verify(sysMenuProducer).sendMenuRefreshMessage(); } @@ -170,102 +137,14 @@ public class SysMenuServiceTest extends BaseDbUnitTest { o.setStatus(RandomUtils.randomCommonStatus()); }); //断言 - AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NOT_EXISTS); - } - - @Test - public void testUpdateMenu_canNotSetSelfToBeParent() { - //构造父子目录 - SysMenuDO sonMenuDO = initParentAndSonMenuDO(); - Long sonId = sonMenuDO.getId(); - - long updateParentId = sonId; - - //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { - o.setId(sonId); - o.setParentId(updateParentId); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - }); - //断言 - AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_ERROR); - } - - @Test - public void testUpdateMenu_parentNotExist() { - //构造父子目录 - SysMenuDO sonMenuDO = initParentAndSonMenuDO(); - Long sonId = sonMenuDO.getId(); - - long updateParentId = -999999; - - //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { - o.setId(sonId); - o.setParentId(updateParentId); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - }); - //断言 - AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_NOT_EXISTS); - } - - @Test - public void testUpdateMenu_parentTypeError() { - SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "son", 999L); - menuMapper.insert(sonMenuDO); - Long sonId = sonMenuDO.getId(); - - //button类型 - SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); - menuMapper.insert(menuDO); - Long parentId = menuDO.getId(); - - //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { - o.setId(sonId); - o.setParentId(parentId); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - }); - //断言 - AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_PARENT_NOT_DIR_OR_MENU); - } - - @Test - public void testUpdateMenu_sonMenuNameDuplicate() { - SysMenuDO parent = createMenuDO(MenuTypeEnum.MENU, "parent", 999L); - menuMapper.insert(parent); - Long parentId = parent.getId(); - - - SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "son", parentId); - menuMapper.insert(sonMenuDO); - - SysMenuDO sonMenuDO2 = createMenuDO(MenuTypeEnum.MENU, "son2", parentId); - menuMapper.insert(sonMenuDO2); - - Long sonId = sonMenuDO.getId(); - String updateName = sonMenuDO2.getName(); - - //调用 - SysMenuUpdateReqVO vo = RandomUtils.randomPojo(SysMenuUpdateReqVO.class, o -> { - o.setId(sonId); - o.setParentId(parentId); - o.setType(MenuTypeEnum.MENU.getType()); - o.setStatus(RandomUtils.randomCommonStatus()); - o.setName(updateName); - }); - //断言 - AssertUtils.assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NAME_DUPLICATE); + assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NOT_EXISTS); } @Test public void testDeleteMenu_success() { SysMenuDO sonMenuDO = initParentAndSonMenuDO(); - Long sonId = sonMenuDO.getId(); + //调用 sysMenuService.deleteMenu(sonId); @@ -280,7 +159,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { public void testDeleteMenu_menuNotExist() { Long sonId = 99999L; - AssertUtils.assertServiceException(() -> sysMenuService.deleteMenu(sonId), MENU_NOT_EXISTS); + assertServiceException(() -> sysMenuService.deleteMenu(sonId), MENU_NOT_EXISTS); } @Test @@ -288,7 +167,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { SysMenuDO sonMenu = initParentAndSonMenuDO(); Long parentId = sonMenu.getParentId(); - AssertUtils.assertServiceException(() -> sysMenuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN); + assertServiceException(() -> sysMenuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN); } @Test @@ -307,15 +186,14 @@ public class SysMenuServiceTest extends BaseDbUnitTest { //断言 Assert.isTrue(menuDOS.size() == idMenuMap.size()); - for (SysMenuDO menu : menuDOS) { - AssertUtils.assertPojoEquals(idMenuMap.get(menu.getId()), menu); - } + menuDOS.stream().forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m)); } @Test public void testGetMenusReqVo_success() { Map idMenuMap = new HashMap<>(); + //用于验证可以模糊搜索名称包含"name",状态为1的menu SysMenuDO menu = createMenuDO(MenuTypeEnum.MENU, "name2", 0L, 1); menuMapper.insert(menu); idMenuMap.put(menu.getId(), menu); @@ -328,13 +206,12 @@ public class SysMenuServiceTest extends BaseDbUnitTest { menuMapper.insert(menu); idMenuMap.put(menu.getId(), menu); - + //以下是不符合搜索条件的的menu menu = createMenuDO(MenuTypeEnum.MENU, "xxxxxx", 0L, 1); menuMapper.insert(menu); menu = createMenuDO(MenuTypeEnum.MENU, "name", 0L, 2); menuMapper.insert(menu); - //调用 SysMenuListReqVO reqVO = new SysMenuListReqVO(); reqVO.setStatus(1); @@ -343,9 +220,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { //断言 Assert.isTrue(menuDOS.size() == idMenuMap.size()); - for (SysMenuDO m : menuDOS) { - AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); - } + menuDOS.stream().forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m)); } @Test @@ -356,6 +231,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { BeanUtil.setFieldValue(target, "menuCache", mockCacheMap); Map idMenuMap = new HashMap<>(); + //用于验证搜索类型为MENU,状态为1的menu SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1); mockCacheMap.put(menuDO.getId(), menuDO); idMenuMap.put(menuDO.getId(), menuDO); @@ -364,7 +240,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { mockCacheMap.put(menuDO.getId(), menuDO); idMenuMap.put(menuDO.getId(), menuDO); - + //以下是不符合搜索条件的menu menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1); mockCacheMap.put(menuDO.getId(), menuDO); menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); @@ -372,9 +248,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest { List menuDOS = sysMenuService.listMenusFromCache(Arrays.asList(MenuTypeEnum.MENU.getType()), Arrays.asList(1)); Assert.isTrue(menuDOS.size() == idMenuMap.size()); - for (SysMenuDO m : menuDOS) { - AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); - } + menuDOS.stream().forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m)); } @@ -386,10 +260,12 @@ public class SysMenuServiceTest extends BaseDbUnitTest { BeanUtil.setFieldValue(target, "menuCache", mockCacheMap); Map idMenuMap = new HashMap<>(); + //验证搜索id为1, 类型为MENU, 状态为1 的menu SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1); mockCacheMap.put(menuDO.getId(), menuDO); idMenuMap.put(menuDO.getId(), menuDO); + //以下是不符合搜索条件的menu menuDO = createMenuDO(2L, MenuTypeEnum.MENU, "name", 0L, 1); mockCacheMap.put(menuDO.getId(), menuDO); menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1); @@ -400,9 +276,57 @@ public class SysMenuServiceTest extends BaseDbUnitTest { List menuDOS = sysMenuService.listMenusFromCache(Arrays.asList(1L), Arrays.asList(MenuTypeEnum.MENU.getType()), Arrays.asList(1)); Assert.isTrue(menuDOS.size() == idMenuMap.size()); - for (SysMenuDO m : menuDOS) { - AssertUtils.assertPojoEquals(idMenuMap.get(m.getId()), m); - } + menuDOS.stream().forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu)); + } + + @Test + public void testCheckParentResource_success() { + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + sysMenuService.checkParentResource(parentId, null); + } + + @Test + public void testCheckParentResource_canNotSetSelfToBeParent() { + assertServiceException(() -> sysMenuService.checkParentResource(1L, 1L), MENU_PARENT_ERROR); + } + + @Test + public void testCheckParentResource_parentNotExist() { + assertServiceException(() -> sysMenuService.checkParentResource(randomLongId(), null), MENU_PARENT_NOT_EXISTS); + } + + @Test + public void testCheckParentResource_parentTypeError() { + SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L); + menuMapper.insert(menuDO); + Long parentId = menuDO.getId(); + + assertServiceException(() -> sysMenuService.checkParentResource(parentId, null), MENU_PARENT_NOT_DIR_OR_MENU); + } + + @Test + public void testCheckResource_success(){ + SysMenuDO sonMenu=initParentAndSonMenuDO(); + Long parentId=sonMenu.getParentId(); + + Long otherSonMenuId=randomLongId(); + String otherSonMenuName=randomString(); + + sysMenuService.checkResource(parentId,otherSonMenuName,otherSonMenuId); + } + + @Test + public void testCheckResource_sonMenuNameDuplicate(){ + SysMenuDO sonMenu=initParentAndSonMenuDO(); + Long parentId=sonMenu.getParentId(); + + Long otherSonMenuId=randomLongId(); + String otherSonMenuName=sonMenu.getName(); //相同名称 + + assertServiceException(()->sysMenuService.checkResource(parentId,otherSonMenuName,otherSonMenuId), MENU_NAME_DUPLICATE); } /** diff --git a/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java b/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java index 376e47069..79c5d2723 100644 --- a/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java +++ b/src/test/java/cn/iocoder/dashboard/util/AopTargetUtils.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.util; +import cn.hutool.core.bean.BeanUtil; import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.AopProxy; import org.springframework.aop.support.AopUtils; @@ -11,7 +12,6 @@ import java.lang.reflect.Field; */ public class AopTargetUtils { - /** * 获取 目标对象 * @@ -20,43 +20,27 @@ public class AopTargetUtils { * @throws Exception */ public static Object getTarget(Object proxy) throws Exception { - if (!AopUtils.isAopProxy(proxy)) { return proxy; //不是代理对象 } - if (AopUtils.isJdkDynamicProxy(proxy)) { return getJdkDynamicProxyTargetObject(proxy); } else { //cglib return getCglibProxyTargetObject(proxy); } - } - private static Object getCglibProxyTargetObject(Object proxy) throws Exception { - Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); - h.setAccessible(true); - Object dynamicAdvisedInterceptor = h.get(proxy); - - Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); - advised.setAccessible(true); - - Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); - + Object dynamicAdvisedInterceptor = BeanUtil.getFieldValue(proxy, "CGLIB$CALLBACK_0"); + AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(dynamicAdvisedInterceptor, "advised"); + Object target = advisedSupport.getTargetSource().getTarget(); return target; } private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { - Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); - h.setAccessible(true); - AopProxy aopProxy = (AopProxy) h.get(proxy); - - Field advised = aopProxy.getClass().getDeclaredField("advised"); - advised.setAccessible(true); - - Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget(); - + AopProxy aopProxy = (AopProxy) BeanUtil.getFieldValue(proxy, "h"); + AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(aopProxy, "advised"); + Object target = advisedSupport.getTargetSource().getTarget(); return target; } From a13a2e7371dd83704fcb2f9dbc47fe6be8188f8c Mon Sep 17 00:00:00 2001 From: timfruit Date: Tue, 23 Mar 2021 22:40:28 +0800 Subject: [PATCH 16/54] =?UTF-8?q?=E5=AE=8C=E6=88=90role=E5=8D=95=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/enums/SysErrorCodeConstants.java | 4 +- .../permission/impl/SysRoleServiceImpl.java | 9 +- .../permission/SysRoleServiceTest.java | 308 ++++++++++++++++++ 3 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 0197b6c05..05ea09672 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -30,8 +30,8 @@ public interface SysErrorCodeConstants { // ========== 角色模块 1002003000 ========== ErrorCode ROLE_NOT_EXISTS = new ErrorCode(1002003000, "角色不存在"); - ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}}】的角色"); - ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}}】的角色"); + ErrorCode ROLE_NAME_DUPLICATE = new ErrorCode(1002003001, "已经存在名为【{}】的角色"); + ErrorCode ROLE_CODE_DUPLICATE = new ErrorCode(1002003002, "已经存在编码为【{}】的角色"); ErrorCode ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE = new ErrorCode(1002003004, "不能操作类型为系统内置的角色"); // ========== 用户模块 1002004000 ========== diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java index e79813636..a940852fc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java @@ -18,6 +18,7 @@ import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import lombok.extern.slf4j.Slf4j; import org.springframework.lang.Nullable; @@ -245,7 +246,8 @@ public class SysRoleServiceImpl implements SysRoleService { * @param code 角色额编码 * @param id 角色编号 */ - private void checkDuplicateRole(String name, String code, Long id) { + @VisibleForTesting + public void checkDuplicateRole(String name, String code, Long id) { // 1. 该 name 名字被其它角色所使用 SysRoleDO role = roleMapper.selectByName(name); if (role != null && !role.getId().equals(id)) { @@ -258,7 +260,7 @@ public class SysRoleServiceImpl implements SysRoleService { // 该 code 编码被其它角色所使用 role = roleMapper.selectByCode(code); if (role != null && !role.getId().equals(id)) { - throw ServiceExceptionUtil.exception(ROLE_CODE_DUPLICATE, name); + throw ServiceExceptionUtil.exception(ROLE_CODE_DUPLICATE, code); } } @@ -267,7 +269,8 @@ public class SysRoleServiceImpl implements SysRoleService { * * @param id 角色编号 */ - private void checkUpdateRole(Long id) { + @VisibleForTesting + public void checkUpdateRole(Long id) { SysRoleDO roleDO = roleMapper.selectById(id); if (roleDO == null) { throw ServiceExceptionUtil.exception(ROLE_NOT_EXISTS); diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java new file mode 100644 index 000000000..f180f2b92 --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleServiceTest.java @@ -0,0 +1,308 @@ +package cn.iocoder.dashboard.modules.system.service.permission; + +import cn.hutool.core.bean.BeanUtil; +import cn.iocoder.dashboard.BaseDbUnitTest; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.security.core.enums.DataScopeEnum; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRolePageReqVO; +import cn.iocoder.dashboard.modules.system.controller.permission.vo.role.SysRoleUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMapper; +import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; +import cn.iocoder.dashboard.modules.system.service.permission.impl.SysRoleServiceImpl; +import cn.iocoder.dashboard.util.AopTargetUtils; +import cn.iocoder.dashboard.util.AssertUtils; +import cn.iocoder.dashboard.util.RandomUtils; +import cn.iocoder.dashboard.util.object.ObjectUtils; +import com.google.common.collect.Sets; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; +import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; +import static cn.iocoder.dashboard.util.RandomUtils.*; +import static cn.iocoder.dashboard.util.object.ObjectUtils.max; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; + +@Import(SysRoleServiceImpl.class) +public class SysRoleServiceTest extends BaseDbUnitTest { + + @Resource + private SysRoleServiceImpl sysRoleService; + + @Resource + private SysRoleMapper roleMapper; + + @MockBean + private SysPermissionService sysPermissionService; + + @MockBean + private SysRoleProducer sysRoleProducer; + + @Test + public void testInitLocalCache_success() throws Exception { + SysRoleDO roleDO1 = createRoleDO("role1", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO1); + SysRoleDO roleDO2 = createRoleDO("role2", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO2); + + //调用 + sysRoleService.initLocalCache(); + + //断言 + //获取代理对象 + SysRoleServiceImpl target = (SysRoleServiceImpl) AopTargetUtils.getTarget(sysRoleService); + + Map roleCache = (Map) BeanUtil.getFieldValue(target, "roleCache"); + assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId())); + assertPojoEquals(roleDO2, roleCache.get(roleDO2.getId())); + + Date maxUpdateTime = (Date) BeanUtil.getFieldValue(target, "maxUpdateTime"); + assertEquals(max(roleDO1.getUpdateTime(), roleDO2.getUpdateTime()), maxUpdateTime); + } + + @Test + public void testCreateRole_success() { + SysRoleCreateReqVO reqVO = randomPojo(SysRoleCreateReqVO.class, o -> { + o.setCode("role_code"); + o.setName("role_name"); + o.setRemark("remark"); + o.setType(SysRoleTypeEnum.CUSTOM.getType()); + o.setSort(1); + }); + Long roleId = sysRoleService.createRole(reqVO); + + //断言 + assertNotNull(roleId); + SysRoleDO roleDO = roleMapper.selectById(roleId); + assertPojoEquals(reqVO, roleDO); + + verify(sysRoleProducer).sendRoleRefreshMessage(); + } + + @Test + public void testUpdateRole_success() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + //调用 + SysRoleUpdateReqVO reqVO = randomPojo(SysRoleUpdateReqVO.class, o -> { + o.setId(roleId); + o.setCode("role_code"); + o.setName("update_name"); + o.setType(SysRoleTypeEnum.SYSTEM.getType()); + o.setSort(999); + }); + sysRoleService.updateRole(reqVO); + + //断言 + SysRoleDO newRoleDO = roleMapper.selectById(roleId); + assertPojoEquals(reqVO, newRoleDO); + + verify(sysRoleProducer).sendRoleRefreshMessage(); + } + + @Test + public void testUpdateRoleStatus_success() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, CommonStatusEnum.ENABLE.getStatus()); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + //调用 + sysRoleService.updateRoleStatus(roleId, CommonStatusEnum.DISABLE.getStatus()); + + //断言 + SysRoleDO newRoleDO = roleMapper.selectById(roleId); + assertEquals(CommonStatusEnum.DISABLE.getStatus(), newRoleDO.getStatus()); + + verify(sysRoleProducer).sendRoleRefreshMessage(); + } + + @Test + public void testUpdateRoleDataScope_success() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + //调用 + Set deptIdSet = Arrays.asList(1L, 2L, 3L, 4L, 5L).stream().collect(Collectors.toSet()); + sysRoleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScore(), deptIdSet); + + //断言 + SysRoleDO newRoleDO = roleMapper.selectById(roleId); + assertEquals(DataScopeEnum.DEPT_CUSTOM.getScore(), newRoleDO.getDataScope()); + + Set newDeptIdSet = newRoleDO.getDataScopeDeptIds(); + assertTrue(deptIdSet.size() == newDeptIdSet.size()); + deptIdSet.stream().forEach(d -> assertTrue(newDeptIdSet.contains(d))); + + verify(sysRoleProducer).sendRoleRefreshMessage(); + } + + @Test + public void testDeleteRole_success() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + //调用 + sysRoleService.deleteRole(roleId); + + //断言 + SysRoleDO newRoleDO = roleMapper.selectById(roleId); + assertNull(newRoleDO); + + verify(sysRoleProducer).sendRoleRefreshMessage(); + } + + @Test + public void testGetRoles_success() { + Map idRoleMap = new HashMap<>(); + // 验证查询状态为1的角色 + SysRoleDO roleDO1 = createRoleDO("role1", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); + roleMapper.insert(roleDO1); + idRoleMap.put(roleDO1.getId(), roleDO1); + + SysRoleDO roleDO2 = createRoleDO("role2", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); + roleMapper.insert(roleDO2); + idRoleMap.put(roleDO2.getId(), roleDO2); + + // 以下是排除的角色 + SysRoleDO roleDO3 = createRoleDO("role3", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2); + roleMapper.insert(roleDO3); + + //调用 + List roles = sysRoleService.getRoles(Arrays.asList(1)); + + //断言 + assertEquals(2, roles.size()); + roles.stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r)); + + } + + @Test + public void testGetRolePage_success() { + Map idRoleMap = new HashMap<>(); + // 验证名称包含"role", 状态为1,code为"code"的角色 + // 第一页 + SysRoleDO roleDO = createRoleDO("role1", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); + roleMapper.insert(roleDO); + idRoleMap.put(roleDO.getId(), roleDO); + // 第二页 + roleDO = createRoleDO("role2", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); + roleMapper.insert(roleDO); + + // 以下是排除的角色 + roleDO = createRoleDO("role3", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2, "code"); + roleMapper.insert(roleDO); + roleDO = createRoleDO("role4", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "xxxxx"); + roleMapper.insert(roleDO); + + //调用 + SysRolePageReqVO reqVO = randomPojo(SysRolePageReqVO.class, o -> { + o.setName("role"); + o.setCode("code"); + o.setStatus(1); + o.setPageNo(1); + o.setPageSize(1); + o.setBeginTime(null); + o.setEndTime(null); + }); + PageResult result = sysRoleService.getRolePage(reqVO); + assertEquals(2, result.getTotal()); + result.getList().stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r)); + } + + @Test + public void testCheckDuplicateRole_success() { + sysRoleService.checkDuplicateRole(randomString(), randomString(), null); + } + + @Test + public void testCheckDuplicateRole_nameDuplicate() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + + String duplicateName = "role_name"; + + assertServiceException(() -> sysRoleService.checkDuplicateRole(duplicateName, randomString(), null), ROLE_NAME_DUPLICATE, duplicateName); + } + + @Test + public void testCheckDuplicateRole_codeDuplicate() { + SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> { + o.setName("role_999"); + o.setCode("code"); + o.setType(SysRoleTypeEnum.CUSTOM.getType()); + o.setStatus(1); + o.setDataScope(DataScopeEnum.ALL.getScore()); + }); + roleMapper.insert(roleDO); + + String randomName = randomString(); + String duplicateCode = "code"; + + assertServiceException(() -> sysRoleService.checkDuplicateRole(randomName, duplicateCode, null), ROLE_CODE_DUPLICATE, duplicateCode); + } + + @Test + public void testCheckUpdateRole_success() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.CUSTOM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + sysRoleService.checkUpdateRole(roleId); + } + + @Test + public void testCheckUpdateRole_roleIdNotExist() { + assertServiceException(() -> sysRoleService.checkUpdateRole(randomLongId()), ROLE_NOT_EXISTS); + } + + @Test + public void testCheckUpdateRole_systemRoleCanNotBeUpdate() { + SysRoleDO roleDO = createRoleDO("role_name", SysRoleTypeEnum.SYSTEM, DataScopeEnum.ALL); + roleMapper.insert(roleDO); + Long roleId = roleDO.getId(); + + assertServiceException(() -> sysRoleService.checkUpdateRole(roleId), ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE); + } + + private SysRoleDO createRoleDO(String name, SysRoleTypeEnum typeEnum, DataScopeEnum scopeEnum, Integer status) { + return createRoleDO( name, typeEnum, scopeEnum, status, randomString()); + } + + private SysRoleDO createRoleDO(String name, SysRoleTypeEnum typeEnum, DataScopeEnum scopeEnum, Integer status, String code) { + return createRoleDO(null, name, typeEnum, scopeEnum, status, code); + } + + private SysRoleDO createRoleDO(String name, SysRoleTypeEnum typeEnum, DataScopeEnum scopeEnum) { + return createRoleDO(null, name, typeEnum, scopeEnum, randomCommonStatus(), randomString()); + } + + private SysRoleDO createRoleDO(Long id, String name, SysRoleTypeEnum typeEnum, DataScopeEnum scopeEnum, Integer status, String code) { + SysRoleDO roleDO = randomPojo(SysRoleDO.class, o -> { + o.setId(id); + o.setName(name); + o.setType(typeEnum.getType()); + o.setStatus(status); + o.setDataScope(scopeEnum.getScore()); + o.setCode(code); + }); + return roleDO; + } + +} From 3acdec965d0b7ba9aa386f190faaf2f6c960039c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 24 Mar 2021 00:52:40 +0800 Subject: [PATCH 17/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-24=EF=BC=8C=E8=B0=83=E6=95=B4=E4=B8=8B=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=8F=91=E9=80=81=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/core/util/RedisStreamUtils.java | 29 ------ .../framework/sms/core/SmsClientFactory.java | 2 +- .../controller/sms/SmsChannelController.java | 2 +- .../sms/SmsDefaultCallbackController.java | 5 - .../system/convert/sms/SmsChannelConvert.java | 2 +- .../convert/sms/SmsTemplateConvert.java | 4 +- .../dataobject/sms/SysSmsChannelDO.java | 2 +- .../dataobject/sms/SysSmsQueryLogDO.java | 2 +- .../dataobject/sms/SysSmsSendLogDO.java | 2 +- .../dataobject/sms/SysSmsTemplateDO.java | 16 +++- .../dal/mysql/sms/SysSmsChannelMapper.java | 4 +- .../dal/mysql/sms/SysSmsQueryLogMapper.java | 4 +- .../dal/mysql/sms/SysSmsSendLogMapper.java | 4 +- .../dal/mysql/sms/SysSmsTemplateMapper.java | 13 ++- .../system/enums/SysErrorCodeConstants.java | 8 +- .../consumer/dept/SysDeptRefreshConsumer.java | 4 +- .../dict/SysDictDataRefreshConsumer.java | 4 +- .../permission/SysMenuRefreshConsumer.java | 4 +- .../SysRoleMenuRefreshConsumer.java | 4 +- .../permission/SysRoleRefreshConsumer.java | 4 +- .../consumer}/sms/SmsSendStreamConsumer.java | 2 +- .../message/dept/SysDeptRefreshMessage.java | 2 +- .../dict/SysDictDataRefreshMessage.java | 2 +- .../permission/SysMenuRefreshMessage.java | 2 +- .../permission/SysRoleMenuRefreshMessage.java | 2 +- .../permission/SysRoleRefreshMessage.java | 2 +- .../mq/producer/dept/SysDeptProducer.java | 4 +- .../mq/producer/dict/SysDictDataProducer.java | 4 +- .../producer/permission/SysMenuProducer.java | 4 +- .../permission/SysPermissionProducer.java | 4 +- .../producer/permission/SysRoleProducer.java | 4 +- .../producer/sms/SmsSendStreamProducer.java | 42 +++++++++ .../mq/consumer/sms/SmsSendConsumer.java | 56 ----------- .../redis/mq/producer/sms/SmsProducer.java | 31 ------- .../redis/stream/StreamConsumerRunner.java | 93 ------------------- .../redis/stream/sms/SmsSendMessage.java | 16 ---- .../stream/sms/SmsSendStreamProducer.java | 35 ------- .../service/dept/impl/SysDeptServiceImpl.java | 2 +- .../dict/impl/SysDictDataServiceImpl.java | 2 +- .../permission/impl/SysMenuServiceImpl.java | 2 +- .../impl/SysPermissionServiceImpl.java | 3 +- .../permission/impl/SysRoleServiceImpl.java | 2 +- .../service/sms/SysSmsChannelService.java | 4 +- .../system/service/sms/SysSmsService.java | 43 +-------- .../service/sms/SysSmsTemplateService.java | 13 ++- .../sms/impl/SysSmsChannelServiceImpl.java | 6 +- .../sms/impl/SysSmsQueryLogServiceImpl.java | 2 +- .../sms/impl/SysSmsSendLogServiceImpl.java | 9 +- .../service/sms/impl/SysSmsServiceImpl.java | 68 +++++++++++++- .../sms/impl/SysSmsTemplateServiceImpl.java | 13 +++ .../service/dept/SysDeptServiceTest.java | 2 +- .../service/dict/SysDictDataServiceTest.java | 2 +- 52 files changed, 219 insertions(+), 378 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/{mysql => }/dataobject/sms/SysSmsChannelDO.java (94%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/{mysql => }/dataobject/sms/SysSmsQueryLogDO.java (95%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/{mysql => }/dataobject/sms/SysSmsSendLogDO.java (93%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/{mysql => }/dataobject/sms/SysSmsTemplateDO.java (75%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/consumer/dept/SysDeptRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/consumer/dict/SysDictDataRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/consumer/permission/SysMenuRefreshConsumer.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/consumer/permission/SysRoleMenuRefreshConsumer.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/consumer/permission/SysRoleRefreshConsumer.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis/stream => mq/consumer}/sms/SmsSendStreamConsumer.java (96%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/message/dept/SysDeptRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/message/dict/SysDictDataRefreshMessage.java (82%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/message/permission/SysMenuRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/message/permission/SysRoleMenuRefreshMessage.java (81%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/message/permission/SysRoleRefreshMessage.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/producer/dept/SysDeptProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/producer/dict/SysDictDataProducer.java (80%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/producer/permission/SysMenuProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/producer/permission/SysPermissionProducer.java (79%) rename src/main/java/cn/iocoder/dashboard/modules/system/{redis => }/mq/producer/permission/SysRoleProducer.java (79%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java b/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java deleted file mode 100644 index 590c84209..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisStreamUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.dashboard.framework.redis.core.util; - -import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; -import org.springframework.data.redis.connection.stream.StreamRecords; -import org.springframework.data.redis.core.RedisTemplate; - -/** - * Redis 消息工具类 - * - * @author 芋道源码 - */ -public class RedisStreamUtils { - - public static final String KEY_SMS_SEND = "stream_sms_send"; - - public static final String GROUP_SMS_SEND = "group_sms_send"; - - /** - * 发送 Redis 消息,基于 Redis pub/sub 实现 - * - * @param redisTemplate Redis 操作模板 - * @param message 消息 - */ - public static void sendChannelMessage(RedisTemplate redisTemplate, SmsSendMessage message) { - - redisTemplate.opsForStream().add(StreamRecords.newRecord().ofObject(message).withStreamKey(KEY_SMS_SEND)); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index d55c7cb99..bd41cc2ee 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -102,7 +102,7 @@ public class SmsClientFactory { public String getTemplateApiIdByCode(String templateCode) { SmsTemplateProperty smsTemplateProperty = templatePropertyMap.get(templateCode); if (smsTemplateProperty == null) { - throw new ServiceException(SMS_TEMPLATE_NOT_FOUND); + throw new ServiceException(SMS_TEMPLATE_NOT_EXISTS); } return smsTemplateProperty.getApiTemplateId(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index ddc492c23..415e47405 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -5,7 +5,7 @@ import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java index 0a33e8b0e..3d4661076 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java @@ -1,19 +1,14 @@ package cn.iocoder.dashboard.modules.system.controller.sms; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.servlet.ServletRequest; -import java.util.Arrays; -import java.util.Map; /** * 短信默认回调接口 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index ad272218e..833c1919c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -7,7 +7,7 @@ import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java index febac15fc..2ff680028 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java @@ -3,8 +3,8 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java similarity index 94% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java index d38c1bc07..48acf346f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableName; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java similarity index 95% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java index ebb170ded..8a5d413bc 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsQueryLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java similarity index 93% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java index f85416dba..4bbe5f23e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsSendLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java similarity index 75% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java index 3e8cdc25c..929e79440 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SysSmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java @@ -1,11 +1,14 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms; +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.Date; +import java.util.List; /** * 短信模板 @@ -44,7 +47,7 @@ public class SysSmsTemplateDO extends BaseDO { private String bizCode; /** - * 编码 + * 模板编码 */ private String code; @@ -66,7 +69,8 @@ public class SysSmsTemplateDO extends BaseDO { /** * 参数数组(自动根据内容生成) */ - private String params; + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; /** * 备注 @@ -74,7 +78,9 @@ public class SysSmsTemplateDO extends BaseDO { private String remark; /** - * 启用状态(0正常 1停用) + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} */ private Integer status; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java index 43b7fe743..e601ebc5c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java @@ -1,10 +1,10 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java index 535afa667..d02ceec8c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java index eebb48fcc..3a5c7fbb8 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java @@ -1,6 +1,6 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; +package cn.iocoder.dashboard.modules.system.dal.mysql.sms; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java index b24c630d4..3cfc898b3 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java @@ -1,15 +1,18 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms; - +package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper -public interface SysSmsTemplateMapper extends BaseMapper { +public interface SysSmsTemplateMapper extends BaseMapperX { + + default SysSmsTemplateDO selectOneByCode(String code) { + return selectOne("code", code); + } /** * 根据短信渠道id查询短信模板集合 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index ca4c11a05..94db1c2f6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -79,11 +79,15 @@ public interface SysErrorCodeConstants { ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空"); - // ========== 消息 1003001000 ========== + // ========== 短信模板 1002010000 ========== + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002010000, "短信模板不存在"); + + // ========== 短信发送 1002011000 ========== + ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002011000, "手机号不存在"); + ErrorCode SMS_CHANNEL_NOT_INIT = new ErrorCode(1003001001, "短信渠道没有初始化, 请调用SmsClientWrapper#initSmsClient()或SmsClientWrapper#addSmsClient"); ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001002, "没有短信渠道信息, 请初始化sms_channel表数据。"); - ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001003, "没有短信模板信息, 请初始化sms_template表数据。"); ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001004, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001005, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); ErrorCode PARAM_VALUE_IS_NULL = new ErrorCode(1003001006, "参数【{}】不能为空"); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java index 7e4852dff..e6fa5a98d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dept/SysDeptRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dept/SysDeptRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dept; +package cn.iocoder.dashboard.modules.system.mq.consumer.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java index 87c898984..12bf134a3 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/dict/SysDictDataRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/dict/SysDictDataRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.consumer.dict; +package cn.iocoder.dashboard.modules.system.mq.consumer.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java index 5f4442769..36152424c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java index 60861ba58..6927e1464 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleMenuRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java index 0a71fca7e..a5e77f7e5 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/permission/SysRoleRefreshConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.consumer.permission; +package cn.iocoder.dashboard.modules.system.mq.consumer.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java similarity index 96% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java index 0ab531b43..bbd5de462 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.stream.sms; +package cn.iocoder.dashboard.modules.system.mq.consumer.sms; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java index 0c069e319..a78b1250f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dept/SysDeptRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dept/SysDeptRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.message.dept; +package cn.iocoder.dashboard.modules.system.mq.message.dept; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java similarity index 82% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java index 2d4342423..7fad277c4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/dict/SysDictDataRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/dict/SysDictDataRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.message.dict; +package cn.iocoder.dashboard.modules.system.mq.message.dict; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java index 8f72705ee..159682a98 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; +package cn.iocoder.dashboard.modules.system.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java similarity index 81% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java index b1c303dbe..491c9b0d2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleMenuRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; +package cn.iocoder.dashboard.modules.system.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java index ac46d181e..b99401021 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/message/permission/SysRoleRefreshMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleRefreshMessage.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.message.permission; +package cn.iocoder.dashboard.modules.system.mq.message.permission; import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java index 3ce859fa4..4ad7db4b8 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dept/SysDeptProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dept/SysDeptProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.producer.dept; +package cn.iocoder.dashboard.modules.system.mq.producer.dept; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.dept.SysDeptRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java similarity index 80% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java index af9daae84..2ccfc51d2 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/dict/SysDictDataProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/dict/SysDictDataProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.producer.dict; +package cn.iocoder.dashboard.modules.system.mq.producer.dict; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.redis.mq.message.dict.SysDictDataRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.dict.SysDictDataRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java index 9a760ad2d..6d664c725 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysMenuProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysMenuProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java index 67a4769a1..f9eded668 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysPermissionProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleMenuRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java similarity index 79% rename from src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java index f1be4b87b..e11945dfe 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/permission/SysRoleProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysRoleProducer.java @@ -1,7 +1,7 @@ -package cn.iocoder.dashboard.modules.system.redis.mq.producer.permission; +package cn.iocoder.dashboard.modules.system.mq.producer.permission; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -import cn.iocoder.dashboard.modules.system.redis.mq.message.permission.SysRoleRefreshMessage; +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleRefreshMessage; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java new file mode 100644 index 000000000..891a844cc --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java @@ -0,0 +1,42 @@ +package cn.iocoder.dashboard.modules.system.mq.producer.sms; + +import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.Map; + +/** + * 短信发送流消息监听器 + * + * @author zzf + * @date 2021/3/9 16:35 + */ +@Slf4j +@Component +public class SmsSendStreamProducer { + + @Resource + private StringRedisTemplate stringRedisTemplate; + + /** + * 发送短信 Message + * + * @param mobile 手机号 + * @param templateCode 短信模板编号 + * @param templateParams 短信模板参数 + * @param userId 用户编号 + * @param userType 用户类型 + */ + public void sendSmsSendMessage(String mobile, String templateCode, Map templateParams, + Integer userId, Integer userType) { + SysSmsSendMessage message = new SysSmsSendMessage(); + message.setMobile(mobile).setTemplateCode(templateCode).setTemplateParams(templateParams); + message.setUserId(userId).setUserType(userType); + RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java deleted file mode 100644 index db8d727ad..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/consumer/sms/SmsSendConsumer.java +++ /dev/null @@ -1,56 +0,0 @@ -//package cn.iocoder.dashboard.modules.system.redis.mq.consumer.sms; -// -//import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; -//import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -//import cn.iocoder.dashboard.framework.sms.core.SmsResult; -//import cn.iocoder.dashboard.modules.system.redis.mq.message.dept.SysDeptRefreshMessage; -//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; -//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -//import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.data.redis.connection.stream.Consumer; -//import org.springframework.data.redis.connection.stream.ObjectRecord; -//import org.springframework.data.redis.connection.stream.ReadOffset; -//import org.springframework.data.redis.connection.stream.StreamOffset; -//import org.springframework.data.redis.core.StringRedisTemplate; -//import org.springframework.stereotype.Component; -// -//import javax.annotation.Resource; -// -///** -// * 针对 {@link SysDeptRefreshMessage} 的消费者 -// * -// * @author 芋道源码 -// */ -//@Component -//@Slf4j -//public class SmsSendConsumer extends AbstractChannelMessageListener { -// -// @Resource -// private SysSmsChannelService smsChannelService; -// -// @Resource -// private SysSmsQueryLogService smsQueryLogService; -// -// @Autowired -// StringRedisTemplate redisTemplate; -// -// @Override -// public void onMessage(SmsSendMessage message) { -// -// redisTemplate.opsForStream().add(ObjectRecord.create("String", message)); -// -// redisTemplate.opsForStream().read(Consumer.from("",""), StreamOffset.create("", ReadOffset.lastConsumed())); -// -// -// -// log.info("[onMessage][收到 发送短信 消息], content: " + message.toString()); -// AbstractSmsClient smsClient = smsChannelService.getSmsClient(message.getSmsBody().getTemplateCode()); -// String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(message.getSmsBody().getTemplateCode()); -// -// SmsResult result = smsClient.send(templateApiId, message.getSmsBody(), message.getTargetPhone()); -// smsQueryLogService.afterSendLog(message.getSmsBody().getSmsLogId(), result); -// } -// -//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java deleted file mode 100644 index 3e4681715..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/mq/producer/sms/SmsProducer.java +++ /dev/null @@ -1,31 +0,0 @@ -//package cn.iocoder.dashboard.modules.system.redis.mq.producer.sms; -// -//import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; -//import cn.iocoder.dashboard.framework.sms.core.SmsBody; -//import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; -//import org.springframework.data.redis.core.StringRedisTemplate; -//import org.springframework.stereotype.Component; -// -//import javax.annotation.Resource; -// -///** -// * 短信的 Producer -// */ -//@Component -//public class SmsProducer { -// -// @Resource -// private StringRedisTemplate stringRedisTemplate; -// -// /** -// * 发送 {@link SmsSendMessage} 消息 -// */ -// public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { -// SmsSendMessage message = new SmsSendMessage(); -// message.setSmsBody(smsBody); -// message.setTargetPhone(targetPhone); -// // TODO FROM 芋艿 TO ZZF:这块等未来改哈。这个方法目前是广播消费,会导致每个节点都发送一次。等后续封装出 redis stream 消息 -// RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); -// } -// -//} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java deleted file mode 100644 index 7cd9d2486..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/StreamConsumerRunner.java +++ /dev/null @@ -1,93 +0,0 @@ -package cn.iocoder.dashboard.modules.system.redis.stream; - -import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; -import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendMessage; -import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamConsumer; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.stream.*; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; -import org.springframework.data.redis.stream.StreamMessageListenerContainer; -import org.springframework.data.redis.stream.StreamMessageListenerContainer.StreamMessageListenerContainerOptions; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.stereotype.Component; -import org.springframework.util.ErrorHandler; - -import javax.annotation.Resource; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.time.Duration; - - -@Slf4j -@Component -public class StreamConsumerRunner implements ApplicationRunner, DisposableBean { - - @Resource - RedisConnectionFactory redisConnectionFactory; - - @Resource - ThreadPoolTaskExecutor threadPoolTaskExecutor; - - @Resource - SmsSendStreamConsumer streamMessageListener; - - @Resource - StringRedisTemplate stringRedisTemplate; - - private StreamMessageListenerContainer> streamMessageListenerContainer; - - @Override - public void run(ApplicationArguments args) throws UnknownHostException { - - StreamInfo.XInfoGroups groups = stringRedisTemplate.opsForStream().groups(RedisStreamUtils.KEY_SMS_SEND); - if (groups.isEmpty()) { - stringRedisTemplate.opsForStream().createGroup(RedisStreamUtils.KEY_SMS_SEND, RedisStreamUtils.GROUP_SMS_SEND); - } - - - // 创建配置对象 - StreamMessageListenerContainerOptions> streamMessageListenerContainerOptions = StreamMessageListenerContainerOptions - .builder() - // 一次性最多拉取多少条消息 - .batchSize(10) - // 执行消息轮询的执行器 - .executor(this.threadPoolTaskExecutor) - // 消息消费异常的handler - .errorHandler(new ErrorHandler() { - @Override - public void handleError(Throwable t) { - // throw new RuntimeException(t); - t.printStackTrace(); - } - }) - // 超时时间,设置为0,表示不超时(超时后会抛出异常) - .pollTimeout(Duration.ZERO) - // 序列化器 - .serializer(new StringRedisSerializer()) - .targetType(SmsSendMessage.class) - .build(); - - // 根据配置对象创建监听容器对象 - StreamMessageListenerContainer> streamMessageListenerContainer = StreamMessageListenerContainer - .create(this.redisConnectionFactory, streamMessageListenerContainerOptions); - - // 使用监听容器对象开始监听消费(使用的是手动确认方式) - streamMessageListenerContainer.receive(Consumer.from(RedisStreamUtils.GROUP_SMS_SEND, InetAddress.getLocalHost().getHostName()), - StreamOffset.create(RedisStreamUtils.KEY_SMS_SEND, ReadOffset.lastConsumed()), this.streamMessageListener); - - this.streamMessageListenerContainer = streamMessageListenerContainer; - // 启动监听 - this.streamMessageListenerContainer.start(); - - } - - @Override - public void destroy() throws Exception { - this.streamMessageListenerContainer.stop(); - } -} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java deleted file mode 100644 index a8aeff23f..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendMessage.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.dashboard.modules.system.redis.stream.sms; - -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import lombok.Data; - -/** - * 部门数据刷新 Message - */ -@Data -public class SmsSendMessage { - - private SmsBody smsBody; - - private String targetPhone; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java deleted file mode 100644 index 069534251..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/redis/stream/sms/SmsSendStreamProducer.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.dashboard.modules.system.redis.stream.sms; - -import cn.iocoder.dashboard.framework.redis.core.util.RedisStreamUtils; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; - -/** - * 短信发送流消息监听器 - * - * @author zzf - * @date 2021/3/9 16:35 - */ -@Slf4j -@Component -public class SmsSendStreamProducer { - - @Resource - private StringRedisTemplate stringRedisTemplate; - - /** - * 发送 {@link SmsSendMessage} 消息 - */ - public void sendSmsSendMessage(SmsBody smsBody, String targetPhone) { - SmsSendMessage message = new SmsSendMessage(); - message.setSmsBody(smsBody); - message.setTargetPhone(targetPhone); - - RedisStreamUtils.sendChannelMessage(stringRedisTemplate, message); - } - -} \ No newline at end of file diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java index e87e92a9b..96e3d1ad0 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dept/impl/SysDeptServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.convert.dept.SysDeptConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysDeptMapper; import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO; import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.dept.SysDeptProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer; import cn.iocoder.dashboard.modules.system.service.dept.SysDeptService; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java index 461d1ab21..7f24cbff4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java @@ -12,7 +12,7 @@ import cn.iocoder.dashboard.modules.system.convert.dict.SysDictDataConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.SysDictDataService; import cn.iocoder.dashboard.modules.system.service.dict.SysDictTypeService; import com.google.common.annotations.VisibleForTesting; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java index 6b93d9d48..ec4ea5a9b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java @@ -11,7 +11,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysMenuMapper; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.enums.permission.MenuIdEnum; import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysMenuProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.util.collection.CollectionUtils; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java index 5cf15879b..9116d3e55 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.dashboard.modules.system.service.permission.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMenuMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysUserRoleMapper; @@ -11,7 +10,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysMenuDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleMenuDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysUserRoleDO; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysPermissionProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java index 1d627b8b3..e79813636 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java @@ -15,7 +15,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMapper; import cn.iocoder.dashboard.modules.system.dal.dataobject.permission.SysRoleDO; import cn.iocoder.dashboard.modules.system.enums.permission.RoleCodeEnum; import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.permission.SysRoleProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer; import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index 3ce83fe78..5224adb9a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -2,14 +2,12 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import javax.servlet.ServletRequest; import java.util.List; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 93a467d62..cccd64c31 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -1,13 +1,8 @@ package cn.iocoder.dashboard.modules.system.service.sms; -import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; - import javax.servlet.ServletRequest; -import java.util.Arrays; import java.util.List; +import java.util.Map; /** * 短信Service接口 @@ -18,39 +13,11 @@ import java.util.List; */ public interface SysSmsService { - /** - * 发送消息 - * - * @param smsBody 消息内容 - * @param targetPhones 发送对象手机号列表 - */ - default void send(SmsBody smsBody, List targetPhones) { - if (CollectionUtil.isEmpty(targetPhones)) { - return; - } - targetPhones.forEach(s -> this.send(smsBody, s)); - } + void sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams); - /** - * 发送消息 - * - * @param smsBody 消息内容 - * @param targetPhone 发送对象手机号 - */ - void send(SmsBody smsBody, String targetPhone); - - /** - * 发送消息 - * - * @param smsBody 消息内容 - * @param targetPhones 发送对象手机号数组 - */ - default void send(SmsBody smsBody, String... targetPhones) { - if (ArrayUtil.isEmpty(targetPhones)) { - return; - } - send(smsBody, Arrays.asList(targetPhones)); - } + void sendBatchSms(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams); /** * 处理短信发送回调函数 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java index 8ba74b2f6..137291a47 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java @@ -1,10 +1,21 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; + /** - * 短信渠道Service接口 + * 短信模板 Service 接口 * * @author zzf * @date 2021/1/25 9:24 */ public interface SysSmsTemplateService { + + /** + * 获得短信模板 + * + * @param code 模板编码 + * @return 短信模板 + */ + SysSmsTemplateDO getSmsTemplateByCode(String code); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index 6ecd7681b..6026320f9 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java @@ -8,7 +8,6 @@ import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -16,10 +15,9 @@ import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsChannelMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java index a08a7bb76..42d7d3550 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -6,7 +6,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import org.springframework.stereotype.Service; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index c58ce5ca7..8cb5772ac 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -2,11 +2,10 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsSendLogMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsQueryLogDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsQueryLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index c679a8c81..6bb0657ee 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -1,17 +1,29 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.modules.system.redis.stream.sms.SmsSendStreamProducer; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; +import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsSendStreamProducer; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.servlet.ServletRequest; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; /** * 短信日志Service实现类 @@ -22,9 +34,15 @@ import javax.servlet.ServletRequest; @Service public class SysSmsServiceImpl implements SysSmsService { + @Resource + private SysSmsTemplateService smsTemplateService; + @Resource + private SysUserService userService; + @Resource private SysSmsChannelService channelService; + @Resource private SysSmsQueryLogService logService; @@ -34,6 +52,54 @@ public class SysSmsServiceImpl implements SysSmsService { @Resource private SmsClientFactory smsClientFactory; + @Override + public void sendSingleSms(String mobile, Long userId, Integer userType, + String templateCode, Map templateParams) { + // 校验短信模板是否存在 + SysSmsTemplateDO template = this.checkSmsTemplateExists(templateCode); + // 校验手机号码是否存在 + mobile = this.checkMobile(mobile, userId, userType); + } + + @Override + public void sendBatchSms(List mobiles, List userIds, Integer userType, + String templateCode, Map templateParams) { + // 校验短信模板是否存在 + SysSmsTemplateDO template = this.checkSmsTemplateExists(templateCode); + } + + private SysSmsTemplateDO checkSmsTemplateExists(String templateCode) { + SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode); + if (template == null) { + throw exception(SMS_TEMPLATE_NOT_EXISTS); + } + return template; + } + + private String checkMobile(String mobile, Long userId, Integer userType) { + mobile = getMobile(mobile, userId, userType); + if (StrUtil.isEmpty(mobile)) { + throw exception(SMS_SEND_MOBILE_NOT_EXISTS); + } + return mobile; + } + + private String getMobile(String mobile, Long userId, Integer userType) { + // 如果已经有手机号,则直接返回 + if (StrUtil.isNotEmpty(mobile)) { + return mobile; + } + // 没有手机号,则基于 userId 检索 + if (userId == null || userType == null) { + return null; + } + if (Objects.equals(userType, UserTypeEnum.ADMIN.getValue())) { + SysUserDO user = userService.getUser(userId); + return user != null ? user.getMobile() : null; + } + return null; + } + @Override public void send(SmsBody smsBody, String targetPhone) { AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index 0bf7ca1a0..ccbb26079 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -1,8 +1,12 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import org.springframework.stereotype.Service; +import javax.annotation.Resource; + /** * 短信模板Service实现类 * @@ -11,4 +15,13 @@ import org.springframework.stereotype.Service; */ @Service public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { + + @Resource + private SysSmsTemplateMapper smsTemplateMapper; + + @Override + public SysSmsTemplateDO getSmsTemplateByCode(String code) { + return smsTemplateMapper.selectOneByCode(code); + } + } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java index f3db031aa..373665546 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java @@ -8,7 +8,7 @@ import cn.iocoder.dashboard.modules.system.controller.dept.vo.dept.SysDeptUpdate import cn.iocoder.dashboard.modules.system.dal.dataobject.dept.SysDeptDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dept.SysDeptMapper; import cn.iocoder.dashboard.modules.system.enums.dept.DeptIdEnum; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.dept.SysDeptProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.dept.SysDeptProducer; import cn.iocoder.dashboard.modules.system.service.dept.impl.SysDeptServiceImpl; import cn.iocoder.dashboard.util.collection.ArrayUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java index bfd1d9781..2874285e4 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dict/SysDictDataServiceTest.java @@ -10,7 +10,7 @@ import cn.iocoder.dashboard.modules.system.controller.dict.vo.data.SysDictDataUp import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictDataDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.dict.SysDictTypeDO; import cn.iocoder.dashboard.modules.system.dal.mysql.dict.SysDictDataMapper; -import cn.iocoder.dashboard.modules.system.redis.mq.producer.dict.SysDictDataProducer; +import cn.iocoder.dashboard.modules.system.mq.producer.dict.SysDictDataProducer; import cn.iocoder.dashboard.modules.system.service.dict.impl.SysDictDataServiceImpl; import cn.iocoder.dashboard.util.collection.ArrayUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; From df01bd6c79cba042f24fe4c70df1fab807a1665d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 25 Mar 2021 00:52:09 +0800 Subject: [PATCH 18/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-25=EF=BC=8C=E8=B0=83=E6=95=B4=E4=B8=8B=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=8F=91=E9=80=81=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/client/impl/ali/AliyunSmsClient.java | 6 +- .../client/impl/yunpian/YunpianSmsClient.java | 6 +- .../framework/sms/core/SmsResultDetail.java | 3 +- .../dal/dataobject/sms/SysSmsQueryLogDO.java | 128 ++++++++++++------ .../dal/dataobject/sms/SysSmsSendLogDO.java | 4 +- .../dal/dataobject/sms/SysSmsTemplateDO.java | 92 ++++++------- .../dal/mysql/sms/SysSmsQueryLogMapper.java | 4 +- .../system/enums/SysErrorCodeConstants.java | 1 + .../system/enums/sms/SmsSendStatusEnum.java | 39 ------ .../enums/sms/SysSmsSendFailureTypeEnum.java | 19 +++ .../enums/sms/SysSmsSendStatusEnum.java | 23 ++++ .../enums/sms/SysSmsTemplateTypeEnum.java | 25 ++++ .../system/service/sms/SysSmsService.java | 2 + .../sms/impl/SysSmsQueryLogServiceImpl.java | 6 +- .../sms/impl/SysSmsSendLogServiceImpl.java | 4 +- .../service/sms/impl/SysSmsServiceImpl.java | 28 +++- 16 files changed, 245 insertions(+), 145 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsTemplateTypeEnum.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java index 49feb8dd2..11301ebf6 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java @@ -7,7 +7,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; @@ -131,8 +131,8 @@ public class AliyunSmsClient extends AbstractSmsClient { public Integer getSendStatus() { return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) - ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SmsSendStatusEnum.SEND_FAIL.getStatus(); + ? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SysSmsSendStatusEnum.SEND_FAIL.getStatus(); } public String getBizId() { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java index 72b03a45e..1164439de 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java @@ -9,7 +9,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.fasterxml.jackson.core.type.TypeReference; import com.yunpian.sdk.YunpianClient; @@ -155,8 +155,8 @@ public class YunpianSmsClient extends AbstractSmsClient { private static int getSendStatus(Map map) { String reportStatus = map.get(REPORT_STATUS); return SmsConstants.SUCCESS.equals(reportStatus) - ? SmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SmsSendStatusEnum.SEND_FAIL.getStatus(); + ? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() + : SysSmsSendStatusEnum.SEND_FAIL.getStatus(); } public static SmsResultDetail getSmsResultDetailByParam(Map map) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java index aab4af217..4d57a090f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import lombok.Data; import java.io.Serializable; @@ -17,7 +18,7 @@ public class SmsResultDetail implements Serializable { private String apiId; /** - * 短信发送状态 {@link cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum} + * 短信发送状态 {@link SysSmsSendStatusEnum} */ private Integer sendStatus; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java index 8a5d413bc..05681d744 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java @@ -1,15 +1,20 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; +import cn.iocoder.dashboard.common.enums.UserTypeEnum; +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendFailureTypeEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; -import java.io.Serializable; import java.util.Date; +import java.util.Map; /** - * 短信日志 + * 短信发送日志 * * @author zzf * @since 2021-01-25 @@ -18,73 +23,118 @@ import java.util.Date; @EqualsAndHashCode @Accessors(chain = true) @TableName(value = "sms_query_log", autoResultMap = true) -public class SysSmsQueryLogDO implements Serializable { +public class SysSmsQueryLogDO extends BaseDO { /** * 自增编号 */ private Long id; - /** - * 第三方唯一标识 - */ - private String apiId; + // ========= 渠道相关字段 ========= /** - * 短信渠道编码(来自枚举类) - */ - private String channelCode; - - /** - * 短信渠道id + * 短信渠道编号 + * + * 关联 {@link SysSmsChannelDO#getId()} */ private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SysSmsChannelDO#getCode()} + */ + private String channelCode; + /** + * 实际渠道模板唯一标识 + */ + private String apiTemplateId; + + // ========= 模板相关字段 ========= /** - * 模板id + * 短信模板编号 + * + * 关联 {@link} */ private String templateCode; + /** + * 短信类型 + * + * 枚举 {@link SysSmsTemplateTypeEnum} + */ + private Integer templateType; + /** + * 基于 {@link SysSmsTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容 + */ + private Map templateParams; + + // ========= 手机相关字段 ========= /** * 手机号 */ - private String phone; - + private String mobile; /** - * 内容 + * 用户编号 */ - private String content; + private Integer userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 发送相关字段 ========= /** * 发送状态 * - * @see cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum + * 枚举 {@link SysSmsSendStatusEnum} */ private Integer sendStatus; + /** + * 发送失败的类型 + * + * 枚举 {@link SysSmsSendFailureTypeEnum} + */ + private Integer sendFailureType; + /** + * 发送成功时间 + */ + private Date sendTime; + /** + * 短信 API 发送失败的类型 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiSendFailureType; + /** + * 短信 API 发送失败的提示 + */ + private String apiSendFailureMsg; + /** + * 短信 API 发送返回的唯一请求 ID + * + * 用于和短信 API 进行定位于排错 + */ + private String apiRequestId; + /** + * 短信 API 发送返回的序号 + * + * 用于和短信 API 平台的发送记录关联 + */ + private String apiSerialNo; + + // ========= 接收相关字段 ========= /** * 是否获取过结果[0否 1是] */ private Integer gotResult; - /** - * 备注 - */ - private String remark; - - /** - * 创建人 - */ - private String createBy; - - /** - * 创建时间 - */ - private Date createTime; - - /** - * 发送时间 - */ - private Date sendTime; - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java index 4bbe5f23e..e85edf74a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; @@ -54,7 +54,7 @@ public class SysSmsSendLogDO implements Serializable { /** * 发送状态 * - * @see SmsSendStatusEnum + * @see SysSmsSendStatusEnum */ private Integer sendStatus; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java index 929e79440..2efd9ae8e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java @@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; @@ -26,62 +27,59 @@ public class SysSmsTemplateDO extends BaseDO { */ private Long id; - /** - * 短信渠道编码(来自枚举类) - */ - private String channelCode; + // ========= 模板相关字段 ========= /** - * 短信渠道id (对于前端来说就是绑定一个签名) - */ - private Long channelId; - - /** - * 消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息] + * 短信类型 + * + * 枚举 {@link SysSmsTemplateTypeEnum} */ private Integer type; - - /** - * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) - */ - private String bizCode; - - /** - * 模板编码 - */ - private String code; - - /** - * 名称 - */ - private String name; - - /** - * 实际渠道模板唯一标识 - */ - private String apiTemplateId; - - /** - * 内容 - */ - private String content; - - /** - * 参数数组(自动根据内容生成) - */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List params; - - /** - * 备注 - */ - private String remark; - /** * 启用状态 * * 枚举 {@link CommonStatusEnum} */ private Integer status; + /** + * 模板编码,保证唯一 + */ + private String code; + /** + * 名称 + */ + private String name; + /** + * 内容 + */ + private String content; + /** + * 参数数组(自动根据内容生成) + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List params; + /** + * 备注 + */ + private String remark; + + // ========= 渠道相关字段 ========= + + /** + * 短信渠道编号 + * + * 关联 {@link SysSmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SysSmsChannelDO#getCode()} + */ + private String channelCode; + /** + * 短信 API 的模板编号 + */ + private String apiTemplateId; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java index d02ceec8c..917a013a6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @@ -17,7 +17,7 @@ public interface SysSmsQueryLogMapper extends BaseMapper { */ default List selectNoResultQueryLogList() { return this.selectList(new LambdaQueryWrapper() - .eq(SysSmsQueryLogDO::getSendStatus, SmsSendStatusEnum.QUERY_SUCCESS) + .eq(SysSmsQueryLogDO::getSendStatus, SysSmsSendStatusEnum.QUERY_SUCCESS) .eq(SysSmsQueryLogDO::getGotResult, DefaultBitFieldEnum.NO) ); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 94db1c2f6..87271a655 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -84,6 +84,7 @@ public interface SysErrorCodeConstants { // ========== 短信发送 1002011000 ========== ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002011000, "手机号不存在"); + ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002011001, "模板参数({})缺失"); ErrorCode SMS_CHANNEL_NOT_INIT = new ErrorCode(1003001001, "短信渠道没有初始化, 请调用SmsClientWrapper#initSmsClient()或SmsClientWrapper#addSmsClient"); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java deleted file mode 100644 index 4e4121083..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SmsSendStatusEnum.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.dashboard.modules.system.enums.sms; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 短信发送状态 - * - * @author zzf - * @date 2021/2/1 13:39 - */ -@Getter -@AllArgsConstructor -public enum SmsSendStatusEnum { - - //请求发送结果时失败 - QUERY_SEND_FAIL(-3), - - //短信发送失败 - SEND_FAIL(-2), - - //短信请求失败 - QUERY_FAIL(-1), - - //异步转发中 - ASYNC(0), - - //请求成功 - QUERY_SUCCESS(1), - - //短信成功 - SEND_SUCCESS(2), - - //等待回执 - WAITING(3); - - private final int status; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java new file mode 100644 index 000000000..8548e92ae --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java @@ -0,0 +1,19 @@ +package cn.iocoder.dashboard.modules.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的发送失败类型的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SysSmsSendFailureTypeEnum { + + ; + + private final int type; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java new file mode 100644 index 000000000..083b11c98 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java @@ -0,0 +1,23 @@ +package cn.iocoder.dashboard.modules.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的发送状态枚举 + * + * @author zzf + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SysSmsSendStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 发送成功 + FAILURE(20), // 发送失败 + ; + + private final int status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsTemplateTypeEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsTemplateTypeEnum.java new file mode 100644 index 000000000..8ff9c49b7 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsTemplateTypeEnum.java @@ -0,0 +1,25 @@ +package cn.iocoder.dashboard.modules.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的模板类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SysSmsTemplateTypeEnum { + + VERIFICATION_CODE(1), // 验证码 + NOTICE(2), // 通知 + PROMOTION(3), // 营销 + ; + + /** + * 类型 + */ + private final int type; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index cccd64c31..d4958f79b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -19,6 +19,8 @@ public interface SysSmsService { void sendBatchSms(List mobiles, List userIds, Integer userType, String templateCode, Map templateParams); + void doSendSms(); + /** * 处理短信发送回调函数 * diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java index 42d7d3550..78935dba6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import org.springframework.stereotype.Service; @@ -36,7 +36,7 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { .setPhone(targetPhone) .setContent(smsBody.getParams().toString()); - smsLog.setSendStatus(SmsSendStatusEnum.ASYNC.getStatus()); + smsLog.setSendStatus(SysSmsSendStatusEnum.ASYNC.getStatus()); logMapper.insert(smsLog); smsBody.setSmsLogId(smsLog.getId()); } @@ -46,7 +46,7 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); smsLog.setId(logId); smsLog.setApiId(result.getApiId()); - smsLog.setSendStatus(SmsSendStatusEnum.QUERY_FAIL.getStatus()); + smsLog.setSendStatus(SysSmsSendStatusEnum.QUERY_FAIL.getStatus()); smsLog.setRemark(result.getCode() + ": " + result.getMessage()); logMapper.updateById(smsLog); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index 8cb5772ac..320c0a7bd 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -6,7 +6,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; -import cn.iocoder.dashboard.modules.system.enums.sms.SmsSendStatusEnum; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; import lombok.extern.slf4j.Slf4j; @@ -88,7 +88,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); smsQueryLogMapper.updateById(updateQueryLog); }*/ - updateQueryLog.setSendStatus(SmsSendStatusEnum.SEND_SUCCESS.getStatus()); + updateQueryLog.setSendStatus(SysSmsSendStatusEnum.SEND_SUCCESS.getStatus()); updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId())); smsQueryLogMapper.updateById(updateQueryLog); }); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 6bb0657ee..64f9e3c8c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -1,5 +1,7 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; @@ -21,6 +23,8 @@ import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @@ -55,24 +59,40 @@ public class SysSmsServiceImpl implements SysSmsService { @Override public void sendSingleSms(String mobile, Long userId, Integer userType, String templateCode, Map templateParams) { - // 校验短信模板是否存在 - SysSmsTemplateDO template = this.checkSmsTemplateExists(templateCode); + // 校验短信模板是否合法 + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); // 校验手机号码是否存在 mobile = this.checkMobile(mobile, userId, userType); + // } @Override public void sendBatchSms(List mobiles, List userIds, Integer userType, String templateCode, Map templateParams) { // 校验短信模板是否存在 - SysSmsTemplateDO template = this.checkSmsTemplateExists(templateCode); + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); } - private SysSmsTemplateDO checkSmsTemplateExists(String templateCode) { + private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map templateParams) { + // 短信模板不存在 SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode); if (template == null) { throw exception(SMS_TEMPLATE_NOT_EXISTS); } + // 参数不够 + if (CollUtil.isNotEmpty(template.getParams())) { + template.getParams().forEach(param -> { + if (!templateParams.containsKey(param)) { + throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS); + } + }); + } + // 移除多余参数 + if (CollUtil.isEmpty(template.getParams())) { + templateParams.clear(); + } else { + templateParams.entrySet().removeIf(entry -> !template.getParams().contains(entry.getKey())); + } return template; } From f3b6783cc3d5ba563e8341960ef4fa34716b1738 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 26 Mar 2021 01:08:17 +0800 Subject: [PATCH 19/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-26=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8F=91=E9=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dal/dataobject/sms/SysSmsQueryLogDO.java | 140 ------------------ .../dal/dataobject/sms/SysSmsSendLogDO.java | 126 +++++++++++++--- .../dal/dataobject/sms/SysSmsSendLogDOX.java | 66 +++++++++ .../dal/dataobject/sms/SysSmsTemplateDO.java | 10 +- .../dal/mysql/sms/SysSmsQueryLogMapper.java | 18 +-- .../service/sms/SysSmsQueryLogService.java | 7 +- .../service/sms/SysSmsSendLogService.java | 7 + .../service/sms/SysSmsTemplateService.java | 11 ++ .../sms/impl/SysSmsQueryLogServiceImpl.java | 8 +- .../sms/impl/SysSmsSendLogServiceImpl.java | 30 +++- .../service/sms/impl/SysSmsServiceImpl.java | 21 ++- .../sms/impl/SysSmsTemplateServiceImpl.java | 7 + 12 files changed, 256 insertions(+), 195 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java deleted file mode 100644 index 05681d744..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsQueryLogDO.java +++ /dev/null @@ -1,140 +0,0 @@ -package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; - -import cn.iocoder.dashboard.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendFailureTypeEnum; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; - -import java.util.Date; -import java.util.Map; - -/** - * 短信发送日志 - * - * @author zzf - * @since 2021-01-25 - */ -@Data -@EqualsAndHashCode -@Accessors(chain = true) -@TableName(value = "sms_query_log", autoResultMap = true) -public class SysSmsQueryLogDO extends BaseDO { - - /** - * 自增编号 - */ - private Long id; - - // ========= 渠道相关字段 ========= - - /** - * 短信渠道编号 - * - * 关联 {@link SysSmsChannelDO#getId()} - */ - private Long channelId; - /** - * 短信渠道编码 - * - * 冗余 {@link SysSmsChannelDO#getCode()} - */ - private String channelCode; - /** - * 实际渠道模板唯一标识 - */ - private String apiTemplateId; - - // ========= 模板相关字段 ========= - - /** - * 短信模板编号 - * - * 关联 {@link} - */ - private String templateCode; - /** - * 短信类型 - * - * 枚举 {@link SysSmsTemplateTypeEnum} - */ - private Integer templateType; - /** - * 基于 {@link SysSmsTemplateDO#getContent()} 格式化后的内容 - */ - private String templateContent; - /** - * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容 - */ - private Map templateParams; - - // ========= 手机相关字段 ========= - - /** - * 手机号 - */ - private String mobile; - /** - * 用户编号 - */ - private Integer userId; - /** - * 用户类型 - * - * 枚举 {@link UserTypeEnum} - */ - private Integer userType; - - // ========= 发送相关字段 ========= - - /** - * 发送状态 - * - * 枚举 {@link SysSmsSendStatusEnum} - */ - private Integer sendStatus; - /** - * 发送失败的类型 - * - * 枚举 {@link SysSmsSendFailureTypeEnum} - */ - private Integer sendFailureType; - /** - * 发送成功时间 - */ - private Date sendTime; - /** - * 短信 API 发送失败的类型 - * - * 由于第三方的错误码可能是字符串,所以使用 String 类型 - */ - private String apiSendFailureType; - /** - * 短信 API 发送失败的提示 - */ - private String apiSendFailureMsg; - /** - * 短信 API 发送返回的唯一请求 ID - * - * 用于和短信 API 进行定位于排错 - */ - private String apiRequestId; - /** - * 短信 API 发送返回的序号 - * - * 用于和短信 API 平台的发送记录关联 - */ - private String apiSerialNo; - - // ========= 接收相关字段 ========= - - /** - * 是否获取过结果[0否 1是] - */ - private Integer gotResult; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java index e85edf74a..28c9f510f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java @@ -1,66 +1,148 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; +import cn.iocoder.dashboard.common.enums.UserTypeEnum; +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; +import lombok.*; -import java.io.Serializable; import java.util.Date; +import java.util.Map; /** - * 短信日志 + * 短信发送日志 * * @author zzf * @since 2021-01-25 */ -@Data -@EqualsAndHashCode -@Accessors(chain = true) @TableName(value = "sms_send_log", autoResultMap = true) -public class SysSmsSendLogDO implements Serializable { +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SysSmsSendLogDO extends BaseDO { /** * 自增编号 */ private Long id; + // ========= 渠道相关字段 ========= + /** - * 短信渠道编码(来自枚举类) + * 短信渠道编号 + * + * 关联 {@link SysSmsChannelDO#getId()} + */ + private Long channelId; + /** + * 短信渠道编码 + * + * 冗余 {@link SysSmsChannelDO#getCode()} */ private String channelCode; - /** - * 短信渠道id - */ - private Long channelId; + // ========= 模板相关字段 ========= /** - * 模板id + * 短信模板编号 + * + * 关联 {@link SysSmsTemplateDO#getId()} + */ + private Long templateId; + /** + * 模板编码 + * + * 冗余 {@link SysSmsTemplateDO#getCode()} */ private String templateCode; + /** + * 短信类型 + * + * 冗余 {@link SysSmsTemplateDO#getType()} + */ + private Integer templateType; + /** + * 基于 {@link SysSmsTemplateDO#getContent()} 格式化后的内容 + */ + private String templateContent; + /** + * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容 + */ + private Map templateParams; + /** + * 短信 API 的模板编号 + * + * 冗余 {@link SysSmsTemplateDO#getApiTemplateId()} + */ + private String apiTemplateId; + + // ========= 手机相关字段 ========= /** * 手机号 */ - private String phone; - + private String mobile; /** - * 备注 + * 用户编号 */ - private String remark; + private Long userId; + /** + * 用户类型 + * + * 枚举 {@link UserTypeEnum} + */ + private Integer userType; + + // ========= 发送相关字段 ========= /** * 发送状态 * - * @see SysSmsSendStatusEnum + * 枚举 {@link SysSmsSendStatusEnum} */ private Integer sendStatus; - /** - * 发送时间 + * 发送失败的类型 + * + * 枚举 {@link SysSmsSendFailureTypeEnum} + */ + private Integer sendFailureType; + /** + * 发送成功时间 */ private Date sendTime; + /** + * 短信 API 发送失败的类型 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiSendFailureType; + /** + * 短信 API 发送失败的提示 + */ + private String apiSendFailureMsg; + /** + * 短信 API 发送返回的唯一请求 ID + * + * 用于和短信 API 进行定位于排错 + */ + private String apiRequestId; + /** + * 短信 API 发送返回的序号 + * + * 用于和短信 API 平台的发送记录关联 + */ + private String apiSerialNo; + + // ========= 接收相关字段 ========= + + /** + * 是否获取过结果[0否 1是] + */ + private Integer gotResult; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java new file mode 100644 index 000000000..31d491d91 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java @@ -0,0 +1,66 @@ +package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; + +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 短信日志 + * + * @author zzf + * @since 2021-01-25 + */ +@Data +@EqualsAndHashCode +@Accessors(chain = true) +@TableName(value = "sms_send_log", autoResultMap = true) +public class SysSmsSendLogDOX implements Serializable { + + /** + * 自增编号 + */ + private Long id; + + /** + * 短信渠道编码(来自枚举类) + */ + private String channelCode; + + /** + * 短信渠道id + */ + private Long channelId; + + /** + * 模板id + */ + private String templateCode; + + /** + * 手机号 + */ + private String phone; + + /** + * 备注 + */ + private String remark; + + /** + * 发送状态 + * + * @see SysSmsSendStatusEnum + */ + private Integer sendStatus; + + /** + * 发送时间 + */ + private Date sendTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java index 2efd9ae8e..ba2b9940e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java @@ -51,6 +51,8 @@ public class SysSmsTemplateDO extends BaseDO { private String name; /** * 内容 + * + * 内容的参数,使用 {} 包括,例如说 {name} */ private String content; /** @@ -62,6 +64,10 @@ public class SysSmsTemplateDO extends BaseDO { * 备注 */ private String remark; + /** + * 短信 API 的模板编号 + */ + private String apiTemplateId; // ========= 渠道相关字段 ========= @@ -77,9 +83,5 @@ public class SysSmsTemplateDO extends BaseDO { * 冗余 {@link SysSmsChannelDO#getCode()} */ private String channelCode; - /** - * 短信 API 的模板编号 - */ - private String apiTemplateId; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java index 917a013a6..d1cf63efa 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; @@ -10,15 +10,15 @@ import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper -public interface SysSmsQueryLogMapper extends BaseMapper { +public interface SysSmsQueryLogMapper extends BaseMapper { /** * 查询还没有获取发送结果的短信请求信息 */ - default List selectNoResultQueryLogList() { - return this.selectList(new LambdaQueryWrapper() - .eq(SysSmsQueryLogDO::getSendStatus, SysSmsSendStatusEnum.QUERY_SUCCESS) - .eq(SysSmsQueryLogDO::getGotResult, DefaultBitFieldEnum.NO) + default List selectNoResultQueryLogList() { + return this.selectList(new LambdaQueryWrapper() + .eq(SysSmsSendLogDO::getSendStatus, SysSmsSendStatusEnum.QUERY_SUCCESS) + .eq(SysSmsSendLogDO::getGotResult, DefaultBitFieldEnum.NO) ); } @@ -26,9 +26,9 @@ public interface SysSmsQueryLogMapper extends BaseMapper { /** * 根据APIId修改对象 */ - default boolean updateByApiId(SysSmsQueryLogDO queryLogDO, String apiId) { - return update(queryLogDO, new LambdaQueryWrapper() - .eq(SysSmsQueryLogDO::getApiId, apiId) + default boolean updateByApiId(SysSmsSendLogDO queryLogDO, String apiId) { + return update(queryLogDO, new LambdaQueryWrapper() + .eq(SysSmsSendLogDO::getApiId, apiId) ) > 0; } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java index e5ec2fa3c..858bf977a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java @@ -5,8 +5,6 @@ import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import java.util.List; - /** * 短信请求日志服务接口 * @@ -14,6 +12,7 @@ import java.util.List; * @date 2021/1/25 9:24 */ public interface SysSmsQueryLogService { + /** * 发送短信前的日志处理 * @@ -22,10 +21,6 @@ public interface SysSmsQueryLogService { * @param client 短信客户端 * @return 生成的日志id */ - // TODO FROM 芋艿 to ZZF: async 是针对发送的方式,对于日志不一定需要关心。这样,短信日志,实际就发送前插入,发送后更新结果. - // 这里只用于记录状态,毕竟异步可能推送失败,此时日志可记录该状态。 - - // TODO FROM 芋艿 to ZZF:短信日志,群发的情况,应该是每个手机一条哈。虽然是群发,但是可能部分成功,部分失败;对应到短信平台,实际也是多条。 void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client); /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java index fe6f5e973..e36dd1f5c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java @@ -1,5 +1,9 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; + +import java.util.Map; + /** * 短信发送日志服务接口 * @@ -8,6 +12,9 @@ package cn.iocoder.dashboard.modules.system.service.sms; */ public interface SysSmsSendLogService { + Long createSmsSendLog(String mobile, Long userId, Integer userType, + SysSmsTemplateDO template, String templateContent, Map templateParams); + void getAndSaveSmsSendLog(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java index 137291a47..5faeeddcb 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java @@ -2,6 +2,8 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import java.util.Map; + /** * 短信模板 Service 接口 * @@ -18,4 +20,13 @@ public interface SysSmsTemplateService { */ SysSmsTemplateDO getSmsTemplateByCode(String code); + /** + * 格式化短信内容 + * + * @param content 短信模板的内容 + * @param params 内容的参数 + * @return 格式化后的内容 + */ + String formatSmsTemplateContent(String content, Map params); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java index 78935dba6..6aefcbb65 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java @@ -6,7 +6,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import org.springframework.stereotype.Service; @@ -27,7 +27,7 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { @Override public void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client) { - SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); + SysSmsSendLogDO smsLog = new SysSmsSendLogDO(); SmsChannelProperty property = client.getProperty(); smsLog.setChannelCode(property.getCode()) @@ -43,7 +43,7 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { @Override public void afterSendLog(Long logId, SmsResult result) { - SysSmsQueryLogDO smsLog = new SysSmsQueryLogDO(); + SysSmsSendLogDO smsLog = new SysSmsSendLogDO(); smsLog.setId(logId); smsLog.setApiId(result.getApiId()); smsLog.setSendStatus(SysSmsSendStatusEnum.QUERY_FAIL.getStatus()); @@ -53,7 +53,7 @@ public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { @Override public void updateSendLogByResultDetail(SmsResultDetail smsResultDetail) { - SysSmsQueryLogDO queryLogDO = new SysSmsQueryLogDO(); + SysSmsSendLogDO queryLogDO = new SysSmsSendLogDO(); queryLogDO.setSendStatus(smsResultDetail.getSendStatus()); queryLogDO.setSendTime(smsResultDetail.getSendTime()); queryLogDO.setRemark(smsResultDetail.getMessage()); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index 320c0a7bd..e8295a5cf 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -2,8 +2,9 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsQueryLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDOX; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; @@ -15,6 +16,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; +import java.util.Map; /** * 短信发送日志服务实现类 @@ -41,18 +43,36 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + @Override + public Long createSmsSendLog(String mobile, Long userId, Integer userType, + SysSmsTemplateDO template, String templateContent, Map templateParams) { + SysSmsSendLogDO.SysSmsSendLogDOBuilder logBuilder = SysSmsSendLogDO.builder(); + // 设置手机相关字段 + logBuilder.mobile(mobile).userId(userId).userType(userType); + // 设置模板相关字段 + logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType()); + logBuilder.templateContent(templateContent).templateParams(templateParams).apiTemplateId(template.getApiTemplateId()); + // 设置渠道相关字段 + logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode()); + + // 插入数据库 + SysSmsSendLogDO logDO = logBuilder.build(); + smsSendLogMapper.insert(logDO); + return logDO.getId(); + } + @Override public void getAndSaveSmsSendLog() { - List noResultQueryLogList = smsQueryLogMapper.selectNoResultQueryLogList(); + List noResultQueryLogList = smsQueryLogMapper.selectNoResultQueryLogList(); if (CollectionUtil.isEmpty(noResultQueryLogList)) { return; } //用于添加的发送日志对象 - SysSmsSendLogDO insertSendLog = new SysSmsSendLogDO(); + SysSmsSendLogDOX insertSendLog = new SysSmsSendLogDOX(); //用于修改状态的请求日志对象 - SysSmsQueryLogDO updateQueryLog = new SysSmsQueryLogDO(); + SysSmsSendLogDO updateQueryLog = new SysSmsSendLogDO(); noResultQueryLogList.forEach(queryLog -> { AbstractSmsClient smsClient = smsChannelService.getSmsClient(queryLog.getTemplateCode()); @@ -94,7 +114,7 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { }); } - private void queryLog2SendLong(SysSmsSendLogDO insertSendLog, SysSmsQueryLogDO queryLog) { + private void queryLog2SendLong(SysSmsSendLogDOX insertSendLog, SysSmsSendLogDO queryLog) { insertSendLog.setChannelCode(queryLog.getChannelCode()); insertSendLog.setChannelId(queryLog.getChannelId()); insertSendLog.setTemplateCode(queryLog.getTemplateCode()); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 64f9e3c8c..dde2580a4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -11,10 +11,7 @@ import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsSendStreamProducer; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; +import cn.iocoder.dashboard.modules.system.service.sms.*; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import org.springframework.stereotype.Service; @@ -40,6 +37,9 @@ public class SysSmsServiceImpl implements SysSmsService { @Resource private SysSmsTemplateService smsTemplateService; + @Resource + private SysSmsSendLogService smsSendLogService; + @Resource private SysUserService userService; @@ -63,7 +63,13 @@ public class SysSmsServiceImpl implements SysSmsService { SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); // 校验手机号码是否存在 mobile = this.checkMobile(mobile, userId, userType); - // + + // 创建发送日志 + String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); + Long sendLogId = smsSendLogService.createSmsSendLog(mobile, userId, userType, template, content, templateParams); + + // 发送 MQ 消息 + } @Override @@ -73,6 +79,11 @@ public class SysSmsServiceImpl implements SysSmsService { SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); } + @Override + public void doSendSms() { + + } + private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map templateParams) { // 短信模板不存在 SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index ccbb26079..c5c1a5127 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -1,11 +1,13 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.Map; /** * 短信模板Service实现类 @@ -24,4 +26,9 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return smsTemplateMapper.selectOneByCode(code); } + @Override + public String formatSmsTemplateContent(String content, Map params) { + return StrUtil.format(content, params); + } + } From 46ed64ba4048e5e6bf24b791b6af5addf10b996a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 28 Mar 2021 18:07:55 +0800 Subject: [PATCH 20/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-28=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8F=91=E9=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/core/SmsClientFactory.java | 2 +- .../sms/core/enums/SmsChannelEnum.java | 21 ++++++------ .../core/enums/SmsSendFailureTypeEnum.java | 26 +++++++++++++++ .../dal/dataobject/sms/SysSmsSendLogDO.java | 4 +-- .../enums/sms/SysSmsSendFailureTypeEnum.java | 19 ----------- ...reamConsumer.java => SmsSendConsumer.java} | 22 +++++++++---- .../mq/consumer/sms/SysSmsSendConsumer.java | 17 ---------- .../mq/message/sms/SysSmsSendMessage.java | 25 ++++++++------- ...treamProducer.java => SysSmsProducer.java} | 18 +++++------ .../service/sms/SysSmsSendLogService.java | 8 +++++ .../system/service/sms/SysSmsService.java | 4 ++- .../sms/impl/SysSmsSendLogServiceImpl.java | 6 +++- .../service/sms/impl/SysSmsServiceImpl.java | 32 ++++++++----------- 13 files changed, 108 insertions(+), 96 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java rename src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/{SmsSendStreamConsumer.java => SmsSendConsumer.java} (69%) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java rename src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/{SmsSendStreamProducer.java => SysSmsProducer.java} (57%) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java index bd41cc2ee..2350bda88 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java @@ -55,7 +55,7 @@ public class SmsClientFactory { throw new ServiceException(INVALID_CHANNEL_CODE); } switch (channelEnum) { - case ALI: + case ALIYUN: return new AliyunSmsClient(channelVO); case YUN_PIAN: return new YunpianSmsClient(channelVO); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 0265f455e..213034882 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.enums; +import cn.hutool.core.util.ArrayUtil; import lombok.AllArgsConstructor; import lombok.Getter; @@ -13,22 +14,22 @@ import lombok.Getter; @AllArgsConstructor public enum SmsChannelEnum { - ALI("ALI", "阿里"), YUN_PIAN("YUN_PIAN", "云片"), - HUA_WEI("HUA_WEI", "华为"), - TENCENT("TENCENT", "腾讯"); + ALIYUN("ALIYUN", "阿里云"), + TENCENT("TENCENT", "腾讯云"), + HUA_WEI("HUA_WEI", "华为云"),; + /** + * 编码 + */ private final String code; - + /** + * 名字 + */ private final String name; public static SmsChannelEnum getByCode(String code) { - for (SmsChannelEnum value : SmsChannelEnum.values()) { - if (value.getCode().equals(code)) { - return value; - } - } - return null; + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values()); } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java new file mode 100644 index 000000000..572ee3908 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.dashboard.framework.sms.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的发送失败类型的枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum SmsSendFailureTypeEnum { + + // ========== 模板相关(100 开头) ========== + SMS_TEMPLATE_DISABLE(100), // 短信模板被禁用 + + // ========== 其它相关 ========== + ; + + /** + * 失败类型 + */ + private final int type; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java index 28c9f510f..7147b8d7a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; @@ -108,7 +108,7 @@ public class SysSmsSendLogDO extends BaseDO { /** * 发送失败的类型 * - * 枚举 {@link SysSmsSendFailureTypeEnum} + * 枚举 {@link SmsSendFailureTypeEnum} */ private Integer sendFailureType; /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java deleted file mode 100644 index 8548e92ae..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendFailureTypeEnum.java +++ /dev/null @@ -1,19 +0,0 @@ -package cn.iocoder.dashboard.modules.system.enums.sms; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 短信的发送失败类型的枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum SysSmsSendFailureTypeEnum { - - ; - - private final int type; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java similarity index 69% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index bbd5de462..63c4bc59e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendStreamConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -1,10 +1,13 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms; +import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import cn.iocoder.dashboard.util.json.JsonUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.stream.ObjectRecord; @@ -14,14 +17,14 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; /** - * 短信发送流消息监听器 + * 针对 {@link SysSmsSendMessage} 的消费者 * * @author zzf * @date 2021/3/9 16:35 */ -@Slf4j @Component -public class SmsSendStreamConsumer implements StreamListener> { +@Slf4j +public class SmsSendConsumer extends AbstractStreamMessageListener { @Resource private SysSmsChannelService smsChannelService; @@ -29,15 +32,22 @@ public class SmsSendStreamConsumer implements StreamListener record) { - SmsSendMessage message = record.getValue(); - SmsBody body = message.getSmsBody(); - log.info("[onMessage][收到 发送短信 消息], content: " + JsonUtils.toJsonString(body)); AbstractSmsClient smsClient = smsChannelService.getSmsClient(body.getTemplateCode()); String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(body.getTemplateCode()); SmsResult result = smsClient.send(templateApiId, body, message.getTargetPhone()); smsQueryLogService.afterSendLog(body.getSmsLogId(), result); } + + @Override + public void onMessage(SysSmsSendMessage message) { + log.info("[onMessage][消息内容({})]", message); + smsService.doSendSms(message); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java deleted file mode 100644 index e3b18ca75..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.dashboard.modules.system.mq.consumer.sms; - -import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; -import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -public class SysSmsSendConsumer extends AbstractStreamMessageListener { - - @Override - public void onMessage(SysSmsSendMessage message) { - log.info("[onMessage][消息内容({})]", message); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java index f47b52466..40cc80ba5 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java @@ -14,30 +14,31 @@ import java.util.Map; @Data public class SysSmsSendMessage implements StreamMessage { + /** + * 发送日志编号 + */ + @NotNull(message = "发送日志编号不能为空") + private Long sendLogId; /** * 手机号 */ @NotNull(message = "手机号不能为空") private String mobile; /** - * 短信模板编号 + * 短信渠道编号 */ - @NotNull(message = "短信模板编号不能为空") - private String templateCode; + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + /** + * 短信 API 的模板编号 + */ + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; /** * 短信模板参数 */ private Map templateParams; - /** - * 用户编号,允许空 - */ - private Integer userId; - /** - * 用户类型,允许空 - */ - private Integer userType; - @Override public String getStreamKey() { return "system.sms.send"; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java similarity index 57% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java index 891a844cc..257de549c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SmsSendStreamProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java @@ -17,7 +17,7 @@ import java.util.Map; */ @Slf4j @Component -public class SmsSendStreamProducer { +public class SysSmsProducer { @Resource private StringRedisTemplate stringRedisTemplate; @@ -25,17 +25,17 @@ public class SmsSendStreamProducer { /** * 发送短信 Message * + * @param sendLogId 发送日志编号 * @param mobile 手机号 - * @param templateCode 短信模板编号 + * @param channelId 渠道编号 + * @param apiTemplateId 短信模板编号 * @param templateParams 短信模板参数 - * @param userId 用户编号 - * @param userType 用户类型 + * @param sendLogId 发送日志编号 */ - public void sendSmsSendMessage(String mobile, String templateCode, Map templateParams, - Integer userId, Integer userType) { - SysSmsSendMessage message = new SysSmsSendMessage(); - message.setMobile(mobile).setTemplateCode(templateCode).setTemplateParams(templateParams); - message.setUserId(userId).setUserType(userType); + public void sendSmsSendMessage(Long sendLogId, String mobile, + Long channelId, String apiTemplateId, Map templateParams) { + SysSmsSendMessage message = new SysSmsSendMessage().setSendLogId(sendLogId).setMobile(mobile); + message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java index e36dd1f5c..baf76b7a0 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java @@ -15,6 +15,14 @@ public interface SysSmsSendLogService { Long createSmsSendLog(String mobile, Long userId, Integer userType, SysSmsTemplateDO template, String templateContent, Map templateParams); + /** + * 更新发送日志为失败 + * + * @param id 发送日志编号 + * @param sendFailureType 失败类型 + */ + void updateSmsSendLogFailure(Long id, Integer sendFailureType); + void getAndSaveSmsSendLog(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index d4958f79b..34fcf4e9c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -1,5 +1,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; + import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; @@ -19,7 +21,7 @@ public interface SysSmsService { void sendBatchSms(List mobiles, List userIds, Integer userType, String templateCode, Map templateParams); - void doSendSms(); + void doSendSms(SysSmsSendMessage message); /** * 处理短信发送回调函数 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index e8295a5cf..cfceda947 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -42,7 +42,6 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { */ private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; - @Override public Long createSmsSendLog(String mobile, Long userId, Integer userType, SysSmsTemplateDO template, String templateContent, Map templateParams) { @@ -61,6 +60,11 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { return logDO.getId(); } + @Override + public void updateSmsSendLogFailure(Long id, Integer sendFailureType) { + smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendFailureType(sendFailureType)); + } + @Override public void getAndSaveSmsSendLog() { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index dde2580a4..b06e99cec 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -1,16 +1,16 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; -import cn.iocoder.dashboard.modules.system.mq.producer.sms.SmsSendStreamProducer; +import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; +import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; import cn.iocoder.dashboard.modules.system.service.sms.*; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import org.springframework.stereotype.Service; @@ -20,8 +20,6 @@ import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Predicate; import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @@ -51,7 +49,7 @@ public class SysSmsServiceImpl implements SysSmsService { private SysSmsQueryLogService logService; @Resource - private SmsSendStreamProducer smsProducer; + private SysSmsProducer smsProducer; @Resource private SmsClientFactory smsClientFactory; @@ -68,8 +66,13 @@ public class SysSmsServiceImpl implements SysSmsService { String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); Long sendLogId = smsSendLogService.createSmsSendLog(mobile, userId, userType, template, content, templateParams); - // 发送 MQ 消息 - + // 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。 + if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) { + smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE.getType()); + return; + } + // 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台 + smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), templateParams); } @Override @@ -79,11 +82,6 @@ public class SysSmsServiceImpl implements SysSmsService { SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); } - @Override - public void doSendSms() { - - } - private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map templateParams) { // 短信模板不存在 SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode); @@ -132,10 +130,8 @@ public class SysSmsServiceImpl implements SysSmsService { } @Override - public void send(SmsBody smsBody, String targetPhone) { - AbstractSmsClient client = channelService.getSmsClient(smsBody.getTemplateCode()); - logService.beforeSendLog(smsBody, targetPhone, client); - smsProducer.sendSmsSendMessage(smsBody, targetPhone); + public void doSendSms(SysSmsSendMessage message) { + } @Override From 515fca5c41819e8187167c483e05d21cd4b4b029 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 28 Mar 2021 22:49:14 +0800 Subject: [PATCH 21/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-28=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8F=91=E9=80=81=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 + .../sms/client/AbstractSmsClient.java | 67 --------- .../sms/config/SmsConfiguration.java | 21 +++ .../dashboard/framework/sms/core/SmsBody.java | 38 ----- .../framework/sms/core/SmsClientFactory.java | 133 ------------------ .../framework/sms/core/SmsConstants.java | 1 + .../framework/sms/core/SmsResult.java | 64 ++++++--- .../sms/{ => core}/client/SmsClient.java | 22 ++- .../sms/core/client/SmsClientFactory.java | 28 ++++ .../core/client/impl/AbstractSmsClient.java | 89 ++++++++++++ .../client/impl/SmsClientFactoryImpl.java | 83 +++++++++++ .../client/impl/aliyun}/AliyunSmsClient.java | 80 +++++------ .../client/impl/yunpian/YunpianSmsClient.java | 105 +++++++------- .../core/enums/SmsSendFailureTypeEnum.java | 13 +- .../core/property/SmsChannelProperties.java | 52 +++++++ .../sms/core/property/SmsChannelProperty.java | 68 --------- .../core/property/SmsTemplateProperty.java | 47 ------- .../sms/vo/req/SmsChannelPageReqVO.java | 3 - .../system/convert/sms/SmsChannelConvert.java | 13 +- .../convert/sms/SmsTemplateConvert.java | 3 - .../dal/dataobject/sms/SysSmsChannelDO.java | 66 ++++----- .../dal/dataobject/sms/SysSmsSendLogDO.java | 13 +- .../dal/dataobject/sms/SysSmsSendLogDOX.java | 66 --------- .../dal/mysql/sms/SysSmsChannelMapper.java | 24 ++-- .../dal/mysql/sms/SysSmsQueryLogMapper.java | 34 ----- .../dal/mysql/sms/SysSmsSendLogMapper.java | 5 +- .../mq/consumer/sms/SmsSendConsumer.java | 23 --- .../service/sms/SysSmsChannelService.java | 24 ---- .../service/sms/SysSmsQueryLogService.java | 35 ----- .../service/sms/SysSmsSendLogService.java | 32 ++++- .../sms/impl/SysSmsChannelServiceImpl.java | 87 ++++-------- .../sms/impl/SysSmsQueryLogServiceImpl.java | 63 --------- .../sms/impl/SysSmsSendLogServiceImpl.java | 91 ++---------- .../service/sms/impl/SysSmsServiceImpl.java | 48 ++++--- 34 files changed, 579 insertions(+), 965 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java rename src/main/java/cn/iocoder/dashboard/framework/sms/{ => core}/client/SmsClient.java (57%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java rename src/main/java/cn/iocoder/dashboard/framework/sms/{client/impl/ali => core/client/impl/aliyun}/AliyunSmsClient.java (73%) rename src/main/java/cn/iocoder/dashboard/framework/sms/{ => core}/client/impl/yunpian/YunpianSmsClient.java (60%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java diff --git a/pom.xml b/pom.xml index 83d372add..949978260 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ 2.2.7 2.2 1.0.5 + @@ -271,6 +272,8 @@ ${screw.version} + + com.yunpian.sdk diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java deleted file mode 100644 index fbeceea10..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/AbstractSmsClient.java +++ /dev/null @@ -1,67 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.client; - -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import lombok.extern.slf4j.Slf4j; - -/** - * 抽象短息客户端 - * - * @author zzf - * @date 2021/2/1 9:28 - */ -@Slf4j -public abstract class AbstractSmsClient implements SmsClient { - - /** - * 短信渠道参数 - */ - protected final SmsChannelProperty channelVO; - - /** - * 短信客户端有参构造函数 - * - * @param property 短信配置 - */ - public AbstractSmsClient(SmsChannelProperty property) { - this.channelVO = property; - } - - public SmsChannelProperty getProperty() { - return channelVO; - } - - @Override - public final SmsResult send(String templateApiId, SmsBody smsBody, String target) { - SmsResult result; - try { - beforeSend(templateApiId, smsBody, target); - result = doSend(templateApiId, smsBody, target); - afterSend(templateApiId, smsBody, target, result); - } catch (Exception e) { - // exception handle - log.debug(e.getMessage(), e); - return SmsResult.failResult("发送异常: " + e.getMessage()); - } - return result; - } - - /** - * 发送消息 - * - * @param templateApiId 短信模板唯一标识 - * @param smsBody 消息内容 - * @param targetPhone 发送对象手机号 - * @return 短信发送结果 - * @throws Exception 调用发送失败,抛出异常 - */ - protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception; - - protected void beforeSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { - } - - protected void afterSend(String templateApiId, SmsBody smsBody, String targetPhone, SmsResult result) throws Exception { - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java new file mode 100644 index 000000000..e5441c91f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.framework.sms.config; + +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.client.impl.SmsClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 短信配置类 + * + * @author 芋道源码 + */ +@Configuration +public class SmsConfiguration { + + @Bean + public SmsClientFactory smsClientFactory() { + return new SmsClientFactoryImpl(); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java deleted file mode 100644 index f82f0e142..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsBody.java +++ /dev/null @@ -1,38 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core; - -import cn.iocoder.dashboard.util.json.JsonUtils; -import lombok.Data; - -import java.util.Map; - -/** - * 消息内容实体类 - */ -@Data -public class SmsBody { - - /** - * 消息日志id - */ - private Long smsLogId; - - /** - * 模板编码 - */ - private String templateCode; - - /** - * 模板编码 - */ - private String templateContent; - - /** - * 参数列表 - */ - private Map params; - - public String getParamsStr() { - return JsonUtils.toJsonString(params); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java deleted file mode 100644 index 2350bda88..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsClientFactory.java +++ /dev/null @@ -1,133 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core; - -import cn.iocoder.dashboard.common.exception.ServiceException; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.client.impl.ali.AliyunSmsClient; -import cn.iocoder.dashboard.framework.sms.client.impl.yunpian.YunpianSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; -import cn.iocoder.dashboard.util.json.JsonUtils; -import org.springframework.stereotype.Component; - -import javax.servlet.ServletRequest; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; - -/** - * 短信客户端工厂 - * - * @author zzf - * @date 2021/1/28 14:01 - */ -@Component -public class SmsClientFactory { - - /** - * channelId: client map - * 保存 渠道id: 对应短信客户端 的map - */ - private final Map smsSenderMap = new ConcurrentHashMap<>(8); - - /** - * templateCode: TemplateProperty map - * 保存 模板编码:模板信息 的map - */ - private final Map templatePropertyMap = new ConcurrentHashMap<>(16); - - /** - * 创建短信客户端 - * - * @param propertyVO 参数对象 - * @return 客户端id(默认channelId) - */ - public Long createClient(SmsChannelProperty propertyVO) { - AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO); - smsSenderMap.put(propertyVO.getId(), sender); - return propertyVO.getId(); - } - - private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) { - if (channelEnum == null) { - throw new ServiceException(INVALID_CHANNEL_CODE); - } - switch (channelEnum) { - case ALIYUN: - return new AliyunSmsClient(channelVO); - case YUN_PIAN: - return new YunpianSmsClient(channelVO); - // TODO fill more channel - default: - break; - } - throw new ServiceException(SMS_SENDER_NOT_FOUND); - } - - /** - * 获取短信客户端 - * - * @param channelId 渠道id - * @return 短信id - */ - public AbstractSmsClient getClient(Long channelId) { - return smsSenderMap.get(channelId); - } - - - /** - * 添加或修改短信模板信息缓存 - */ - public void addOrUpdateTemplateCache(Collection templateProperties) { - templateProperties.forEach(this::addOrUpdateTemplateCache); - } - - - /** - * 添加或修改短信模板信息缓存 - */ - public void addOrUpdateTemplateCache(SmsTemplateProperty templateProperty) { - templatePropertyMap.put(templateProperty.getCode(), templateProperty); - } - - - /** - * 根据短信模板编码获取模板唯一标识 - * - * @param templateCode 短信模板编码 - * @return 短信id - */ - public String getTemplateApiIdByCode(String templateCode) { - SmsTemplateProperty smsTemplateProperty = templatePropertyMap.get(templateCode); - if (smsTemplateProperty == null) { - throw new ServiceException(SMS_TEMPLATE_NOT_EXISTS); - } - return smsTemplateProperty.getApiTemplateId(); - } - - - /** - * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId - * - * @param callbackRequest 短信发送回调函数请求 - * @return 第三方平台短信唯一标识 - */ - public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) { - for (Long channelId : smsSenderMap.keySet()) { - AbstractSmsClient smsClient = smsSenderMap.get(channelId); - try { - SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest); - if (smsSendResult != null) { - return smsSendResult; - } - } catch (Exception ignored) { - } - } - throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: " - + JsonUtils.toJsonString(callbackRequest.getParameterMap())); - } - - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java index e519306f3..139cc6736 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java @@ -15,4 +15,5 @@ public interface SmsConstants { String COMMA = ","; String SUCCESS = "SUCCESS"; + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 228630348..1754b897d 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -1,7 +1,8 @@ package cn.iocoder.dashboard.framework.sms.core; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import lombok.Data; -import lombok.experimental.Accessors; import java.io.Serializable; @@ -9,33 +10,64 @@ import java.io.Serializable; * 消息内容实体类 */ @Data -@Accessors(chain = true) public class SmsResult implements Serializable { /** - * 是否成功(发送短信的请求是否成功) + * 是否成功 + * + * 注意,是调用 API 短信平台的请求是否成功 */ private Boolean success; + /** + * 发送失败的类型 + * + * 枚举 {@link SmsSendFailureTypeEnum#getType()} + */ + private Integer sendFailureType; + /** + * 发送失败的提示 + * + * 一般情况下,使用 {@link SmsSendFailureTypeEnum#getMsg()} + * 异常情况下,通过格式化 Exception 的提示存储 + */ + private String sendFailureMsg; /** - * 第三方唯一标识 + * 短信 API 发送的错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 */ - private String apiId; - + private String apiSendCode; /** - * 状态码 + * 短信 API 发送的提示 */ - private String code; - + private String apiSendMsg; /** - * 提示 + * 短信 API 发送返回的唯一请求 ID + * + * 用于和短信 API 进行定位于排错 */ - private String message; + private String apiRequestId; + /** + * 短信 API 发送返回的序号 + * + * 用于和短信 API 平台的发送记录关联 + */ + private String apiSerialNo; - public static SmsResult failResult(String message) { - SmsResult resultBody = new SmsResult(); - resultBody.setSuccess(false); - resultBody.setMessage(message); - return resultBody; + private SmsResult() { } + + public static SmsResult success(SmsSendFailureTypeEnum sendFailureType, + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { + return new SmsResult().setSuccess(true).setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()) + .setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + } + + public static SmsResult error(Throwable ex) { + return new SmsResult().setSuccess(false) + .setSendFailureType(SmsSendFailureTypeEnum.SMS_SEND_EXCEPTION.getType()) + .setSendFailureMsg(ExceptionUtil.getRootCauseMessage(ex)); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java similarity index 57% rename from src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index ff8e6e72f..2933a11a0 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -1,28 +1,36 @@ -package cn.iocoder.dashboard.framework.sms.client; +package cn.iocoder.dashboard.framework.sms.core.client; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import javax.servlet.ServletRequest; +import java.util.Map; /** - * 短信父接口 + * 短信客户端接口 * * @author zzf * @date 2021/1/25 14:14 */ public interface SmsClient { + /** + * 获得渠道编号 + * + * @return 渠道编号 + */ + Long getId(); + /** * 发送消息 * - * @param templateApiId 短信模板唯一标识 - * @param smsBody 消息内容 - * @param targets 发送对象列表 + * @param sendLogId 发送日志编号 + * @param mobile 手机号 + * @param apiTemplateId 短信 API 的模板编号 + * @param templateParams 短信模板参数 * @return 短信发送结果 */ - SmsResult send(String templateApiId, SmsBody smsBody, String targets); + SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams); // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX /** diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java new file mode 100644 index 000000000..f4bc87dd4 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java @@ -0,0 +1,28 @@ +package cn.iocoder.dashboard.framework.sms.core.client; + +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; + +/** + * 短信客户端工厂接口 + * + * @author zzf + * @date 2021/1/28 14:01 + */ +public interface SmsClientFactory { + + /** + * 获得短信 Client + * + * @param channelId 渠道编号 + * @return 短信 Client + */ + SmsClient getSmsClient(Long channelId); + + /** + * 创建短信 Client + * + * @param properties 配置对象 + */ + void createOrUpdateSmsClient(SmsChannelProperties properties); + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java new file mode 100644 index 000000000..c8bd94e7a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -0,0 +1,89 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl; + +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +/** + * 短信客户端抽象类 + * + * @author zzf + * @date 2021/2/1 9:28 + */ +@Slf4j +public abstract class AbstractSmsClient implements SmsClient { + + /** + * 短信渠道配置 + */ + protected volatile SmsChannelProperties properties; + + /** + * 短信客户端有参构造函数 + * + * @param properties 短信配置 + */ + public AbstractSmsClient(SmsChannelProperties properties) { + this.properties = properties; + } + + /** + * 初始化 + */ + public final void init() { + doInit(); + log.info("[init][配置({}) 初始化完成]", properties); + } + + public final void refresh(SmsChannelProperties properties) { + // 判断是否更新 + if (!properties.equals(this.properties)) { + return; + } + log.info("[refresh][配置({})发生变化,重新初始化]", properties); + this.properties = properties; + // 初始化 + this.init(); + } + + /** + * 自定义初始化 + */ + protected abstract void doInit(); + + @Override + public Long getId() { + return properties.getId(); + } + + @Override + public final SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) { + SmsResult result; + try { + result = doSend(sendLogId, mobile, apiTemplateId, templateParams); + } catch (Throwable ex) { + // 打印异常日志 + log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", + sendLogId, mobile, apiTemplateId, templateParams, ex); + // 封装返回 + return SmsResult.error(ex); + } + return result; + } + + /** + * 发送消息 + * + * @param sendLogId 发送日志编号 + * @param mobile 手机号 + * @param apiTemplateId 短信 API 的模板编号 + * @param templateParams 短信模板参数 + * @return 短信发送结果 + */ + protected abstract SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) + throws Throwable; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java new file mode 100644 index 000000000..ddfe2302f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -0,0 +1,83 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl; + +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 短信客户端工厂接口 + * + * @author zzf + */ +@Validated +@Slf4j +public class SmsClientFactoryImpl implements SmsClientFactory { + + /** + * 短信客户端 Map + * key:渠道编号,使用 {@link SmsChannelProperties#getId()} + */ + private final Map clients = new ConcurrentHashMap<>(); + + @Override + public SmsClient getSmsClient(Long channelId) { + return clients.get(channelId); + } + + @Override + public void createOrUpdateSmsClient(SmsChannelProperties properties) { + AbstractSmsClient client = clients.get(properties.getId()); + if (client == null) { + client = this.createSmsClient(properties); + clients.put(client.getId(), client); + } else { + client.refresh(properties); + } + } + + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) { + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode()); + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum)); + // 创建客户端 + switch (channelEnum) { + case ALIYUN: + return new AliyunSmsClient(properties); + case YUN_PIAN: + return new YunpianSmsClient(properties); + } + // 创建失败,错误日志 + 抛出异常 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties); + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties)); + } + +// /** +// * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId +// * +// * @param callbackRequest 短信发送回调函数请求 +// * @return 第三方平台短信唯一标识 +// */ +// public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) { +// for (Long channelId : clients.keySet()) { +// AbstractSmsClient smsClient = clients.get(channelId); +// try { +// SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest); +// if (smsSendResult != null) { +// return smsSendResult; +// } +// } catch (Exception ignored) { +// } +// } +// throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: " +// + JsonUtils.toJsonString(callbackRequest.getParameterMap())); +// } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index 11301ebf6..a2af47ffb 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/ali/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -1,19 +1,15 @@ -package cn.iocoder.dashboard.framework.sms.client.impl.ali; +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; -import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import com.fasterxml.jackson.core.type.TypeReference; @@ -28,7 +24,7 @@ import java.util.List; import java.util.Map; /** - * 阿里短信实现类 + * 阿里短信客户端的实现类 * * @author zzf * @date 2021/1/25 14:17 @@ -36,54 +32,54 @@ import java.util.Map; @Slf4j public class AliyunSmsClient extends AbstractSmsClient { - private static final String OK = "OK"; - private static final String PRODUCT = "Dystopi"; - private static final String DOMAIN = "dysmsapi.aliyuncs.com"; - private static final String ENDPOINT = "cn-hangzhou"; - private final IAcsClient acsClient; + private static final String OK = "OK"; /** - * 构造阿里云短信发送处理 - * - * @param channelVO 阿里云短信配置 + * 阿里云客户端 */ - public AliyunSmsClient(SmsChannelProperty channelVO) { - super(channelVO); + private volatile IAcsClient acsClient; - String accessKeyId = channelVO.getApiKey(); - String accessKeySecret = channelVO.getApiSecret(); + public AliyunSmsClient(SmsChannelProperties properties) { + super(properties); + } - IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); + @Override + protected void doInit() { + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); - acsClient = new DefaultAcsClient(profile); } @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { - SendSmsRequest request = new SendSmsRequest(); - request.setSysMethod(MethodType.POST); - request.setPhoneNumbers(targetPhone); - request.setSignName(channelVO.getApiSignatureId()); - request.setTemplateCode(templateApiId); - request.setTemplateParam(smsBody.getParamsStr()); - SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); - - boolean success = OK.equals(sendSmsResponse.getCode()); - if (!success) { - log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); - } - return new SmsResult() - .setSuccess(success) - .setMessage(sendSmsResponse.getMessage()) - .setCode(sendSmsResponse.getCode()) - .setApiId(sendSmsResponse.getBizId()); + protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { + return null; } +// @Override +// public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { +// SendSmsRequest request = new SendSmsRequest(); +// request.setSysMethod(MethodType.POST); +// request.setPhoneNumbers(targetPhone); +// request.setSignName(properties.getSignature()); +// request.setTemplateCode(templateApiId); +// request.setTemplateParam(smsBody.getParamsStr()); +// SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); +// +// boolean success = OK.equals(sendSmsResponse.getCode()); +// if (!success) { +// log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); +// } +// return new SmsResult() +// .setSuccess(success) +// .setMessage(sendSmsResponse.getMessage()) +// .setCode(sendSmsResponse.getCode()) +// .setApiId(sendSmsResponse.getBizId()); +// } + /** * [{ * "send_time" : "2017-08-30 00:00:00", @@ -131,8 +127,8 @@ public class AliyunSmsClient extends AbstractSmsClient { public Integer getSendStatus() { return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) - ? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SysSmsSendStatusEnum.SEND_FAIL.getStatus(); + ? SysSmsSendStatusEnum.SUCCESS.getStatus() + : SysSmsSendStatusEnum.FAILURE.getStatus(); } public String getBizId() { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java similarity index 60% rename from src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 1164439de..dfadd573a 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -1,19 +1,20 @@ -package cn.iocoder.dashboard.framework.sms.client.impl.yunpian; +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; +import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.fasterxml.jackson.core.type.TypeReference; import com.yunpian.sdk.YunpianClient; -import com.yunpian.sdk.constant.Code; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; import com.yunpian.sdk.model.SmsSingleSend; @@ -25,9 +26,10 @@ import java.net.URLEncoder; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.StringJoiner; /** - * 云片短信实现类 + * 云片短信客户端的实现类 * * @author zzf * @date 9:48 2021/3/5 @@ -35,71 +37,59 @@ import java.util.Map; @Slf4j public class YunpianSmsClient extends AbstractSmsClient { - private final YunpianClient client; + /** + * 云信短信客户端 + */ + private volatile YunpianClient client; private final TypeReference>> callbackType = new TypeReference>>() { }; - /** - * 构造云片短信发送处理 - * - * @param channelVO 阿里云短信配置 - */ - public YunpianSmsClient(SmsChannelProperty channelVO) { - super(channelVO); - client = new YunpianClient(channelVO.getApiKey()); + public YunpianSmsClient(SmsChannelProperties properties) { + super(properties); } @Override - public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) { - Map paramMap = new HashMap<>(); - paramMap.put(YunpianConstant.APIKEY, getProperty().getApiKey()); - paramMap.put(YunpianConstant.MOBILE, String.join(SmsConstants.COMMA, targetPhone)); - paramMap.put(YunpianConstant.TEXT, formatContent(smsBody)); - paramMap.put(Helper.CALLBACK, getProperty().getCallbackUrl()); + public void doInit() { + client = new YunpianClient(properties.getApiKey()); + } - Result sendResult = client.sms().single_send(paramMap); - boolean success = sendResult.getCode().equals(Code.OK); + @Override + protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Throwable { + // 构建参数 + Map request = new HashMap<>(); + request.put(YunpianConstant.APIKEY, properties.getApiKey()); + request.put(YunpianConstant.MOBILE, mobile); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); + request.put(YunpianConstant.UID, String.valueOf(sendLogId)); + request.put(Helper.CALLBACK, properties.getCallbackUrl()); - if (!success) { - log.debug("send fail[code={}, message={}]", sendResult.getCode(), sendResult.getDetail()); + // 执行发送 + Result sendResult = client.sms().tpl_single_send(request); + if (sendResult.getThrowable() != null) { + throw sendResult.getThrowable(); } - return new SmsResult() - .setSuccess(success) - .setMessage(sendResult.getDetail()) - .setCode(sendResult.getCode().toString()) - .setApiId(sendResult.getData().getSid().toString()); + // 解析结果 + SmsSingleSend data = sendResult.getData(); + return SmsResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码 + String.valueOf(data.getCode()), data.getMsg(), null, String.valueOf(data.getSid())); } - - /** - * 格式化短信内容,将参数注入到模板中 - * - * @param smsBody 短信信息 - * @return 格式化后的短信内容 - */ - private String formatContent(SmsBody smsBody) { - StringBuilder result = new StringBuilder(smsBody.getTemplateContent()); - smsBody.getParams().forEach((key, val) -> { - String param = parseParamToPlaceholder(key); - result.replace(result.indexOf(param), result.indexOf(param + param.length()), val); - }); - return result.toString(); + private static String formatTplValue(Map templateParams) { + if (CollUtil.isEmpty(templateParams)) { + return ""; + } + // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化 + StringJoiner joiner = new StringJoiner("&"); + templateParams.forEach((key, value) -> joiner.add(String.format("#%s#=%s", key, URLUtil.encode(String.valueOf(value))))); + return joiner.toString(); } - /** - * 将指定参数改成对应的占位字符 - *

- * 云片的是 #param# 的形式作为占位符 - * - * @param key 参数名 - * @return 对应的占位字符 - */ - private String parseParamToPlaceholder(String key) { - return SmsConstants.JING_HAO + key + SmsConstants.JING_HAO; + private static SmsSendFailureTypeEnum parseSendFailureType(Result sendResult) { + return SmsSendFailureTypeEnum.SMS_UNKNOWN; } - /** * 云片的比较复杂,又是加密又是套娃的 */ @@ -109,7 +99,6 @@ public class YunpianSmsClient extends AbstractSmsClient { return Helper.getSmsResultDetailByParam(map); } - /** * 从 request 中获取请求中传入的短信发送结果信息 * @@ -155,8 +144,8 @@ public class YunpianSmsClient extends AbstractSmsClient { private static int getSendStatus(Map map) { String reportStatus = map.get(REPORT_STATUS); return SmsConstants.SUCCESS.equals(reportStatus) - ? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() - : SysSmsSendStatusEnum.SEND_FAIL.getStatus(); + ? SysSmsSendStatusEnum.SUCCESS.getStatus() + : SysSmsSendStatusEnum.FAILURE.getStatus(); } public static SmsResultDetail getSmsResultDetailByParam(Map map) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java index 572ee3908..82ce1e836 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java @@ -13,14 +13,23 @@ import lombok.Getter; public enum SmsSendFailureTypeEnum { // ========== 模板相关(100 开头) ========== - SMS_TEMPLATE_DISABLE(100), // 短信模板被禁用 + SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"), - // ========== 其它相关 ========== + // ========== 模板相关(200 开头) ========== + SMS_TEMPLATE_DISABLE(200, "短信模板被禁用"), + + // ========== 其它相关(900 开头) ========== + SMS_SEND_EXCEPTION(900, "发送异常"), + SMS_UNKNOWN(999, "未知错误,需要解析") ; /** * 失败类型 */ private final int type; + /** + * 失败提示 + */ + private final String msg; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java new file mode 100644 index 000000000..750f2e7b4 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperties.java @@ -0,0 +1,52 @@ +package cn.iocoder.dashboard.framework.sms.core.property; + +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * 短信渠道配置类 + * + * @author zzf + * @date 2021/1/25 17:01 + */ +@Data +@Validated +public class SmsChannelProperties { + + /** + * 渠道编号 + */ + @NotNull(message = "短信渠道 ID 不能为空") + private Long id; + /** + * 短信签名 + */ + @NotEmpty(message = "短信签名不能为空") + private String signature; + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + @NotEmpty(message = "渠道编码不能为空") + private String code; + /** + * 短信 API 的账号 + */ + @NotEmpty(message = "短信 API 的账号不能为空") + private String apiKey; + /** + * 短信 API 的秘钥 + */ + @NotEmpty(message = "短信 API 的秘钥不能为空") + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java deleted file mode 100644 index 1c7ff2305..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsChannelProperty.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.property; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.util.List; - -/** - * 渠道(包含模板)信息VO类 - * - * @author zzf - * @date 2021/1/25 17:01 - */ -@Data -@EqualsAndHashCode -public class SmsChannelProperty implements Serializable { - - /** - * id - */ - @NotNull(message = "短信渠道ID不能为空") - private Long id; - - /** - * 编码(来自枚举类 阿里、华为、七牛等) - */ - @NotEmpty(message = "短信渠道编码不能为空") - private String code; - - /** - * 渠道账号id - */ - @NotEmpty(message = "渠道账号id不能为空") - private String apiKey; - - /** - * 渠道账号秘钥 - */ - @NotEmpty(message = "渠道账号秘钥不能为空") - private String apiSecret; - - /** - * 实际渠道签名唯一标识 - */ - @NotEmpty(message = "实际渠道签名唯一标识不能为空") - private String apiSignatureId; - - /** - * 签名值 - */ - @NotEmpty(message = "签名值不能为空") - private String signature; - - /** - * 是否拥有回调函数(0否 1是) - */ - @NotNull(message = "是否拥有回调函数不能为空") - private Integer hadCallback; - - /** - * 短信发送回调url - */ - private String callbackUrl; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java deleted file mode 100644 index ebd3a7a95..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/property/SmsTemplateProperty.java +++ /dev/null @@ -1,47 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.property; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -import javax.validation.constraints.NotEmpty; - -/** - * 渠道模板VO类 - * - * @author zzf - * @date 2021/1/25 17:03 - */ -@Data -@EqualsAndHashCode -public class SmsTemplateProperty { - - /** - * 渠道id - */ - @NotEmpty(message = "短信渠道编码不能为空") - private Long channelId; - - /** - * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板) - */ - private String bizCode; - - /** - * 编码 - */ - @NotEmpty(message = "短信模板编码不能为空") - private String code; - - /** - * 实际渠道模板唯一标识 - */ - @NotEmpty(message = "短信模板唯一标识不能为空") - private String apiTemplateId; - - /** - * 内容 - */ - @NotEmpty(message = "短信模板内容不能为空") - private String content; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java index 19e2987fe..9b941edf3 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java @@ -15,9 +15,6 @@ import lombok.NoArgsConstructor; @EqualsAndHashCode(callSuper = true) public class SmsChannelPageReqVO extends PageParam { - @ApiModelProperty(value = "渠道名", example = "阿里", notes = "模糊匹配") - private String name; - @ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配") private String signature; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index 833c1919c..43d72b471 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -1,16 +1,13 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; -import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import com.baomidou.mybatisplus.core.metadata.IPage; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; import java.util.List; @@ -20,9 +17,6 @@ public interface SmsChannelConvert { SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); - @Mapping(source = "records", target = "list") - PageResult convertPage(IPage page); - SysSmsChannelDO convert(SmsChannelCreateReqVO bean); SysSmsChannelDO convert(SysUserUpdateReqVO bean); @@ -31,9 +25,8 @@ public interface SmsChannelConvert { List convert(List bean); - List convertProperty(List list); - - List convertProperties(List list); + List convertProperty(List list); + List convertList(List list); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java index 2ff680028..788fc8e19 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java @@ -1,7 +1,6 @@ package cn.iocoder.dashboard.modules.system.convert.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; @@ -24,6 +23,4 @@ public interface SmsTemplateConvert { SmsTemplateVO convert(SysSmsTemplateDO bean); - List convertProperty(List bean); - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java index 48acf346f..4bca7e517 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java @@ -1,70 +1,58 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; - /** * 短信渠道 * * @author zzf * @since 2021-01-25 */ +@TableName(value = "sms_channel", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) -@TableName(value = "sms_channel", autoResultMap = true) public class SysSmsChannelDO extends BaseDO { /** - * 自增编号 + * 渠道编号 */ private Long id; - /** - * 编码(来自枚举类 阿里、华为、七牛等) - */ - private String code; - - /** - * 短信发送回调url - */ - private String callback_url; - - /** - * 渠道账号id - */ - private String apiKey; - - /** - * 渠道账号秘钥 - */ - private String apiSecret; - - /** - * 实际渠道签名唯一标识 - */ - private String apiSignatureId; - - /** - * 名称 - */ - private String name; - - /** - * 签名值 + * 短信签名 */ private String signature; - + /** + * 渠道编码 + * + * 枚举 {@link SmsChannelEnum} + */ + private String code; + /** + * 启用状态 + * + * 枚举 {@link CommonStatusEnum} + */ + private Integer status; /** * 备注 */ private String remark; - /** - * 启用状态(0正常 1停用) + * 短信 API 的账号 */ - private Integer status; + private String apiKey; + /** + * 短信 API 的秘钥 + */ + private String apiSecret; + /** + * 短信发送回调 URL + */ + private String callbackUrl; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java index 7147b8d7a..53e725634 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java @@ -105,16 +105,23 @@ public class SysSmsSendLogDO extends BaseDO { * 枚举 {@link SysSmsSendStatusEnum} */ private Integer sendStatus; + /** + * 时间发送时间 + */ + private Date sendTime; /** * 发送失败的类型 * - * 枚举 {@link SmsSendFailureTypeEnum} + * 枚举 {@link SmsSendFailureTypeEnum#getType()} */ private Integer sendFailureType; /** - * 发送成功时间 + * 发送失败的提示 + * + * 一般情况下,使用 {@link SmsSendFailureTypeEnum#getMsg()} + * 异常情况下,通过格式化 Exception 的提示存储 */ - private Date sendTime; + private String sendFailureMsg; /** * 短信 API 发送失败的类型 * diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java deleted file mode 100644 index 31d491d91..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDOX.java +++ /dev/null @@ -1,66 +0,0 @@ -package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; - -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.Date; - -/** - * 短信日志 - * - * @author zzf - * @since 2021-01-25 - */ -@Data -@EqualsAndHashCode -@Accessors(chain = true) -@TableName(value = "sms_send_log", autoResultMap = true) -public class SysSmsSendLogDOX implements Serializable { - - /** - * 自增编号 - */ - private Long id; - - /** - * 短信渠道编码(来自枚举类) - */ - private String channelCode; - - /** - * 短信渠道id - */ - private Long channelId; - - /** - * 模板id - */ - private String templateCode; - - /** - * 手机号 - */ - private String phone; - - /** - * 备注 - */ - private String remark; - - /** - * 发送状态 - * - * @see SysSmsSendStatusEnum - */ - private Integer sendStatus; - - /** - * 发送时间 - */ - private Date sendTime; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java index e601ebc5c..e6371e9c9 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java @@ -1,31 +1,27 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.common.enums.CommonStatusEnum; -import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper -public interface SysSmsChannelMapper extends BaseMapper { +public interface SysSmsChannelMapper extends BaseMapperX { - default IPage selectChannelPage(SmsChannelPageReqVO reqVO) { - return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper() - .like(StrUtil.isNotBlank(reqVO.getName()), SysSmsChannelDO::getName, reqVO.getName()) - .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getName, reqVO.getSignature()) - ); + default PageResult selectChannelPage(SmsChannelPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapper() + .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getSignature, reqVO.getSignature())); } - default List selectEnabledList() { + default List selectListByStatus(Integer status) { return selectList(new LambdaQueryWrapper() - .eq(SysSmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SysSmsChannelDO::getId) - ); + .eq(SysSmsChannelDO::getStatus, status) + .orderByAsc(SysSmsChannelDO::getId)); } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java deleted file mode 100644 index d1cf63efa..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsQueryLogMapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package cn.iocoder.dashboard.modules.system.dal.mysql.sms; - -import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -@Mapper -public interface SysSmsQueryLogMapper extends BaseMapper { - - /** - * 查询还没有获取发送结果的短信请求信息 - */ - default List selectNoResultQueryLogList() { - return this.selectList(new LambdaQueryWrapper() - .eq(SysSmsSendLogDO::getSendStatus, SysSmsSendStatusEnum.QUERY_SUCCESS) - .eq(SysSmsSendLogDO::getGotResult, DefaultBitFieldEnum.NO) - ); - } - - - /** - * 根据APIId修改对象 - */ - default boolean updateByApiId(SysSmsSendLogDO queryLogDO, String apiId) { - return update(queryLogDO, new LambdaQueryWrapper() - .eq(SysSmsSendLogDO::getApiId, apiId) - ) > 0; - } -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java index 3a5c7fbb8..74d713d48 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java @@ -1,10 +1,9 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SysSmsSendLogMapper extends BaseMapper { - +public interface SysSmsSendLogMapper extends BaseMapperX { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java index 63c4bc59e..1e63ca662 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java @@ -1,17 +1,9 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms; import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; -import cn.iocoder.dashboard.util.json.JsonUtils; import lombok.extern.slf4j.Slf4j; -import org.springframework.data.redis.connection.stream.ObjectRecord; -import org.springframework.data.redis.stream.StreamListener; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -26,24 +18,9 @@ import javax.annotation.Resource; @Slf4j public class SmsSendConsumer extends AbstractStreamMessageListener { - @Resource - private SysSmsChannelService smsChannelService; - - @Resource - private SysSmsQueryLogService smsQueryLogService; - @Resource private SysSmsService smsService; - @Override - public void onMessage(ObjectRecord record) { - AbstractSmsClient smsClient = smsChannelService.getSmsClient(body.getTemplateCode()); - String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(body.getTemplateCode()); - - SmsResult result = smsClient.send(templateApiId, body, message.getTargetPhone()); - smsQueryLogService.afterSendLog(body.getSmsLogId(), result); - } - @Override public void onMessage(SysSmsSendMessage message) { log.info("[onMessage][消息内容({})]", message); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index 5224adb9a..e720e363f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -1,8 +1,6 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; @@ -46,26 +44,4 @@ public interface SysSmsChannelService { */ List getSmsChannelEnums(); - /** - * 根据短信模板编码获取短信客户端 - * - * @param templateCode 短信模板编码 - * @return 短信客户端 - */ - AbstractSmsClient getSmsClient(String templateCode); - - /** - * 根据短信模板编码获取模板唯一标识 - * - * @param templateCode 短信模板编码 - * @return 短信客户端 - */ - String getSmsTemplateApiIdByCode(String templateCode); - - /** - * 查询渠道(包含名下模块)信息集合 - * - * @return 渠道(包含名下模块)信息集合 - */ - List listSmsChannelAllEnabledInfo(); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java deleted file mode 100644 index 858bf977a..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsQueryLogService.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.dashboard.modules.system.service.sms; - -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; - -/** - * 短信请求日志服务接口 - * - * @author zzf - * @date 2021/1/25 9:24 - */ -public interface SysSmsQueryLogService { - - /** - * 发送短信前的日志处理 - * - * @param smsBody 短信内容 - * @param targetPhone 发送对象手机号 - * @param client 短信客户端 - * @return 生成的日志id - */ - void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client); - - /** - * 发送消息后的日志处理 - * - * @param logId 日志id - * @param result 消息结果 - */ - void afterSendLog(Long logId, SmsResult result); - - void updateSendLogByResultDetail(SmsResultDetail smsResultDetail); -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java index baf76b7a0..29118cb8c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import java.util.Map; @@ -12,17 +13,38 @@ import java.util.Map; */ public interface SysSmsSendLogService { + /** + * 创建发送日志 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param template 短信模板 + * @param templateContent 短信内容 + * @param templateParams 短信参数 + * @return + */ Long createSmsSendLog(String mobile, Long userId, Integer userType, SysSmsTemplateDO template, String templateContent, Map templateParams); /** - * 更新发送日志为失败 + * 更新发送日志的结果 * - * @param id 发送日志编号 - * @param sendFailureType 失败类型 + * @param id 日志编号 + * @param success 是否成功 + * @param sendFailureType 发送失败的类型 + * @param sendFailureMsg 发送失败的提示 + * @param apiSendFailureType 短信 API 发送失败的类型 + * @param apiSendFailureMsg 短信 API 发送失败的提示 + * @param apiRequestId 短信 API 发送返回的唯一请求 ID + * @param apiSerialNo 短信 API 发送返回的序号 */ - void updateSmsSendLogFailure(Long id, Integer sendFailureType); + void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg, + String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo); - void getAndSaveSmsSendLog(); + default void updateSmsSendLogFailure(Long id, SmsSendFailureTypeEnum sendFailureType) { + updateSmsSendLogResult(id, false, sendFailureType.getType(), sendFailureType.getMsg(), + null, null, null, null); + } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index 6026320f9..930a7db9c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java @@ -1,32 +1,24 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; -import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsChannelMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * 短信渠道Service实现类 @@ -37,10 +29,8 @@ import java.util.concurrent.ConcurrentHashMap; @Service public class SysSmsChannelServiceImpl implements SysSmsChannelService { - private final Map templateCode2ChannelIdMap = new ConcurrentHashMap<>(32); - @Resource - private SmsClientFactory clientFactory; + private SmsClientFactory smsClientFactory; @Resource private SysSmsChannelMapper channelMapper; @@ -48,30 +38,19 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { @Resource private SysSmsTemplateMapper templateMapper; - - @PostConstruct @Override + @PostConstruct public void initSmsClientAndCacheSmsTemplate() { // 查询有效渠道信息 - List channelDOList = channelMapper.selectEnabledList(); - List propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList); - - // 遍历渠道生成client、获取模板并缓存 - propertyList.forEach(channelProperty -> { - List templateDOList = templateMapper.selectListByChannelId(channelProperty.getId()); - if (ObjectUtil.isNotEmpty(templateDOList)) { - Long clientId = clientFactory.createClient(channelProperty); - templateDOList.forEach(template -> templateCode2ChannelIdMap.put(template.getCode(), clientId)); - - List templatePropertyList = SmsTemplateConvert.INSTANCE.convertProperty(templateDOList); - clientFactory.addOrUpdateTemplateCache(templatePropertyList); - } - }); + List channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + // 创建渠道 Client + List propertiesList = SmsChannelConvert.INSTANCE.convertList(channelDOList); + propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); } @Override public PageResult pageSmsChannels(SmsChannelPageReqVO reqVO) { - return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO)); + return channelMapper.selectChannelPage(reqVO); } @Override @@ -86,30 +65,20 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); } - @Override - public AbstractSmsClient getSmsClient(String templateCode) { - return clientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); - } - - @Override - public String getSmsTemplateApiIdByCode(String templateCode) { - return clientFactory.getTemplateApiIdByCode(templateCode); - } - - @Override - public List listSmsChannelAllEnabledInfo() { - List channelDOList = channelMapper.selectEnabledList(); - if (ObjectUtil.isNull(channelDOList)) { - return null; - } - List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); - channelAllVOList.forEach(smsChannelDO -> { - List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); - if (ObjectUtil.isNull(templateDOList)) { - templateDOList = new ArrayList<>(); - } - smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList)); - }); - return channelAllVOList; - } +// @Override +// public List listSmsChannelAllEnabledInfo() { +// List channelDOList = channelMapper.selectListByStatus(); +// if (ObjectUtil.isNull(channelDOList)) { +// return null; +// } +// List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); +// channelAllVOList.forEach(smsChannelDO -> { +// List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); +// if (ObjectUtil.isNull(templateDOList)) { +// templateDOList = new ArrayList<>(); +// } +// smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList)); +// }); +// return channelAllVOList; +// } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java deleted file mode 100644 index 6aefcbb65..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsQueryLogServiceImpl.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.dashboard.modules.system.service.sms.impl; - -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.SmsBody; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; -import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; - -/** - * 短信请求日志服务实现类 - * - * @author zzf - * @date 13:50 2021/3/2 - */ -@Service -public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService { - - @Resource - private SysSmsQueryLogMapper logMapper; - - @Override - public void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client) { - SysSmsSendLogDO smsLog = new SysSmsSendLogDO(); - SmsChannelProperty property = client.getProperty(); - - smsLog.setChannelCode(property.getCode()) - .setChannelId(property.getId()) - .setTemplateCode(smsBody.getTemplateCode()) - .setPhone(targetPhone) - .setContent(smsBody.getParams().toString()); - - smsLog.setSendStatus(SysSmsSendStatusEnum.ASYNC.getStatus()); - logMapper.insert(smsLog); - smsBody.setSmsLogId(smsLog.getId()); - } - - @Override - public void afterSendLog(Long logId, SmsResult result) { - SysSmsSendLogDO smsLog = new SysSmsSendLogDO(); - smsLog.setId(logId); - smsLog.setApiId(result.getApiId()); - smsLog.setSendStatus(SysSmsSendStatusEnum.QUERY_FAIL.getStatus()); - smsLog.setRemark(result.getCode() + ": " + result.getMessage()); - logMapper.updateById(smsLog); - } - - @Override - public void updateSendLogByResultDetail(SmsResultDetail smsResultDetail) { - SysSmsSendLogDO queryLogDO = new SysSmsSendLogDO(); - queryLogDO.setSendStatus(smsResultDetail.getSendStatus()); - queryLogDO.setSendTime(smsResultDetail.getSendTime()); - queryLogDO.setRemark(smsResultDetail.getMessage()); - logMapper.updateByApiId(queryLogDO, smsResultDetail.getApiId()); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index cfceda947..b57912bd4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -1,22 +1,17 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.hutool.core.collection.CollectionUtil; -import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDOX; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsQueryLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.util.List; +import java.util.Date; import java.util.Map; +import java.util.Objects; /** * 短信发送日志服务实现类 @@ -28,20 +23,9 @@ import java.util.Map; @Service public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { - @Resource - private SysSmsQueryLogMapper smsQueryLogMapper; - @Resource private SysSmsSendLogMapper smsSendLogMapper; - @Resource - private SysSmsChannelService smsChannelService; - - /** - * 定时执行 {@link #getSmsSendResultJob()} 的周期 - */ - private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; - @Override public Long createSmsSendLog(String mobile, Long userId, Integer userType, SysSmsTemplateDO template, String templateContent, Map templateParams) { @@ -61,71 +45,12 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { } @Override - public void updateSmsSendLogFailure(Long id, Integer sendFailureType) { - smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendFailureType(sendFailureType)); + public void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg, + String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo) { + SysSmsSendStatusEnum sendStatus = Objects.equals(success, true) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE; + smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendStatus(sendStatus.getStatus()).setSendTime(new Date()) + .setSendFailureType(sendFailureType).setSendFailureMsg(sendFailureMsg) + .setApiSendFailureType(apiSendFailureType).setApiSendFailureMsg(apiSendFailureMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo)); } - @Override - public void getAndSaveSmsSendLog() { - - List noResultQueryLogList = smsQueryLogMapper.selectNoResultQueryLogList(); - - if (CollectionUtil.isEmpty(noResultQueryLogList)) { - return; - } - //用于添加的发送日志对象 - SysSmsSendLogDOX insertSendLog = new SysSmsSendLogDOX(); - //用于修改状态的请求日志对象 - SysSmsSendLogDO updateQueryLog = new SysSmsSendLogDO(); - - noResultQueryLogList.forEach(queryLog -> { - AbstractSmsClient smsClient = smsChannelService.getSmsClient(queryLog.getTemplateCode()); - - updateQueryLog.setId(queryLog.getId()); - - // 只处理实现了获取发送结果方法的短信客户端,理论上这里都是满足条件的,以防万一加个判断。 - /*if (smsClient instanceof NeedQuerySendResultSmsClient) { - //初始化点字段值 - queryLog2SendLong(insertSendLog, queryLog); - - NeedQuerySendResultSmsClient querySendResultSmsClient = (NeedQuerySendResultSmsClient) smsClient; - try { - List smsSendResult = querySendResultSmsClient.getSmsSendResult(queryLog.getRemark()); - smsSendResult.forEach(resultDetail -> { - insertSendLog.setPhone(resultDetail.getPhone()); - insertSendLog.setSendStatus(resultDetail.getSendStatus()); - insertSendLog.setSendTime(resultDetail.getSendTime()); - insertSendLog.setRemark(resultDetail.getMessage()); - smsSendLogMapper.insert(insertSendLog); - }); - } catch (Exception e) { - //exception handle - log.error("query send result fail, exception: " + e.getMessage()); - - updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); - updateQueryLog.setRemark(e.getMessage()); - smsQueryLogMapper.updateById(updateQueryLog); - return; - } - } else { - //理论上这里都是满足条件的,以防万一加个判断。 - updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus()); - smsQueryLogMapper.updateById(updateQueryLog); - }*/ - updateQueryLog.setSendStatus(SysSmsSendStatusEnum.SEND_SUCCESS.getStatus()); - updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId())); - smsQueryLogMapper.updateById(updateQueryLog); - }); - } - - private void queryLog2SendLong(SysSmsSendLogDOX insertSendLog, SysSmsSendLogDO queryLog) { - insertSendLog.setChannelCode(queryLog.getChannelCode()); - insertSendLog.setChannelId(queryLog.getChannelId()); - insertSendLog.setTemplateCode(queryLog.getTemplateCode()); - } - - @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) - public void getSmsSendResultJob() { - getAndSaveSmsSendLog(); - } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index b06e99cec..61a73ea71 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -4,15 +4,19 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; -import cn.iocoder.dashboard.modules.system.service.sms.*; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -31,29 +35,21 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; * @date 2021/1/25 9:25 */ @Service +@Slf4j public class SysSmsServiceImpl implements SysSmsService { @Resource private SysSmsTemplateService smsTemplateService; @Resource private SysSmsSendLogService smsSendLogService; + @Resource + private SysSmsProducer smsProducer; + @Resource + private SmsClientFactory smsClientFactory; @Resource private SysUserService userService; - @Resource - private SysSmsChannelService channelService; - - - @Resource - private SysSmsQueryLogService logService; - - @Resource - private SysSmsProducer smsProducer; - - @Resource - private SmsClientFactory smsClientFactory; - @Override public void sendSingleSms(String mobile, Long userId, Integer userType, String templateCode, Map templateParams) { @@ -68,7 +64,7 @@ public class SysSmsServiceImpl implements SysSmsService { // 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。 if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) { - smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE.getType()); + smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE); return; } // 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台 @@ -126,19 +122,31 @@ public class SysSmsServiceImpl implements SysSmsService { SysUserDO user = userService.getUser(userId); return user != null ? user.getMobile() : null; } + // TODO 芋艿:支持 C 端用户 return null; } @Override public void doSendSms(SysSmsSendMessage message) { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); + if (smsClient == null) { + log.error("[doSendSms][短信 message({}) 找不到对应的客户端]", message); + smsSendLogService.updateSmsSendLogFailure(message.getSendLogId(), SmsSendFailureTypeEnum.SMS_CHANNEL_CLIENT_NOT_EXISTS); + return; + } + // 发送短信 + SmsResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(), + message.getApiTemplateId(), message.getTemplateParams()); } @Override public Object smsSendCallbackHandle(ServletRequest request) { - SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); - logService.updateSendLogByResultDetail(smsResultDetail); - return smsResultDetail.getCallbackResponseBody(); +// SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); +// logService.updateSendLogByResultDetail(smsResultDetail); +// return smsResultDetail.getCallbackResponseBody(); + return null; } } From 52b51254fc1247531f319cdcf1d81dccb3d80d9e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 29 Mar 2021 00:22:42 +0800 Subject: [PATCH 22/54] =?UTF-8?q?=E4=BA=91=E7=89=87=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E7=9A=84=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/impl/yunpian/YunpianSmsClient.java | 37 +++++++++++++++++-- .../core/enums/SmsSendFailureTypeEnum.java | 11 ++++-- .../redis/core/stream/RedisStreamTest.java | 6 +-- .../YunpianSmsClientIntegrationTest.java | 36 ++++++++++++++++++ .../sms/core/client/package-info.java | 1 + 5 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java create mode 100644 src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/package-info.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index dfadd573a..00b64ad4c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsResult; @@ -28,6 +29,8 @@ import java.util.List; import java.util.Map; import java.util.StringJoiner; +import static com.yunpian.sdk.constant.Code.*; + /** * 云片短信客户端的实现类 * @@ -51,7 +54,15 @@ public class YunpianSmsClient extends AbstractSmsClient { @Override public void doInit() { - client = new YunpianClient(properties.getApiKey()); + YunpianClient oldClient = client; + // 初始化新的客户端 + YunpianClient newClient = new YunpianClient(properties.getApiKey()); + newClient.init(); + this.client = newClient; + // 销毁老的客户端 + if (oldClient != null) { + oldClient.close(); + } } @Override @@ -71,9 +82,8 @@ public class YunpianSmsClient extends AbstractSmsClient { throw sendResult.getThrowable(); } // 解析结果 - SmsSingleSend data = sendResult.getData(); return SmsResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码 - String.valueOf(data.getCode()), data.getMsg(), null, String.valueOf(data.getSid())); + String.valueOf(sendResult.getCode()), formatResultMsg(sendResult), null, getApiSerialNo(sendResult)); } private static String formatTplValue(Map templateParams) { @@ -86,10 +96,31 @@ public class YunpianSmsClient extends AbstractSmsClient { return joiner.toString(); } + private static String formatResultMsg(Result sendResult) { + if (StrUtil.isEmpty(sendResult.getDetail())) { + return sendResult.getMsg(); + } + return sendResult.getMsg() + " => " + sendResult.getDetail(); + } + private static SmsSendFailureTypeEnum parseSendFailureType(Result sendResult) { + Integer code = sendResult.getCode(); + switch (code) { + case ARGUMENT_MISSING: return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; + case BAD_ARGUMENT_FORMAT: return SmsSendFailureTypeEnum.SMS_TEMPLATE_PARAM_ERROR; + case TPL_NOT_FOUND: return SmsSendFailureTypeEnum.SMS_TEMPLATE_NOT_EXISTS; + case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TMPLATE_INVALID; + } return SmsSendFailureTypeEnum.SMS_UNKNOWN; } + private static String getApiSerialNo(Result sendResult) { + if (sendResult.getData() == null) { + return null; + } + return String.valueOf(sendResult.getData().getSid()); + } + /** * 云片的比较复杂,又是加密又是套娃的 */ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java index 82ce1e836..d014f5966 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java @@ -12,14 +12,19 @@ import lombok.Getter; @AllArgsConstructor public enum SmsSendFailureTypeEnum { - // ========== 模板相关(100 开头) ========== + // ========== 渠道相关(100 开头) ========== SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"), // ========== 模板相关(200 开头) ========== - SMS_TEMPLATE_DISABLE(200, "短信模板被禁用"), + SMS_TEMPLATE_NOT_EXISTS(200, "短信模板不存在"), + SMS_TEMPLATE_DISABLE(201, "短信模板被禁用"), // 例如说,我们在管理后台禁用了 + SMS_TMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 + SMS_TEMPLATE_PARAM_ERROR(203, "模板参数不正确"), // ========== 其它相关(900 开头) ========== - SMS_SEND_EXCEPTION(900, "发送异常"), + SMS_API_PARAM_ERROR(900, "请求参数缺失"), + + SMS_SEND_EXCEPTION(998, "发送异常"), SMS_UNKNOWN(999, "未知错误,需要解析") ; diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java index 1c193bbf2..c976528ae 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java @@ -4,7 +4,7 @@ import cn.hutool.core.thread.ThreadUtil; import cn.iocoder.dashboard.BaseRedisIntegrationTest; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; import cn.iocoder.dashboard.modules.system.mq.consumer.mail.SysMailSendConsumer; -import cn.iocoder.dashboard.modules.system.mq.consumer.sms.SysSmsSendConsumer; +import cn.iocoder.dashboard.modules.system.mq.consumer.sms.SmsSendConsumer; import cn.iocoder.dashboard.modules.system.mq.message.mail.SysMailSendMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import org.junit.jupiter.api.Disabled; @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; public class RedisStreamTest { - @Import({SysSmsSendConsumer.class, SysMailSendConsumer.class}) + @Import({SmsSendConsumer.class, SysMailSendConsumer.class}) @Disabled public static class ConsumerTest extends BaseRedisIntegrationTest { @@ -43,7 +43,7 @@ public class RedisStreamTest { for (int i = 0; i < 100; i++) { // 创建消息 SysSmsSendMessage message = new SysSmsSendMessage(); - message.setMobile("15601691300").setTemplateCode("test:" + i); + message.setMobile("15601691300").setApiTemplateId("test:" + i); // 发送消息 RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message); } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java new file mode 100644 index 000000000..af4a8b6a0 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java @@ -0,0 +1,36 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; + +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link YunpianSmsClient} 的集成测试 + */ +public class YunpianSmsClientIntegrationTest { + + @Test + public void testSend() { + // 创建配置类 + SmsChannelProperties properties = new SmsChannelProperties(); + properties.setId(1L); + properties.setSignature("芋道"); + properties.setCode(SmsChannelEnum.YUN_PIAN.getCode()); + properties.setApiKey("1555a14277cb8a608cf45a9e6a80d510"); + // 创建客户端 + YunpianSmsClient smsClient = new YunpianSmsClient(properties); + smsClient.init(); + // 发送短信 + Map templateParams = new HashMap<>(); + templateParams.put("code", "1024"); + templateParams.put("operation", "嘿嘿"); +// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); + SmsResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); + System.out.println(result); + } + +} diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/package-info.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/package-info.java new file mode 100644 index 000000000..037ce8ca2 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.dashboard.framework.sms.core.client; From 60911c9f56058ced79a55af6a8cbfa29a7fdf0bf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 30 Mar 2021 01:12:36 +0800 Subject: [PATCH 23/54] =?UTF-8?q?=E9=98=BF=E9=87=8C=E4=BA=91=E7=9F=AD?= =?UTF-8?q?=E4=BF=A1=E7=9A=84=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/core/SmsResult.java | 8 ++- .../client/impl/aliyun/AliyunSmsClient.java | 65 ++++++++++++------- .../client/impl/yunpian/YunpianSmsClient.java | 3 +- .../core/enums/SmsSendFailureTypeEnum.java | 5 +- .../impl/aliyun/AliyunSmsClientTest.java | 37 +++++++++++ 5 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java index 1754b897d..46c59033c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java @@ -60,8 +60,12 @@ public class SmsResult implements Serializable { public static SmsResult success(SmsSendFailureTypeEnum sendFailureType, String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { - return new SmsResult().setSuccess(true).setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()) - .setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + SmsResult result = new SmsResult().setSuccess(true).setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg) + .setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + if (sendFailureType != null) { + result.setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()); + } + return result; } public static SmsResult error(Throwable ex) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index a2af47ffb..f9f19a22e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -2,14 +2,20 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; +import com.aliyuncs.exceptions.ClientException; +import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import com.fasterxml.jackson.core.type.TypeReference; @@ -36,8 +42,6 @@ public class AliyunSmsClient extends AbstractSmsClient { private static final String DOMAIN = "dysmsapi.aliyuncs.com"; private static final String ENDPOINT = "cn-hangzhou"; - private static final String OK = "OK"; - /** * 阿里云客户端 */ @@ -56,29 +60,44 @@ public class AliyunSmsClient extends AbstractSmsClient { @Override protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { - return null; + // 构建参数 + SendSmsRequest request = new SendSmsRequest(); + request.setSysMethod(MethodType.POST); + request.setPhoneNumbers(mobile); + request.setSignName(properties.getSignature()); + request.setTemplateCode(apiTemplateId); + request.setTemplateParam(JsonUtils.toJsonString(templateParams)); + request.setOutId(String.valueOf(sendLogId)); + + try { + // 执行发送 + SendSmsResponse sendResult = acsClient.getAcsResponse(request); + // 解析结果 + return SmsResult.success(parseSendFailureType(sendResult.getCode()), // 将 API 短信平台,解析成统一的错误码 + sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), sendResult.getBizId()); + } catch (ClientException ex) { + return SmsResult.success(parseSendFailureType(ex.getErrCode()), // 将 API 短信平台,解析成统一的错误码 + ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null); + } } -// @Override -// public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { -// SendSmsRequest request = new SendSmsRequest(); -// request.setSysMethod(MethodType.POST); -// request.setPhoneNumbers(targetPhone); -// request.setSignName(properties.getSignature()); -// request.setTemplateCode(templateApiId); -// request.setTemplateParam(smsBody.getParamsStr()); -// SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); -// -// boolean success = OK.equals(sendSmsResponse.getCode()); -// if (!success) { -// log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage()); -// } -// return new SmsResult() -// .setSuccess(success) -// .setMessage(sendSmsResponse.getMessage()) -// .setCode(sendSmsResponse.getCode()) -// .setApiId(sendSmsResponse.getBizId()); -// } + private static SmsSendFailureTypeEnum parseSendFailureType(String code) { + switch (code) { + case "OK": return null; + case "MissingAccessKeyId": return SmsSendFailureTypeEnum.SMS_CHANNEL_API_KEY_MISSING; + case "isp.RAM_PERMISSION_DENY": return SmsSendFailureTypeEnum.SMS_CHANNEL_PERMISSION_DENY; + case "isv.INVALID_PARAMETERS": return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; + case "isv.BUSINESS_LIMIT_CONTROL": return SmsSendFailureTypeEnum.SMS_SEND_LIMIT_CONTROL; + } + return SmsSendFailureTypeEnum.SMS_UNKNOWN; + } + + private static String formatResultMsg(ClientException ex) { + if (StrUtil.isEmpty(ex.getErrorDescription())) { + return ex.getMessage(); + } + return ex.getErrMsg() + " => " + ex.getErrorDescription(); + } /** * [{ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 00b64ad4c..9e840f6ae 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -106,10 +106,11 @@ public class YunpianSmsClient extends AbstractSmsClient { private static SmsSendFailureTypeEnum parseSendFailureType(Result sendResult) { Integer code = sendResult.getCode(); switch (code) { + case OK: return null; case ARGUMENT_MISSING: return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; case BAD_ARGUMENT_FORMAT: return SmsSendFailureTypeEnum.SMS_TEMPLATE_PARAM_ERROR; case TPL_NOT_FOUND: return SmsSendFailureTypeEnum.SMS_TEMPLATE_NOT_EXISTS; - case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TMPLATE_INVALID; + case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TEMPLATE_INVALID; } return SmsSendFailureTypeEnum.SMS_UNKNOWN; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java index d014f5966..af29977fa 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java @@ -14,16 +14,19 @@ public enum SmsSendFailureTypeEnum { // ========== 渠道相关(100 开头) ========== SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"), + SMS_CHANNEL_API_KEY_MISSING(101, "API Key 不存在"), + SMS_CHANNEL_PERMISSION_DENY(102, "没有发送短信的权限"), // ========== 模板相关(200 开头) ========== SMS_TEMPLATE_NOT_EXISTS(200, "短信模板不存在"), SMS_TEMPLATE_DISABLE(201, "短信模板被禁用"), // 例如说,我们在管理后台禁用了 - SMS_TMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 + SMS_TEMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 SMS_TEMPLATE_PARAM_ERROR(203, "模板参数不正确"), // ========== 其它相关(900 开头) ========== SMS_API_PARAM_ERROR(900, "请求参数缺失"), + SMS_SEND_LIMIT_CONTROL(997, "业务限流"), // 将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 SMS_SEND_EXCEPTION(998, "发送异常"), SMS_UNKNOWN(999, "未知错误,需要解析") ; diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java new file mode 100644 index 000000000..b042365e4 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -0,0 +1,37 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * {@link AliyunSmsClient} 的集成测试 + */ +public class AliyunSmsClientTest { + + @Test + public void testSend() { + // 创建配置类 + SmsChannelProperties properties = new SmsChannelProperties(); + properties.setId(1L); + properties.setSignature("Ballcat"); + properties.setCode(SmsChannelEnum.ALIYUN.getCode()); + properties.setApiKey(System.getenv("ALIYUN_ACCESS_KEY")); + properties.setApiSecret(System.getenv("ALIYUN_SECRET_KEY")); + // 创建客户端 + AliyunSmsClient smsClient = new AliyunSmsClient(properties); + smsClient.init(); + // 发送短信 + Map templateParams = new HashMap<>(); + templateParams.put("code", "1024"); +// templateParams.put("operation", "嘿嘿"); +// SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); + SmsResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); + System.out.println(result); + } + +} From 9528698a5f875eabee5ab4c16935d24d97c7b6cd Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 31 Mar 2021 00:46:20 +0800 Subject: [PATCH 24/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-03-31=EF=BC=8C=E9=87=8D=E6=9E=84=E8=BF=94=E5=9B=9E=E7=9A=84?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/GlobalException.java | 41 ---------- .../dashboard/common/pojo/CommonResult.java | 15 +--- .../framework/sms/core/SmsConstants.java | 3 - .../framework/sms/core/SmsResult.java | 77 ------------------- .../framework/sms/core/client/SmsClient.java | 4 +- .../sms/core/client/SmsCommonResult.java | 59 ++++++++++++++ .../sms/core/client/dto/SmsSendRespDTO.java | 15 ++++ .../core/client/impl/AbstractSmsClient.java | 15 ++-- .../client/impl/aliyun/AliyunSmsClient.java | 8 +- .../client/impl/yunpian/YunpianSmsClient.java | 6 +- .../service/sms/impl/SysSmsServiceImpl.java | 4 +- .../impl/aliyun/AliyunSmsClientTest.java | 4 +- .../YunpianSmsClientIntegrationTest.java | 4 +- 13 files changed, 101 insertions(+), 154 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java diff --git a/src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java b/src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java deleted file mode 100644 index d4f9c945e..000000000 --- a/src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.dashboard.common.exception; - -import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - * 全局异常 Exception - */ -@Data -@EqualsAndHashCode(callSuper = true) -public class GlobalException extends RuntimeException { - - /** - * 全局错误码 - * - * @see GlobalErrorCodeConstants - */ - private Integer code; - /** - * 错误提示 - */ - private String message; - - /** - * 空构造方法,避免反序列化问题 - */ - public GlobalException() { - } - - public GlobalException(ErrorCode errorCode) { - this.code = errorCode.getCode(); - this.message = errorCode.getMessage(); - } - - public GlobalException(Integer code, String message) { - this.code = code; - this.message = message; - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java index 14e34070d..d6e50c65d 100644 --- a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java +++ b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java @@ -1,7 +1,6 @@ package cn.iocoder.dashboard.common.pojo; import cn.iocoder.dashboard.common.exception.ErrorCode; -import cn.iocoder.dashboard.common.exception.GlobalException; import cn.iocoder.dashboard.common.exception.ServiceException; import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -16,7 +15,7 @@ import java.io.Serializable; * @param 数据泛型 */ @Data -public final class CommonResult implements Serializable { +public class CommonResult implements Serializable { /** * 错误码 @@ -81,16 +80,12 @@ public final class CommonResult implements Serializable { // ========= 和 Exception 异常体系集成 ========= /** - * 判断是否有异常。如果有,则抛出 {@link GlobalException} 或 {@link ServiceException} 异常 + * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常 */ - public void checkError() throws GlobalException, ServiceException { + public void checkError() throws ServiceException { if (isSuccess()) { return; } - // 全局异常 - if (GlobalErrorCodeConstants.isMatch(code)) { - throw new GlobalException(code, msg); - } // 业务异常 throw new ServiceException(code, msg); } @@ -99,8 +94,4 @@ public final class CommonResult implements Serializable { return error(serviceException.getCode(), serviceException.getMessage()); } - public static CommonResult error(GlobalException globalException) { - return error(globalException.getCode(), globalException.getMessage()); - } - } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java index 139cc6736..c5351d68b 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java @@ -8,9 +8,6 @@ package cn.iocoder.dashboard.framework.sms.core; */ public interface SmsConstants { - String OK = "OK"; - - String JING_HAO = "#"; String COMMA = ","; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java deleted file mode 100644 index 46c59033c..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResult.java +++ /dev/null @@ -1,77 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core; - -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; -import lombok.Data; - -import java.io.Serializable; - -/** - * 消息内容实体类 - */ -@Data -public class SmsResult implements Serializable { - - /** - * 是否成功 - * - * 注意,是调用 API 短信平台的请求是否成功 - */ - private Boolean success; - /** - * 发送失败的类型 - * - * 枚举 {@link SmsSendFailureTypeEnum#getType()} - */ - private Integer sendFailureType; - /** - * 发送失败的提示 - * - * 一般情况下,使用 {@link SmsSendFailureTypeEnum#getMsg()} - * 异常情况下,通过格式化 Exception 的提示存储 - */ - private String sendFailureMsg; - - /** - * 短信 API 发送的错误码 - * - * 由于第三方的错误码可能是字符串,所以使用 String 类型 - */ - private String apiSendCode; - /** - * 短信 API 发送的提示 - */ - private String apiSendMsg; - /** - * 短信 API 发送返回的唯一请求 ID - * - * 用于和短信 API 进行定位于排错 - */ - private String apiRequestId; - /** - * 短信 API 发送返回的序号 - * - * 用于和短信 API 平台的发送记录关联 - */ - private String apiSerialNo; - - private SmsResult() { - } - - public static SmsResult success(SmsSendFailureTypeEnum sendFailureType, - String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { - SmsResult result = new SmsResult().setSuccess(true).setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg) - .setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); - if (sendFailureType != null) { - result.setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()); - } - return result; - } - - public static SmsResult error(Throwable ex) { - return new SmsResult().setSuccess(false) - .setSendFailureType(SmsSendFailureTypeEnum.SMS_SEND_EXCEPTION.getType()) - .setSendFailureMsg(ExceptionUtil.getRootCauseMessage(ex)); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index 2933a11a0..4a0d9aedc 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.framework.sms.core.client; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import javax.servlet.ServletRequest; import java.util.Map; @@ -30,7 +30,7 @@ public interface SmsClient { * @param templateParams 短信模板参数 * @return 短信发送结果 */ - SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams); + SmsCommonResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams); // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX /** diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java new file mode 100644 index 000000000..ffd8c5b0c --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java @@ -0,0 +1,59 @@ +package cn.iocoder.dashboard.framework.sms.core.client; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * 短信的 CommonResult 拓展类 + * + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段 + * + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段 + * + * @author 芋道源码 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SmsCommonResult extends CommonResult { + + /** + * API 返回错误码 + * + * 由于第三方的错误码可能是字符串,所以使用 String 类型 + */ + private String apiCode; + /** + * API 返回提示 + */ + private String apiMsg; + + /** + * API 请求编号 + */ + private String apiRequestId; + + private SmsCommonResult() { + } + + public static SmsCommonResult success(SmsSendFailureTypeEnum sendFailureType, + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { + SmsCommonResult result = new SmsCommonResult().setSuccess(true).setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg) + .setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); + if (sendFailureType != null) { + result.setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()); + } + return result; + } + + public static SmsCommonResult error(Throwable ex) { + return new SmsCommonResult().setSuccess(false) + .setSendFailureType(SmsSendFailureTypeEnum.SMS_SEND_EXCEPTION.getType()) + .setSendFailureMsg(ExceptionUtil.getRootCauseMessage(ex)); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java new file mode 100644 index 000000000..c3a28cb93 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java @@ -0,0 +1,15 @@ +package cn.iocoder.dashboard.framework.sms.core.client.dto; + +/** + * 短信发送响应 DTO + * + * @author 芋道源码 + */ +public class SmsSendRespDTO { + + /** + * 短信 API 发送返回的序号 + */ + private String serialNo; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index c8bd94e7a..d2b008b73 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -1,7 +1,8 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; @@ -60,8 +61,10 @@ public abstract class AbstractSmsClient implements SmsClient { } @Override - public final SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) { - SmsResult result; + public final SmsCommonResult send(Long sendLogId, String mobile, + String apiTemplateId, Map templateParams) { + // 执行短信发送 + SmsCommonResult result; try { result = doSend(sendLogId, mobile, apiTemplateId, templateParams); } catch (Throwable ex) { @@ -69,7 +72,7 @@ public abstract class AbstractSmsClient implements SmsClient { log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", sendLogId, mobile, apiTemplateId, templateParams, ex); // 封装返回 - return SmsResult.error(ex); + return SmsCommonResult.error(ex); } return result; } @@ -83,7 +86,7 @@ public abstract class AbstractSmsClient implements SmsClient { * @param templateParams 短信模板参数 * @return 短信发送结果 */ - protected abstract SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) - throws Throwable; + protected abstract SmsCommonResult doSend(Long sendLogId, String mobile, + String apiTemplateId, Map templateParams) throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index f9f19a22e..a0f903871 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -3,7 +3,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; @@ -59,7 +59,7 @@ public class AliyunSmsClient extends AbstractSmsClient { } @Override - protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { + protected SmsCommonResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { // 构建参数 SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); @@ -73,10 +73,10 @@ public class AliyunSmsClient extends AbstractSmsClient { // 执行发送 SendSmsResponse sendResult = acsClient.getAcsResponse(request); // 解析结果 - return SmsResult.success(parseSendFailureType(sendResult.getCode()), // 将 API 短信平台,解析成统一的错误码 + return SmsCommonResult.success(parseSendFailureType(sendResult.getCode()), // 将 API 短信平台,解析成统一的错误码 sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), sendResult.getBizId()); } catch (ClientException ex) { - return SmsResult.success(parseSendFailureType(ex.getErrCode()), // 将 API 短信平台,解析成统一的错误码 + return SmsCommonResult.success(parseSendFailureType(ex.getErrCode()), // 将 API 短信平台,解析成统一的错误码 ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null); } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 9e840f6ae..0d6a51021 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -7,7 +7,7 @@ import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.framework.sms.core.SmsConstants; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; @@ -66,7 +66,7 @@ public class YunpianSmsClient extends AbstractSmsClient { } @Override - protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Throwable { + protected SmsCommonResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Throwable { // 构建参数 Map request = new HashMap<>(); request.put(YunpianConstant.APIKEY, properties.getApiKey()); @@ -82,7 +82,7 @@ public class YunpianSmsClient extends AbstractSmsClient { throw sendResult.getThrowable(); } // 解析结果 - return SmsResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码 + return SmsCommonResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码 String.valueOf(sendResult.getCode()), formatResultMsg(sendResult), null, getApiSerialNo(sendResult)); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 61a73ea71..e722b4499 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; @@ -137,7 +137,7 @@ public class SysSmsServiceImpl implements SysSmsService { } // 发送短信 - SmsResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(), + SmsCommonResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(), message.getApiTemplateId(), message.getTemplateParams()); } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java index b042365e4..1c85031b6 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import org.junit.jupiter.api.Test; @@ -30,7 +30,7 @@ public class AliyunSmsClientTest { templateParams.put("code", "1024"); // templateParams.put("operation", "嘿嘿"); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); + SmsCommonResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); System.out.println(result); } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java index af4a8b6a0..028cd6c77 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; -import cn.iocoder.dashboard.framework.sms.core.SmsResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import org.junit.jupiter.api.Test; @@ -29,7 +29,7 @@ public class YunpianSmsClientIntegrationTest { templateParams.put("code", "1024"); templateParams.put("operation", "嘿嘿"); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); + SmsCommonResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); System.out.println(result); } From 5a1491d7fdc510c2fb20e85ad99d1a3e10c4dc92 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 1 Apr 2021 01:31:35 +0800 Subject: [PATCH 25/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-04-01=EF=BC=8C=E9=87=8D=E6=9E=84=E8=BF=94=E5=9B=9E=E7=9A=84?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/common/exception/ErrorCode.java | 7 +-- .../common/exception/ServiceException.java | 2 +- .../exception/util/ServiceExceptionUtil.java | 4 +- .../dashboard/common/pojo/CommonResult.java | 4 +- .../framework/sms/core/client/SmsClient.java | 2 +- .../sms/core/client/SmsCodeMapping.java | 17 ++++++++ .../sms/core/client/SmsCommonResult.java | 31 ++++++++----- .../{ => client/dto}/SmsResultDetail.java | 2 +- .../sms/core/client/dto/SmsSendRespDTO.java | 3 ++ .../core/client/impl/AbstractSmsClient.java | 8 +++- .../client/impl/aliyun/AliyunSmsClient.java | 30 +++++-------- .../impl/aliyun/AliyunSmsCodeMapping.java | 27 ++++++++++++ .../client/impl/yunpian/YunpianSmsClient.java | 40 ++++++----------- .../impl/yunpian/YunpianSmsCodeMapping.java | 30 +++++++++++++ .../sms/core/{ => enums}/SmsConstants.java | 2 +- .../enums/SmsFrameworkErrorCodeConstants.java | 32 ++++++++++++++ .../core/enums/SmsSendFailureTypeEnum.java | 43 ------------------- .../core/handler/GlobalExceptionHandler.java | 25 +---------- .../service/sms/SysSmsSendLogService.java | 1 - .../service/user/SysUserServiceImpl.java | 2 +- .../iocoder/dashboard/util/AssertUtils.java | 2 +- 21 files changed, 174 insertions(+), 140 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java rename src/main/java/cn/iocoder/dashboard/framework/sms/core/{ => client/dto}/SmsResultDetail.java (91%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java rename src/main/java/cn/iocoder/dashboard/framework/sms/core/{ => enums}/SmsConstants.java (75%) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java diff --git a/src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java b/src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java index 670029504..065aece7c 100644 --- a/src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java +++ b/src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java @@ -1,12 +1,13 @@ package cn.iocoder.dashboard.common.exception; +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange; import lombok.Data; /** * 错误码对象 * - * 全局错误码,占用 [0, 999],参见 {@link GlobalException} + * 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants} * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange} * * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 @@ -21,11 +22,11 @@ public class ErrorCode { /** * 错误提示 */ - private final String message; + private final String msg; public ErrorCode(Integer code, String message) { this.code = code; - this.message = message; + this.msg = message; } } diff --git a/src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java b/src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java index 83c43ca2e..2e2adec75 100644 --- a/src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java +++ b/src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java @@ -30,7 +30,7 @@ public final class ServiceException extends RuntimeException { public ServiceException(ErrorCode errorCode) { this.code = errorCode.getCode(); - this.message = errorCode.getMessage(); + this.message = errorCode.getMsg(); } public ServiceException(Integer code, String message) { diff --git a/src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java b/src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java index 6dbfe6ca6..e6367c835 100644 --- a/src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java +++ b/src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java @@ -47,12 +47,12 @@ public class ServiceExceptionUtil { // ========== 和 ServiceException 的集成 ========== public static ServiceException exception(ErrorCode errorCode) { - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg()); return exception0(errorCode.getCode(), messagePattern); } public static ServiceException exception(ErrorCode errorCode, Object... params) { - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg()); return exception0(errorCode.getCode(), messagePattern, params); } diff --git a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java index d6e50c65d..73b4c7a76 100644 --- a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java +++ b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java @@ -30,7 +30,7 @@ public class CommonResult implements Serializable { /** * 错误提示,用户可阅读 * - * @see ErrorCode#getMessage() () + * @see ErrorCode#getMsg() () */ private String msg; @@ -56,7 +56,7 @@ public class CommonResult implements Serializable { } public static CommonResult error(ErrorCode errorCode) { - return error(errorCode.getCode(), errorCode.getMessage()); + return error(errorCode.getCode(), errorCode.getMsg()); } public static CommonResult success(T data) { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index 4a0d9aedc..5028e1b0f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -1,6 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import javax.servlet.ServletRequest; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java new file mode 100644 index 000000000..7b6cc51f2 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java @@ -0,0 +1,17 @@ +package cn.iocoder.dashboard.framework.sms.core.client; + +import cn.iocoder.dashboard.common.exception.ErrorCode; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; + +import java.util.function.Function; + +/** + * 将 API 的错误码,转换为通用的错误码 + * + * @see SmsCommonResult + * @see SmsFrameworkErrorCodeConstants + * + * @author 芋道源码 + */ +public interface SmsCodeMapping extends Function { +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java index ffd8c5b0c..79ebed3a2 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java @@ -1,8 +1,10 @@ package cn.iocoder.dashboard.framework.sms.core.client; import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.lang.Assert; +import cn.iocoder.dashboard.common.exception.ErrorCode; import cn.iocoder.dashboard.common.pojo.CommonResult; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -40,20 +42,27 @@ public class SmsCommonResult extends CommonResult { private SmsCommonResult() { } - public static SmsCommonResult success(SmsSendFailureTypeEnum sendFailureType, - String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { - SmsCommonResult result = new SmsCommonResult().setSuccess(true).setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg) - .setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo); - if (sendFailureType != null) { - result.setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg()); + public static SmsCommonResult build(String apiCode, String apiMsg, String apiRequestId, + T data, SmsCodeMapping codeMapping) { + Assert.notNull(codeMapping, "参数 codeMapping 不能为空"); + SmsCommonResult result = new SmsCommonResult().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId); + result.setData(data); + // 翻译错误码 + if (codeMapping != null) { + ErrorCode errorCode = codeMapping.apply(apiCode); + if (errorCode == null) { + errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN; + } + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg()); } return result; } - public static SmsCommonResult error(Throwable ex) { - return new SmsCommonResult().setSuccess(false) - .setSendFailureType(SmsSendFailureTypeEnum.SMS_SEND_EXCEPTION.getType()) - .setSendFailureMsg(ExceptionUtil.getRootCauseMessage(ex)); + public static SmsCommonResult error(Throwable ex) { + SmsCommonResult result = new SmsCommonResult<>(); + result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode()); + result.setMsg(ExceptionUtil.getRootCauseMessage(ex)); + return result; } } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java similarity index 91% rename from src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java index 4d57a090f..f8e19db82 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.framework.sms.core; +package cn.iocoder.dashboard.framework.sms.core.client.dto; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import lombok.Data; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java index c3a28cb93..0f6777a3f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java @@ -1,10 +1,13 @@ package cn.iocoder.dashboard.framework.sms.core.client.dto; +import lombok.Data; + /** * 短信发送响应 DTO * * @author 芋道源码 */ +@Data public class SmsSendRespDTO { /** diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index d2b008b73..1c2dce0e6 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; @@ -21,14 +22,19 @@ public abstract class AbstractSmsClient implements SmsClient { * 短信渠道配置 */ protected volatile SmsChannelProperties properties; + /** + * 错误码枚举类 + */ + protected final SmsCodeMapping codeMapping; /** * 短信客户端有参构造函数 * * @param properties 短信配置 */ - public AbstractSmsClient(SmsChannelProperties properties) { + public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) { this.properties = properties; + this.codeMapping = codeMapping; } /** diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index a0f903871..4dbaffbf0 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -4,9 +4,9 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; @@ -48,7 +48,7 @@ public class AliyunSmsClient extends AbstractSmsClient { private volatile IAcsClient acsClient; public AliyunSmsClient(SmsChannelProperties properties) { - super(properties); + super(properties, new AliyunSmsCodeMapping()); } @Override @@ -59,7 +59,8 @@ public class AliyunSmsClient extends AbstractSmsClient { } @Override - protected SmsCommonResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Exception { + protected SmsCommonResult doSend(Long sendLogId, String mobile, + String apiTemplateId, Map templateParams) throws Throwable { // 构建参数 SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); @@ -73,25 +74,16 @@ public class AliyunSmsClient extends AbstractSmsClient { // 执行发送 SendSmsResponse sendResult = acsClient.getAcsResponse(request); // 解析结果 - return SmsCommonResult.success(parseSendFailureType(sendResult.getCode()), // 将 API 短信平台,解析成统一的错误码 - sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), sendResult.getBizId()); + SmsSendRespDTO data = null; + if (sendResult.getBizId() != null) { + data = new SmsSendRespDTO().setSerialNo(sendResult.getBizId()); + } + return SmsCommonResult.build(sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), data, codeMapping); } catch (ClientException ex) { - return SmsCommonResult.success(parseSendFailureType(ex.getErrCode()), // 将 API 短信平台,解析成统一的错误码 - ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null); + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); } } - private static SmsSendFailureTypeEnum parseSendFailureType(String code) { - switch (code) { - case "OK": return null; - case "MissingAccessKeyId": return SmsSendFailureTypeEnum.SMS_CHANNEL_API_KEY_MISSING; - case "isp.RAM_PERMISSION_DENY": return SmsSendFailureTypeEnum.SMS_CHANNEL_PERMISSION_DENY; - case "isv.INVALID_PARAMETERS": return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; - case "isv.BUSINESS_LIMIT_CONTROL": return SmsSendFailureTypeEnum.SMS_SEND_LIMIT_CONTROL; - } - return SmsSendFailureTypeEnum.SMS_UNKNOWN; - } - private static String formatResultMsg(ClientException ex) { if (StrUtil.isEmpty(ex.getErrorDescription())) { return ex.getMessage(); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java new file mode 100644 index 000000000..d11be8c1b --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java @@ -0,0 +1,27 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.dashboard.common.exception.ErrorCode; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; + +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*; + +/** + * 阿里云的 SmsCodeMapping 实现类 + * + * @author 芋道源码 + */ +public class AliyunSmsCodeMapping implements SmsCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + switch (apiCode) { + case "OK": return null; + case "MissingAccessKeyId": return SMS_CHANNEL_API_KEY_MISSING; + case "isp.RAM_PERMISSION_DENY": return SMS_CHANNEL_PERMISSION_DENY; + case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR; + case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_LIMIT_CONTROL; + } + return SMS_UNKNOWN; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 0d6a51021..503aa32d5 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -6,11 +6,11 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; -import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.json.JsonUtils; @@ -29,8 +29,6 @@ import java.util.List; import java.util.Map; import java.util.StringJoiner; -import static com.yunpian.sdk.constant.Code.*; - /** * 云片短信客户端的实现类 * @@ -49,7 +47,7 @@ public class YunpianSmsClient extends AbstractSmsClient { }; public YunpianSmsClient(SmsChannelProperties properties) { - super(properties); + super(properties, new YunpianSmsCodeMapping()); } @Override @@ -66,7 +64,8 @@ public class YunpianSmsClient extends AbstractSmsClient { } @Override - protected SmsCommonResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map templateParams) throws Throwable { + protected SmsCommonResult doSend(Long sendLogId, String mobile, + String apiTemplateId, Map templateParams) throws Throwable { // 构建参数 Map request = new HashMap<>(); request.put(YunpianConstant.APIKEY, properties.getApiKey()); @@ -82,8 +81,12 @@ public class YunpianSmsClient extends AbstractSmsClient { throw sendResult.getThrowable(); } // 解析结果 - return SmsCommonResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码 - String.valueOf(sendResult.getCode()), formatResultMsg(sendResult), null, getApiSerialNo(sendResult)); + SmsSendRespDTO data = null; + if (sendResult.getData() != null) { + data = new SmsSendRespDTO().setSerialNo(String.valueOf(sendResult.getData().getSid())); + } + return SmsCommonResult.build(String.valueOf(sendResult.getCode()), formatResultMsg(sendResult), null, + data, codeMapping); } private static String formatTplValue(Map templateParams) { @@ -103,25 +106,6 @@ public class YunpianSmsClient extends AbstractSmsClient { return sendResult.getMsg() + " => " + sendResult.getDetail(); } - private static SmsSendFailureTypeEnum parseSendFailureType(Result sendResult) { - Integer code = sendResult.getCode(); - switch (code) { - case OK: return null; - case ARGUMENT_MISSING: return SmsSendFailureTypeEnum.SMS_API_PARAM_ERROR; - case BAD_ARGUMENT_FORMAT: return SmsSendFailureTypeEnum.SMS_TEMPLATE_PARAM_ERROR; - case TPL_NOT_FOUND: return SmsSendFailureTypeEnum.SMS_TEMPLATE_NOT_EXISTS; - case TPL_NOT_VALID: return SmsSendFailureTypeEnum.SMS_TEMPLATE_INVALID; - } - return SmsSendFailureTypeEnum.SMS_UNKNOWN; - } - - private static String getApiSerialNo(Result sendResult) { - if (sendResult.getData() == null) { - return null; - } - return String.valueOf(sendResult.getData().getSid()); - } - /** * 云片的比较复杂,又是加密又是套娃的 */ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java new file mode 100644 index 000000000..012b734de --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java @@ -0,0 +1,30 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; + +import cn.iocoder.dashboard.common.exception.ErrorCode; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; + +import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.SUCCESS; +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*; +import static com.yunpian.sdk.constant.Code.*; + +/** + * 云片的 SmsCodeMapping 实现类 + * + * @author 芋道源码 + */ +public class YunpianSmsCodeMapping implements SmsCodeMapping { + + @Override + public ErrorCode apply(String apiCode) { + int code = Integer.parseInt(apiCode); + switch (code) { + case OK: return SUCCESS; + case ARGUMENT_MISSING: return SMS_API_PARAM_ERROR; + case BAD_ARGUMENT_FORMAT: return SMS_TEMPLATE_PARAM_ERROR; + case TPL_NOT_FOUND: return SMS_TEMPLATE_NOT_EXISTS; + case TPL_NOT_VALID: return SMS_TEMPLATE_INVALID; + } + return SMS_UNKNOWN; + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java similarity index 75% rename from src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java index c5351d68b..e699db96e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/SmsConstants.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java @@ -1,4 +1,4 @@ -package cn.iocoder.dashboard.framework.sms.core; +package cn.iocoder.dashboard.framework.sms.core.enums; /** * 短信相关常量类 diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java new file mode 100644 index 000000000..f0cbb762f --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java @@ -0,0 +1,32 @@ +package cn.iocoder.dashboard.framework.sms.core.enums; + +import cn.iocoder.dashboard.common.exception.ErrorCode; + +/** + * 短信框架的错误码枚举 + * + * 短信框架,使用 2-001-000-000 段 + * + * @author 芋道源码 + */ +public interface SmsFrameworkErrorCodeConstants { + + // ========== 渠道相关 2001000100 ========== + ErrorCode SMS_CHANNEL_CLIENT_NOT_EXISTS = new ErrorCode(2001000100, "短信渠道的客户端不存在"); + ErrorCode SMS_CHANNEL_API_KEY_MISSING = new ErrorCode(2001000101, "API Key 不存在"); + ErrorCode SMS_CHANNEL_PERMISSION_DENY = new ErrorCode(2001000102, "没有发送短信的权限"); + + // ========== 模板相关(200 开头) ========== + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(200, "短信模板不存在"); + ErrorCode SMS_TEMPLATE_DISABLE = new ErrorCode(201, "短信模板被禁用"); // 例如说,我们在管理后台禁用了 + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(202, "短信模板不可用"); // 例如说,短信模板正在审核中 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(203, "模板参数不正确"); + + // ========== 其它相关(900 开头) ========== + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(900, "请求参数缺失"); + + ErrorCode SMS_SEND_LIMIT_CONTROL = new ErrorCode(997, "业务限流"); // 将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 + ErrorCode EXCEPTION = new ErrorCode(998, "调用异常"); + ErrorCode SMS_UNKNOWN = new ErrorCode(999, "未知错误,需要解析"); + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java deleted file mode 100644 index af29977fa..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsSendFailureTypeEnum.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 短信的发送失败类型的枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum SmsSendFailureTypeEnum { - - // ========== 渠道相关(100 开头) ========== - SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"), - SMS_CHANNEL_API_KEY_MISSING(101, "API Key 不存在"), - SMS_CHANNEL_PERMISSION_DENY(102, "没有发送短信的权限"), - - // ========== 模板相关(200 开头) ========== - SMS_TEMPLATE_NOT_EXISTS(200, "短信模板不存在"), - SMS_TEMPLATE_DISABLE(201, "短信模板被禁用"), // 例如说,我们在管理后台禁用了 - SMS_TEMPLATE_INVALID(202, "短信模板不可用"), // 例如说,短信模板正在审核中 - SMS_TEMPLATE_PARAM_ERROR(203, "模板参数不正确"), - - // ========== 其它相关(900 开头) ========== - SMS_API_PARAM_ERROR(900, "请求参数缺失"), - - SMS_SEND_LIMIT_CONTROL(997, "业务限流"), // 将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。 - SMS_SEND_EXCEPTION(998, "发送异常"), - SMS_UNKNOWN(999, "未知错误,需要解析") - ; - - /** - * 失败类型 - */ - private final int type; - /** - * 失败提示 - */ - private final String msg; - -} diff --git a/src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java b/src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java index 75704145c..faa01c641 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java +++ b/src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java @@ -3,7 +3,6 @@ package cn.iocoder.dashboard.framework.web.core.handler; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.extra.servlet.ServletUtil; -import cn.iocoder.dashboard.common.exception.GlobalException; import cn.iocoder.dashboard.common.exception.ServiceException; import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService; @@ -96,9 +95,6 @@ public class GlobalExceptionHandler { if (ex instanceof AccessDeniedException) { return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); } - if (ex instanceof GlobalException) { - return globalExceptionHandler(request, (GlobalException) ex); - } return defaultExceptionHandler(request, ex); } @@ -222,25 +218,6 @@ public class GlobalExceptionHandler { return CommonResult.error(ex.getCode(), ex.getMessage()); } - /** - * 处理全局异常 ServiceException - * - * 例如说,Dubbo 请求超时,调用的 Dubbo 服务系统异常 - */ - @ExceptionHandler(value = GlobalException.class) - public CommonResult globalExceptionHandler(HttpServletRequest req, GlobalException ex) { - // 系统异常时,才打印异常日志 - if (INTERNAL_SERVER_ERROR.getCode().equals(ex.getCode())) { - // 插入异常日志 - this.createExceptionLog(req, ex); - // 普通全局异常,打印 info 日志即可 - } else { - log.info("[globalExceptionHandler]", ex); - } - // 返回 ERROR CommonResult - return CommonResult.error(ex); - } - /** * 处理系统异常,兜底处理所有的一切 */ @@ -250,7 +227,7 @@ public class GlobalExceptionHandler { // 插入异常日志 this.createExceptionLog(req, ex); // 返回 ERROR CommonResult - return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMessage()); + return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg()); } private void createExceptionLog(HttpServletRequest req, Throwable e) { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java index 29118cb8c..7c91b55cb 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java @@ -1,6 +1,5 @@ package cn.iocoder.dashboard.modules.system.service.sms; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import java.util.Map; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java index 88997dfa0..1ed46fa34 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java @@ -358,7 +358,7 @@ public class SysUserServiceImpl implements SysUserService { } // 如果存在,判断是否允许更新 if (!isUpdateSupport) { - respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMessage()); + respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg()); return; } SysUserDO updateUser = SysUserConvert.INSTANCE.convert(importUser); diff --git a/src/test/java/cn/iocoder/dashboard/util/AssertUtils.java b/src/test/java/cn/iocoder/dashboard/util/AssertUtils.java index 042208530..0c16b8456 100644 --- a/src/test/java/cn/iocoder/dashboard/util/AssertUtils.java +++ b/src/test/java/cn/iocoder/dashboard/util/AssertUtils.java @@ -62,7 +62,7 @@ public class AssertUtils { ServiceException serviceException = assertThrows(ServiceException.class, executable); // 校验错误码 Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配"); - String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMessage(), messageParams); + String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), messageParams); Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配"); } From d843d6a5a8329e89c0fa8f9e9f982b89091d0852 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 3 Apr 2021 22:05:11 +0800 Subject: [PATCH 26/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=8F=90=E4=BA=A4=2020?= =?UTF-8?q?21-04-03=EF=BC=8C=E9=87=8D=E6=9E=84=E8=BF=94=E5=9B=9E=E7=9A=84?= =?UTF-8?q?=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/common/core/KeyValue.java | 20 +++++ .../dashboard/common/pojo/CommonResult.java | 7 +- .../framework/sms/core/client/SmsClient.java | 7 +- .../sms/core/client/dto/SmsSendRespDTO.java | 2 +- .../core/client/impl/AbstractSmsClient.java | 16 ++-- .../client/impl/aliyun/AliyunSmsClient.java | 6 +- .../impl/aliyun/AliyunSmsCodeMapping.java | 3 +- .../client/impl/yunpian/YunpianSmsClient.java | 7 +- .../enums/SmsFrameworkErrorCodeConstants.java | 1 - .../controller/sms/SmsChannelController.java | 8 -- .../sms/vo/resp/SmsChannelEnumRespVO.java | 21 ----- .../system/convert/sms/SmsChannelConvert.java | 4 - .../dal/dataobject/sms/SysSmsChannelDO.java | 6 +- ...{SysSmsSendLogDO.java => SysSmsLogDO.java} | 43 ++++++----- .../dal/dataobject/sms/SysSmsTemplateDO.java | 10 ++- ...endLogMapper.java => SysSmsLogMapper.java} | 4 +- .../enums/sms/SysSmsSendStatusEnum.java | 1 + .../mq/message/sms/SysSmsSendMessage.java | 11 +-- .../mq/producer/sms/SysSmsProducer.java | 12 +-- .../service/sms/SysSmsChannelService.java | 14 +--- .../system/service/sms/SysSmsLogService.java | 44 +++++++++++ .../service/sms/SysSmsSendLogService.java | 49 ------------ .../sms/impl/SysSmsChannelServiceImpl.java | 16 +--- .../sms/impl/SysSmsSendLogServiceImpl.java | 36 +++++---- .../service/sms/impl/SysSmsServiceImpl.java | 77 ++++++++++--------- .../dashboard/util/collection/MapUtils.java | 8 ++ .../impl/aliyun/AliyunSmsClientTest.java | 12 +-- .../YunpianSmsClientIntegrationTest.java | 14 ++-- 28 files changed, 232 insertions(+), 227 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java rename src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/{SysSmsSendLogDO.java => SysSmsLogDO.java} (76%) rename src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/{SysSmsSendLogMapper.java => SysSmsLogMapper.java} (73%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java diff --git a/src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java b/src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java new file mode 100644 index 000000000..57fe08b5a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java @@ -0,0 +1,20 @@ +package cn.iocoder.dashboard.common.core; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Key Value 的键值对 + * + * @author 芋道源码 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class KeyValue { + + private K key; + private V value; + +} diff --git a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java index 73b4c7a76..0a56d334a 100644 --- a/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java +++ b/src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java @@ -8,6 +8,7 @@ import lombok.Data; import org.springframework.util.Assert; import java.io.Serializable; +import java.util.Objects; /** * 通用返回 @@ -67,9 +68,13 @@ public class CommonResult implements Serializable { return result; } + public static boolean isSuccess(Integer code) { + return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode()); + } + @JsonIgnore // 避免 jackson 序列化 public boolean isSuccess() { - return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code); + return isSuccess(GlobalErrorCodeConstants.SUCCESS.getCode()); } @JsonIgnore // 避免 jackson 序列化 diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index 5028e1b0f..f343b540f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -1,10 +1,11 @@ package cn.iocoder.dashboard.framework.sms.core.client; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import javax.servlet.ServletRequest; -import java.util.Map; +import java.util.List; /** * 短信客户端接口 @@ -24,13 +25,13 @@ public interface SmsClient { /** * 发送消息 * - * @param sendLogId 发送日志编号 + * @param logId 日志编号 * @param mobile 手机号 * @param apiTemplateId 短信 API 的模板编号 * @param templateParams 短信模板参数 * @return 短信发送结果 */ - SmsCommonResult send(Long sendLogId, String mobile, String apiTemplateId, Map templateParams); + SmsCommonResult send(Long logId, String mobile, String apiTemplateId, List> templateParams); // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX /** diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java index 0f6777a3f..c3f6b51ae 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java +++ b/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; import lombok.Data; /** - * 短信发送响应 DTO + * 短信发送 Response DTO * * @author 芋道源码 */ diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index 1c2dce0e6..6e334cf0a 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -1,13 +1,14 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl; +import cn.iocoder.dashboard.common.core.KeyValue; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; -import java.util.Map; +import java.util.List; /** * 短信客户端抽象类 @@ -67,16 +68,16 @@ public abstract class AbstractSmsClient implements SmsClient { } @Override - public final SmsCommonResult send(Long sendLogId, String mobile, - String apiTemplateId, Map templateParams) { + public final SmsCommonResult send(Long logId, String mobile, + String apiTemplateId, List> templateParams) { // 执行短信发送 SmsCommonResult result; try { - result = doSend(sendLogId, mobile, apiTemplateId, templateParams); + result = doSend(logId, mobile, apiTemplateId, templateParams); } catch (Throwable ex) { // 打印异常日志 log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", - sendLogId, mobile, apiTemplateId, templateParams, ex); + logId, mobile, apiTemplateId, templateParams, ex); // 封装返回 return SmsCommonResult.error(ex); } @@ -93,6 +94,7 @@ public abstract class AbstractSmsClient implements SmsClient { * @return 短信发送结果 */ protected abstract SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, Map templateParams) throws Throwable; + String apiTemplateId, List> templateParams) + throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index 4dbaffbf0..acc8a0193 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/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; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; +import cn.iocoder.dashboard.util.collection.MapUtils; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; @@ -60,14 +62,14 @@ public class AliyunSmsClient extends AbstractSmsClient { @Override protected SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, Map templateParams) throws Throwable { + String apiTemplateId, List> templateParams) { // 构建参数 SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); request.setPhoneNumbers(mobile); request.setSignName(properties.getSignature()); request.setTemplateCode(apiTemplateId); - request.setTemplateParam(JsonUtils.toJsonString(templateParams)); + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); request.setOutId(String.valueOf(sendLogId)); try { diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java index d11be8c1b..8a804de0c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java @@ -1,6 +1,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.iocoder.dashboard.common.exception.ErrorCode; +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*; @@ -15,7 +16,7 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping { @Override public ErrorCode apply(String apiCode) { switch (apiCode) { - case "OK": return null; + case "OK": return GlobalErrorCodeConstants.SUCCESS; case "MissingAccessKeyId": return SMS_CHANNEL_API_KEY_MISSING; case "isp.RAM_PERMISSION_DENY": return SMS_CHANNEL_PERMISSION_DENY; case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR; diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 503aa32d5..249d8c481 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -6,6 +6,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; @@ -65,7 +66,7 @@ public class YunpianSmsClient extends AbstractSmsClient { @Override protected SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, Map templateParams) throws Throwable { + String apiTemplateId, List> templateParams) throws Throwable { // 构建参数 Map request = new HashMap<>(); request.put(YunpianConstant.APIKEY, properties.getApiKey()); @@ -89,13 +90,13 @@ public class YunpianSmsClient extends AbstractSmsClient { data, codeMapping); } - private static String formatTplValue(Map templateParams) { + private static String formatTplValue(List> templateParams) { if (CollUtil.isEmpty(templateParams)) { return ""; } // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化 StringJoiner joiner = new StringJoiner("&"); - templateParams.forEach((key, value) -> joiner.add(String.format("#%s#=%s", key, URLUtil.encode(String.valueOf(value))))); + templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue()))))); return joiner.toString(); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java index f0cbb762f..741410944 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java @@ -12,7 +12,6 @@ import cn.iocoder.dashboard.common.exception.ErrorCode; public interface SmsFrameworkErrorCodeConstants { // ========== 渠道相关 2001000100 ========== - ErrorCode SMS_CHANNEL_CLIENT_NOT_EXISTS = new ErrorCode(2001000100, "短信渠道的客户端不存在"); ErrorCode SMS_CHANNEL_API_KEY_MISSING = new ErrorCode(2001000101, "API Key 不存在"); ErrorCode SMS_CHANNEL_PERMISSION_DENY = new ErrorCode(2001000102, "没有发送短信的权限"); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index 415e47405..3d6ccc575 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -4,7 +4,6 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import io.swagger.annotations.Api; @@ -13,7 +12,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; -import java.util.List; import static cn.iocoder.dashboard.common.pojo.CommonResult.success; @@ -31,12 +29,6 @@ public class SmsChannelController { return success(service.pageSmsChannels(reqVO)); } - @ApiOperation("获取渠道枚举") - @GetMapping("/list/channel-enum") - public CommonResult> getChannelEnums() { - return success(service.getSmsChannelEnums()); - } - @ApiOperation("添加消息渠道") @PostMapping("/create") public CommonResult add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java deleted file mode 100644 index cb156781d..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp; - -import io.swagger.annotations.ApiModel; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.io.Serializable; - - -@ApiModel("用户分页 Request VO") -@Data -@NoArgsConstructor -@EqualsAndHashCode -public class SmsChannelEnumRespVO implements Serializable { - - private String code; - - private String name; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java index 43d72b471..c8a0f7591 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java @@ -1,10 +1,8 @@ package cn.iocoder.dashboard.modules.system.convert.sms; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import org.mapstruct.Mapper; @@ -21,8 +19,6 @@ public interface SmsChannelConvert { SysSmsChannelDO convert(SysUserUpdateReqVO bean); - List convertEnum(List bean); - List convert(List bean); List convertProperty(List list); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java index 4bca7e517..7b0b3f072 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsChannelDO.java +++ b/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; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; /** - * 短信渠道 + * 短信渠道 DO * * @author zzf * @since 2021-01-25 */ -@TableName(value = "sms_channel", autoResultMap = true) +@TableName(value = "sys_sms_channel", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class SysSmsChannelDO extends BaseDO { /** diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java similarity index 76% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java index 53e725634..44d0da639 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsSendLogDO.java +++ b/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; import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import java.util.Date; import java.util.Map; /** - * 短信发送日志 + * 短信日志 DO * * @author zzf * @since 2021-01-25 */ -@TableName(value = "sms_send_log", autoResultMap = true) +@TableName(value = "sys_sms_log", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @AllArgsConstructor @NoArgsConstructor @Builder -public class SysSmsSendLogDO extends BaseDO { +public class SysSmsLogDO extends BaseDO { /** * 自增编号 @@ -48,7 +50,7 @@ public class SysSmsSendLogDO extends BaseDO { // ========= 模板相关字段 ========= /** - * 短信模板编号 + * 模板编号 * * 关联 {@link SysSmsTemplateDO#getId()} */ @@ -70,8 +72,9 @@ public class SysSmsSendLogDO extends BaseDO { */ private String templateContent; /** - * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的内容 + * 基于 {@link SysSmsTemplateDO#getParams()} 输入后的参数 */ + @TableField(typeHandler = JacksonTypeHandler.class) private Map templateParams; /** * 短信 API 的模板编号 @@ -106,32 +109,32 @@ public class SysSmsSendLogDO extends BaseDO { */ private Integer sendStatus; /** - * 时间发送时间 + * 发送时间 */ private Date sendTime; /** - * 发送失败的类型 + * 发送结果的编码 * - * 枚举 {@link SmsSendFailureTypeEnum#getType()} + * 枚举 {@link SmsFrameworkErrorCodeConstants} */ - private Integer sendFailureType; + private Integer sendCode; /** - * 发送失败的提示 + * 发送结果的提示 * - * 一般情况下,使用 {@link SmsSendFailureTypeEnum#getMsg()} + * 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants} * 异常情况下,通过格式化 Exception 的提示存储 */ - private String sendFailureMsg; + private String sendMsg; /** - * 短信 API 发送失败的类型 + * 短信 API 发送结果的编码 * * 由于第三方的错误码可能是字符串,所以使用 String 类型 */ - private String apiSendFailureType; + private String apiSendCode; /** * 短信 API 发送失败的提示 */ - private String apiSendFailureMsg; + private String apiSendMsg; /** * 短信 API 发送返回的唯一请求 ID * @@ -147,9 +150,9 @@ public class SysSmsSendLogDO extends BaseDO { // ========= 接收相关字段 ========= - /** - * 是否获取过结果[0否 1是] - */ - private Integer gotResult; +// /** +// * 是否获取过结果[0否 1是] +// */ +// private Integer gotResult; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java index ba2b9940e..9316358df 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java @@ -8,18 +8,20 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; /** - * 短信模板 + * 短信模板 DO * * @author zzf * @since 2021-01-25 */ +@TableName(value = "sys_sms_template", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) -@TableName(value = "sms_template", autoResultMap = true) +@ToString(callSuper = true) public class SysSmsTemplateDO extends BaseDO { /** @@ -46,11 +48,11 @@ public class SysSmsTemplateDO extends BaseDO { */ private String code; /** - * 名称 + * 模板名称 */ private String name; /** - * 内容 + * 模板内容 * * 内容的参数,使用 {} 包括,例如说 {name} */ diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java similarity index 73% rename from src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java rename to src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java index 74d713d48..2255c444e 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsSendLogMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsLogMapper.java @@ -1,9 +1,9 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO; import org.apache.ibatis.annotations.Mapper; @Mapper -public interface SysSmsSendLogMapper extends BaseMapperX { +public interface SysSmsLogMapper extends BaseMapperX { } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java index 083b11c98..1d505ee02 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsSendStatusEnum.java @@ -16,6 +16,7 @@ public enum SysSmsSendStatusEnum { INIT(0), // 初始化 SUCCESS(10), // 发送成功 FAILURE(20), // 发送失败 + IGNORE(30), // 忽略,即不发送 ; private final int status; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java index 40cc80ba5..9bb30514a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/message/sms/SysSmsSendMessage.java @@ -1,10 +1,11 @@ package cn.iocoder.dashboard.modules.system.mq.message.sms; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.redis.core.stream.StreamMessage; import lombok.Data; import javax.validation.constraints.NotNull; -import java.util.Map; +import java.util.List; /** * 短信发送消息 @@ -15,10 +16,10 @@ import java.util.Map; public class SysSmsSendMessage implements StreamMessage { /** - * 发送日志编号 + * 短信日志编号 */ - @NotNull(message = "发送日志编号不能为空") - private Long sendLogId; + @NotNull(message = "短信日志编号不能为空") + private Long logId; /** * 手机号 */ @@ -37,7 +38,7 @@ public class SysSmsSendMessage implements StreamMessage { /** * 短信模板参数 */ - private Map templateParams; + private List> templateParams; @Override public String getStreamKey() { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java index 257de549c..8e72bcf38 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/sms/SysSmsProducer.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.modules.system.mq.producer.sms; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import lombok.extern.slf4j.Slf4j; @@ -7,7 +8,7 @@ import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.util.Map; +import java.util.List; /** * 短信发送流消息监听器 @@ -25,16 +26,15 @@ public class SysSmsProducer { /** * 发送短信 Message * - * @param sendLogId 发送日志编号 + * @param logId 短信日志编号 * @param mobile 手机号 * @param channelId 渠道编号 * @param apiTemplateId 短信模板编号 * @param templateParams 短信模板参数 - * @param sendLogId 发送日志编号 */ - public void sendSmsSendMessage(Long sendLogId, String mobile, - Long channelId, String apiTemplateId, Map templateParams) { - SysSmsSendMessage message = new SysSmsSendMessage().setSendLogId(sendLogId).setMobile(mobile); + public void sendSmsSendMessage(Long logId, String mobile, + Long channelId, String apiTemplateId, List> templateParams) { + SysSmsSendMessage message = new SysSmsSendMessage().setLogId(logId).setMobile(mobile); message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams); RedisMessageUtils.sendStreamMessage(stringRedisTemplate, message); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index e720e363f..142812b3c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -3,11 +3,8 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import java.util.List; - /** * 短信渠道Service接口 * @@ -17,9 +14,9 @@ import java.util.List; public interface SysSmsChannelService { /** - * 初始化短信渠道并缓存短信模板信息 + * 初始化短信客户端 */ - void initSmsClientAndCacheSmsTemplate(); + void initSmsClients(); /** * 分页查询短信渠道信息 @@ -37,11 +34,4 @@ public interface SysSmsChannelService { */ Long createSmsChannel(SmsChannelCreateReqVO reqVO); - /** - * 获取短信渠道枚举/渠道编码 - * - * @return 短信渠道枚举/渠道编码 - */ - List getSmsChannelEnums(); - } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java new file mode 100644 index 000000000..fd04a62b5 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java @@ -0,0 +1,44 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; + +import java.util.Map; + +/** + * 短信日志服务接口 + * + * @author zzf + * @date 13:48 2021/3/2 + */ +public interface SysSmsLogService { + + /** + * 创建短信日志 + * + * @param mobile 手机号 + * @param userId 用户编号 + * @param userType 用户类型 + * @param isSend 是否发送 + * @param template 短信模板 + * @param templateContent 短信内容 + * @param templateParams 短信参数 + * @return 发送日志编号 + */ + Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SysSmsTemplateDO template, String templateContent, Map templateParams); + + /** + * 更新发送日志的结果 + * + * @param id 日志编号 + * @param sendCode 发送结果的编码 + * @param sendMsg 发送结果的提示 + * @param apiSendCode 短信 API 发送结果的编码 + * @param apiSendMsg 短信 API 发送失败的提示 + * @param apiRequestId 短信 API 发送返回的唯一请求 ID + * @param apiSerialNo 短信 API 发送返回的序号 + */ + void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java deleted file mode 100644 index 7c91b55cb..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsSendLogService.java +++ /dev/null @@ -1,49 +0,0 @@ -package cn.iocoder.dashboard.modules.system.service.sms; - -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; - -import java.util.Map; - -/** - * 短信发送日志服务接口 - * - * @author zzf - * @date 13:48 2021/3/2 - */ -public interface SysSmsSendLogService { - - /** - * 创建发送日志 - * - * @param mobile 手机号 - * @param userId 用户编号 - * @param userType 用户类型 - * @param template 短信模板 - * @param templateContent 短信内容 - * @param templateParams 短信参数 - * @return - */ - Long createSmsSendLog(String mobile, Long userId, Integer userType, - SysSmsTemplateDO template, String templateContent, Map templateParams); - - /** - * 更新发送日志的结果 - * - * @param id 日志编号 - * @param success 是否成功 - * @param sendFailureType 发送失败的类型 - * @param sendFailureMsg 发送失败的提示 - * @param apiSendFailureType 短信 API 发送失败的类型 - * @param apiSendFailureMsg 短信 API 发送失败的提示 - * @param apiRequestId 短信 API 发送返回的唯一请求 ID - * @param apiSerialNo 短信 API 发送返回的序号 - */ - void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg, - String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo); - - default void updateSmsSendLogFailure(Long id, SmsSendFailureTypeEnum sendFailureType) { - updateSmsSendLogResult(id, false, sendFailureType.getType(), sendFailureType.getMsg(), - null, null, null, null); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index 930a7db9c..a34d511bb 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java +++ b/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; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper; -import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.Arrays; import java.util.List; /** @@ -35,12 +31,9 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { @Resource private SysSmsChannelMapper channelMapper; - @Resource - private SysSmsTemplateMapper templateMapper; - @Override @PostConstruct - public void initSmsClientAndCacheSmsTemplate() { + public void initSmsClients() { // 查询有效渠道信息 List channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); // 创建渠道 Client @@ -48,6 +41,8 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); } + // TODO 芋艿:刷新缓存 + @Override public PageResult pageSmsChannels(SmsChannelPageReqVO reqVO) { return channelMapper.selectChannelPage(reqVO); @@ -60,11 +55,6 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { return channelDO.getId(); } - @Override - public List getSmsChannelEnums() { - return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); - } - // @Override // public List listSmsChannelAllEnabledInfo() { // List channelDOList = channelMapper.selectListByStatus(); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java index b57912bd4..00c43e8f1 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java @@ -1,10 +1,11 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; -import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -21,15 +22,18 @@ import java.util.Objects; */ @Slf4j @Service -public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { +public class SysSmsSendLogServiceImpl implements SysSmsLogService { @Resource - private SysSmsSendLogMapper smsSendLogMapper; + private SysSmsLogMapper smsLogMapper; @Override - public Long createSmsSendLog(String mobile, Long userId, Integer userType, - SysSmsTemplateDO template, String templateContent, Map templateParams) { - SysSmsSendLogDO.SysSmsSendLogDOBuilder logBuilder = SysSmsSendLogDO.builder(); + public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend, + SysSmsTemplateDO template, String templateContent, Map templateParams) { + SysSmsLogDO.SysSmsLogDOBuilder logBuilder = SysSmsLogDO.builder(); + // 根据是否要发送,设置状态 + logBuilder.sendStatus(Objects.equals(isSend, true) ? SysSmsSendStatusEnum.INIT.getStatus() + : SysSmsSendStatusEnum.IGNORE.getStatus()); // 设置手机相关字段 logBuilder.mobile(mobile).userId(userId).userType(userType); // 设置模板相关字段 @@ -39,18 +43,18 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode()); // 插入数据库 - SysSmsSendLogDO logDO = logBuilder.build(); - smsSendLogMapper.insert(logDO); + SysSmsLogDO logDO = logBuilder.build(); + smsLogMapper.insert(logDO); return logDO.getId(); } @Override - public void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg, - String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo) { - SysSmsSendStatusEnum sendStatus = Objects.equals(success, true) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE; - smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendStatus(sendStatus.getStatus()).setSendTime(new Date()) - .setSendFailureType(sendFailureType).setSendFailureMsg(sendFailureMsg) - .setApiSendFailureType(apiSendFailureType).setApiSendFailureMsg(apiSendFailureMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo)); + public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, + String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { + SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE; + smsLogMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date()) + .sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) + .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build()); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index e722b4499..959a997b0 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -1,29 +1,32 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.enums.UserTypeEnum; -import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; import javax.annotation.Resource; import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @@ -38,10 +41,12 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @Slf4j public class SysSmsServiceImpl implements SysSmsService { + @Resource + private SysSmsChannelService smsChannelService; @Resource private SysSmsTemplateService smsTemplateService; @Resource - private SysSmsSendLogService smsSendLogService; + private SysSmsLogService smsLogService; @Resource private SysSmsProducer smsProducer; @Resource @@ -54,53 +59,58 @@ public class SysSmsServiceImpl implements SysSmsService { public void sendSingleSms(String mobile, Long userId, Integer userType, String templateCode, Map templateParams) { // 校验短信模板是否合法 - SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode); // 校验手机号码是否存在 mobile = this.checkMobile(mobile, userId, userType); // 创建发送日志 + Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus()); // 如果模板被禁用,则不发送短信,只记录日志 String content = smsTemplateService.formatSmsTemplateContent(template.getContent(), templateParams); - Long sendLogId = smsSendLogService.createSmsSendLog(mobile, userId, userType, template, content, templateParams); + Long sendLogId = smsLogService.createSmsLog(mobile, userId, userType, isSend, template, content, templateParams); - // 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。 - if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) { - smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE); + // 发送 MQ 消息,异步执行发送短信 + if (!isSend) { return; } - // 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台 - smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), templateParams); + List> newTemplateParams = this.buildTemplateParams(template, templateParams); + smsProducer.sendSmsSendMessage(sendLogId, mobile, template.getChannelId(), template.getApiTemplateId(), newTemplateParams); } @Override public void sendBatchSms(List mobiles, List userIds, Integer userType, String templateCode, Map templateParams) { // 校验短信模板是否存在 - SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode, templateParams); + SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode); } - private SysSmsTemplateDO checkSmsTemplateValid(String templateCode, Map templateParams) { + private SysSmsTemplateDO checkSmsTemplateValid(String templateCode) { // 短信模板不存在 SysSmsTemplateDO template = smsTemplateService.getSmsTemplateByCode(templateCode); if (template == null) { throw exception(SMS_TEMPLATE_NOT_EXISTS); } - // 参数不够 - if (CollUtil.isNotEmpty(template.getParams())) { - template.getParams().forEach(param -> { - if (!templateParams.containsKey(param)) { - throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS); - } - }); - } - // 移除多余参数 - if (CollUtil.isEmpty(template.getParams())) { - templateParams.clear(); - } else { - templateParams.entrySet().removeIf(entry -> !template.getParams().contains(entry.getKey())); - } return template; } + /** + * 将参数模板,处理成有序的 KeyValue 数组 + * + * 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023 + * + * @param template 短信模板 + * @param templateParams 原始参数 + * @return 处理后的参数 + */ + private List> buildTemplateParams(SysSmsTemplateDO template, Map templateParams) { + return template.getParams().stream().map(key -> { + Object value = templateParams.get(key); + if (value == null) { + throw exception(SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, key); + } + return new KeyValue<>(key, value); + }).collect(Collectors.toList()); + } + private String checkMobile(String mobile, Long userId, Integer userType) { mobile = getMobile(mobile, userId, userType); if (StrUtil.isEmpty(mobile)) { @@ -130,15 +140,12 @@ public class SysSmsServiceImpl implements SysSmsService { public void doSendSms(SysSmsSendMessage message) { // 获得渠道对应的 SmsClient 客户端 SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); - if (smsClient == null) { - log.error("[doSendSms][短信 message({}) 找不到对应的客户端]", message); - smsSendLogService.updateSmsSendLogFailure(message.getSendLogId(), SmsSendFailureTypeEnum.SMS_CHANNEL_CLIENT_NOT_EXISTS); - return; - } - + Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId())); // 发送短信 - SmsCommonResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(), + SmsCommonResult sendResult = smsClient.send(message.getLogId(), message.getMobile(), message.getApiTemplateId(), message.getTemplateParams()); + smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), + sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), sendResult.getData().getSerialNo()); } @Override diff --git a/src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java b/src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java index ebe29648f..ce5805db8 100644 --- a/src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java @@ -2,6 +2,8 @@ package cn.iocoder.dashboard.util.collection; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.dashboard.common.core.KeyValue; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import java.util.ArrayList; @@ -55,4 +57,10 @@ public class MapUtils { consumer.accept(value); } + public static Map convertMap(List> keyValues) { + Map map = Maps.newLinkedHashMapWithExpectedSize(keyValues.size()); + keyValues.forEach(keyValue -> map.put(keyValue.getKey(), keyValue.getValue())); + return map; + } + } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java index 1c85031b6..baae08886 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -1,12 +1,14 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import org.junit.jupiter.api.Test; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; /** * {@link AliyunSmsClient} 的集成测试 @@ -26,11 +28,11 @@ public class AliyunSmsClientTest { AliyunSmsClient smsClient = new AliyunSmsClient(properties); smsClient.init(); // 发送短信 - Map templateParams = new HashMap<>(); - templateParams.put("code", "1024"); + List> templateParams = new ArrayList<>(); + templateParams.add(new KeyValue<>("code", "1024")); // templateParams.put("operation", "嘿嘿"); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsCommonResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); + SmsCommonResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); System.out.println(result); } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java index 028cd6c77..6e4d4315c 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java @@ -1,12 +1,14 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; +import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import org.junit.jupiter.api.Test; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; /** * {@link YunpianSmsClient} 的集成测试 @@ -25,11 +27,11 @@ public class YunpianSmsClientIntegrationTest { YunpianSmsClient smsClient = new YunpianSmsClient(properties); smsClient.init(); // 发送短信 - Map templateParams = new HashMap<>(); - templateParams.put("code", "1024"); - templateParams.put("operation", "嘿嘿"); + List> templateParams = new ArrayList<>(); + templateParams.add(new KeyValue<>("code", "1024")); + templateParams.add(new KeyValue<>("operation", "嘿嘿")); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsCommonResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); + SmsCommonResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); System.out.println(result); } From 0d0110ec08af77841c737fc0fe13c5621c0a95c0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 3 Apr 2021 23:05:22 +0800 Subject: [PATCH 27/54] =?UTF-8?q?=E4=BA=91=E7=89=87=E3=80=81=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=E7=9F=AD=E4=BF=A1=E5=8F=91=E9=80=81=E7=9A=84?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/redis/config/RedisConfig.java | 8 +- .../client/impl/SmsClientFactoryImpl.java | 1 + ...dConsumer.java => SysSmsSendConsumer.java} | 2 +- .../system/service/sms/SysSmsLogService.java | 2 +- ...iceImpl.java => SysSmsLogServiceImpl.java} | 4 +- .../service/sms/impl/SysSmsServiceImpl.java | 6 +- .../BaseDbAndRedisIntegrationTest.java | 37 ++++++++++ .../redis/core/stream/RedisStreamTest.java | 4 +- .../modules/system/service/package-info.java | 1 + .../sms/SysSmsServiceIntegrationTest.java | 74 +++++++++++++++++++ .../application-integration-test.yaml | 14 ++-- 11 files changed, 130 insertions(+), 23 deletions(-) rename src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/{SmsSendConsumer.java => SysSmsSendConsumer.java} (89%) rename src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/{SysSmsSendLogServiceImpl.java => SysSmsLogServiceImpl.java} (96%) create mode 100644 src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java create mode 100644 src/test-integration/java/cn/iocoder/dashboard/modules/system/service/package-info.java create mode 100644 src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java b/src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java index 432d5618c..52bef8059 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java +++ b/src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java @@ -48,8 +48,8 @@ public class RedisConfig { * 创建 Redis Pub/Sub 广播消费的容器 */ @Bean - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory, - List> listeners) { + public RedisMessageListenerContainer redisMessageListenerContainer( + RedisConnectionFactory factory, List> listeners) { // 创建 RedisMessageListenerContainer 对象 RedisMessageListenerContainer container = new RedisMessageListenerContainer(); // 设置 RedisConnection 工厂。 @@ -69,8 +69,8 @@ public class RedisConfig { * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html */ @Bean(initMethod = "start", destroyMethod = "stop") - public StreamMessageListenerContainer> redisStreamMessageListenerContainer(RedisTemplate redisTemplate, - List> listeners) { + public StreamMessageListenerContainer> redisStreamMessageListenerContainer( + RedisTemplate redisTemplate, List> listeners) { // 第一步,创建 StreamMessageListenerContainer 容器 // 创建 options 配置 StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java index ddfe2302f..4f0db5c02 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -38,6 +38,7 @@ public class SmsClientFactoryImpl implements SmsClientFactory { AbstractSmsClient client = clients.get(properties.getId()); if (client == null) { client = this.createSmsClient(properties); + client.init(); clients.put(client.getId(), client); } else { client.refresh(properties); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java similarity index 89% rename from src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java rename to src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java index 1e63ca662..70b167168 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SmsSendConsumer.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/sms/SysSmsSendConsumer.java @@ -16,7 +16,7 @@ import javax.annotation.Resource; */ @Component @Slf4j -public class SmsSendConsumer extends AbstractStreamMessageListener { +public class SysSmsSendConsumer extends AbstractStreamMessageListener { @Resource private SysSmsService smsService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java index fd04a62b5..a7a6f8fee 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java @@ -5,7 +5,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import java.util.Map; /** - * 短信日志服务接口 + * 短信日志 Service 实现类 * * @author zzf * @date 13:48 2021/3/2 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java similarity index 96% rename from src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java rename to src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java index 00c43e8f1..32f4883e0 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsSendLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java @@ -15,14 +15,14 @@ import java.util.Map; import java.util.Objects; /** - * 短信发送日志服务实现类 + * 短信日志 Service 实现类 * * @author zzf * @date 2021/1/25 9:25 */ @Slf4j @Service -public class SysSmsSendLogServiceImpl implements SysSmsLogService { +public class SysSmsLogServiceImpl implements SysSmsLogService { @Resource private SysSmsLogMapper smsLogMapper; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 959a997b0..87f8298da 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -12,7 +12,6 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; @@ -41,8 +40,6 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @Slf4j public class SysSmsServiceImpl implements SysSmsService { - @Resource - private SysSmsChannelService smsChannelService; @Resource private SysSmsTemplateService smsTemplateService; @Resource @@ -145,7 +142,8 @@ public class SysSmsServiceImpl implements SysSmsService { SmsCommonResult sendResult = smsClient.send(message.getLogId(), message.getMobile(), message.getApiTemplateId(), message.getTemplateParams()); smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), - sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), sendResult.getData().getSerialNo()); + sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), + sendResult.getData() != null ? sendResult.getData().getSerialNo() : null); } @Override diff --git a/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java new file mode 100644 index 000000000..98e1721c2 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/BaseDbAndRedisIntegrationTest.java @@ -0,0 +1,37 @@ +package cn.iocoder.dashboard; + +import cn.iocoder.dashboard.framework.datasource.config.DataSourceConfiguration; +import cn.iocoder.dashboard.framework.mybatis.config.MybatisConfiguration; +import cn.iocoder.dashboard.framework.redis.config.RedisConfig; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseDbAndRedisIntegrationTest { + + @Import({ + // DB 配置类 + DataSourceConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + DruidDataSourceAutoConfigure.class, // Druid 自动配置类 + // MyBatis 配置类 + MybatisConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + // Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + RedisConfig.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动高配置类 + }) + public static class Application { + } + +} diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java index c976528ae..888357570 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/redis/core/stream/RedisStreamTest.java @@ -4,7 +4,7 @@ import cn.hutool.core.thread.ThreadUtil; import cn.iocoder.dashboard.BaseRedisIntegrationTest; import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; import cn.iocoder.dashboard.modules.system.mq.consumer.mail.SysMailSendConsumer; -import cn.iocoder.dashboard.modules.system.mq.consumer.sms.SmsSendConsumer; +import cn.iocoder.dashboard.modules.system.mq.consumer.sms.SysSmsSendConsumer; import cn.iocoder.dashboard.modules.system.mq.message.mail.SysMailSendMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import org.junit.jupiter.api.Disabled; @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; public class RedisStreamTest { - @Import({SmsSendConsumer.class, SysMailSendConsumer.class}) + @Import({SysSmsSendConsumer.class, SysMailSendConsumer.class}) @Disabled public static class ConsumerTest extends BaseRedisIntegrationTest { diff --git a/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/package-info.java b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/package-info.java new file mode 100644 index 000000000..09c1d9d14 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.dashboard.modules.system.service; diff --git a/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java new file mode 100644 index 000000000..b4d57a719 --- /dev/null +++ b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java @@ -0,0 +1,74 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.thread.ThreadUtil; +import cn.iocoder.dashboard.BaseDbAndRedisIntegrationTest; +import cn.iocoder.dashboard.common.enums.UserTypeEnum; +import cn.iocoder.dashboard.framework.sms.config.SmsConfiguration; +import cn.iocoder.dashboard.modules.system.mq.consumer.sms.SysSmsSendConsumer; +import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsChannelServiceImpl; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsLogServiceImpl; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsServiceImpl; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsTemplateServiceImpl; +import cn.iocoder.dashboard.modules.system.service.user.SysUserService; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Import({SmsConfiguration.class, + SysSmsChannelServiceImpl.class, SysSmsServiceImpl.class, SysSmsTemplateServiceImpl.class, SysSmsLogServiceImpl.class, + SysSmsProducer.class, SysSmsSendConsumer.class}) +public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest { + + @Resource + private SysSmsServiceImpl smsService; + @Resource + private SysSmsChannelServiceImpl smsChannelService; + + @MockBean + private SysUserService userService; + + @Test + public void testSendSingleSms_云片发送成功() { + // 参数准备 + String mobile = "15601691399"; + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + String templateCode = "test_01"; + Map templateParams = MapUtil.builder() + .put("operation", "登陆").put("code", "1234").build(); + // 调用 + smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); + + // 等待 MQ 消费 + ThreadUtil.sleep(1, TimeUnit.HOURS); + } + + @Test + public void testSendSingleSms_阿里云发送成功() { + // 参数准备 + String mobile = "15601691399"; + Long userId = 1L; + Integer userType = UserTypeEnum.ADMIN.getValue(); + String templateCode = "test_02"; + Map templateParams = MapUtil.builder() + .put("code", "1234").build(); + // 调用 + smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams); + + // 等待 MQ 消费 + ThreadUtil.sleep(1, TimeUnit.HOURS); + } + +// @Test +// public void testDoSendSms() { +// // 等待 MQ 消费 +// ThreadUtil.sleep(1, TimeUnit.HOURS); +// } + +} diff --git a/src/test-integration/resources/application-integration-test.yaml b/src/test-integration/resources/application-integration-test.yaml index 88b92273c..43a846ee2 100644 --- a/src/test-integration/resources/application-integration-test.yaml +++ b/src/test-integration/resources/application-integration-test.yaml @@ -9,19 +9,15 @@ spring: # 数据源配置项 datasource: name: ruoyi-vue-pro - url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写 - driver-class-name: org.h2.Driver - username: sa - password: - schema: classpath:sql/create_tables.sql # MySQL 转 H2 的语句,使用 https://www.jooq.org/translate/ 工具 - druid: - async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度 - initial-size: 1 # 单元测试,配置为 1,提升启动速度 + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 redis: host: 127.0.0.1 # 地址 - port: 6379 # 端口(单元测试,使用 16379 端口) + port: 6379 # 端口 database: 0 # 数据库索引 mybatis: From c91833a504242b511c623ab220c1aa105ac17e59 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 4 Apr 2021 01:44:18 +0800 Subject: [PATCH 28/54] =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E7=9A=84=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/SecurityConfiguration.java | 14 +- .../framework/sms/core/client/SmsClient.java | 15 +- .../sms/core/client/SmsClientFactory.java | 8 ++ ...sultDetail.java => SmsReceiveRespDTO.java} | 6 +- .../core/client/impl/AbstractSmsClient.java | 32 +++-- .../client/impl/SmsClientFactoryImpl.java | 36 ++++- .../client/impl/aliyun/AliyunSmsClient.java | 20 +-- .../client/impl/yunpian/YunpianSmsClient.java | 130 +++++++++--------- .../sms/core/enums/SmsChannelEnum.java | 5 +- .../sms/core/enums/SmsConstants.java | 16 --- .../controller/sms/SmsCallbackController.java | 34 +++++ .../sms/SmsDefaultCallbackController.java | 48 ------- .../system/service/sms/SysSmsService.java | 10 +- .../service/sms/impl/SysSmsServiceImpl.java | 15 +- .../dashboard/util/json/JsonUtils.java | 19 ++- .../impl/aliyun/AliyunSmsClientTest.java | 2 +- .../YunpianSmsClientIntegrationTest.java | 2 +- 17 files changed, 225 insertions(+), 187 deletions(-) rename src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/{SmsResultDetail.java => SmsReceiveRespDTO.java} (85%) delete mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java index bb55e1e71..e20431153 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java +++ b/src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java @@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { // 设置每个请求的权限 .authorizeRequests() // 登陆的接口,可匿名访问 - .antMatchers(webProperties.getApiPrefix() + "/login").anonymous() + .antMatchers(api("/login")).anonymous() // 通用的接口,可匿名访问 - .antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous() + .antMatchers(api("/system/captcha/**")).anonymous() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll() // 文件的获取接口,可匿名访问 - .antMatchers(webProperties.getApiPrefix() + "/infra/file/get/**").anonymous() + .antMatchers(api("/infra/file/get/**")).anonymous() // Swagger 接口文档 .antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-resources/**").anonymous() @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { .antMatchers("/actuator/**").anonymous() // Druid 监控 .antMatchers("/druid/**").anonymous() + // 短信回调 API + .antMatchers(api("/system/sms/callback/**")).anonymous() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() .headers().frameOptions().disable(); - httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler); + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler); // 添加 JWT Filter httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } + private String api(String url) { + return webProperties.getApiPrefix() + url; + } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index f343b540f..fc84c5df2 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -1,10 +1,9 @@ package cn.iocoder.dashboard.framework.sms.core.client; import cn.iocoder.dashboard.common.core.KeyValue; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; -import javax.servlet.ServletRequest; import java.util.List; /** @@ -31,15 +30,15 @@ public interface SmsClient { * @param templateParams 短信模板参数 * @return 短信发送结果 */ - SmsCommonResult send(Long logId, String mobile, String apiTemplateId, List> templateParams); + SmsCommonResult sendSms(Long logId, String mobile, String apiTemplateId, List> templateParams); - // TODO FROM 芋艿 to ZZF:是不是可以改成意图更明确的解析返回结果,例如说 parseXXXX /** - * 短信发送回调请求处理 + * 解析接收短信的接收结果 * - * @param request 请求 - * @return 短信发送结果 + * @param text 结果 + * @return 结果内容 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常 */ - SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception; + SmsCommonResult parseSmsReceiveStatus(String text) throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java index f4bc87dd4..83fb88c24 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java @@ -18,6 +18,14 @@ public interface SmsClientFactory { */ SmsClient getSmsClient(Long channelId); + /** + * 获得短信 Client + * + * @param channelCode 渠道编码 + * @return 短信 Client + */ + SmsClient getSmsClient(String channelCode); + /** * 创建短信 Client * diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java similarity index 85% rename from src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java rename to src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java index f8e19db82..b120ca3dd 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsResultDetail.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -7,10 +7,12 @@ import java.io.Serializable; import java.util.Date; /** - * 消息内容实体类 + * 消息接收 Response DTO + * + * @author 芋道源码 */ @Data -public class SmsResultDetail implements Serializable { +public class SmsReceiveRespDTO implements Serializable { /** * 唯一标识 diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index 6e334cf0a..8eb681868 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; @@ -68,12 +69,12 @@ public abstract class AbstractSmsClient implements SmsClient { } @Override - public final SmsCommonResult send(Long logId, String mobile, - String apiTemplateId, List> templateParams) { + public final SmsCommonResult sendSms(Long logId, String mobile, + String apiTemplateId, List> templateParams) { // 执行短信发送 SmsCommonResult result; try { - result = doSend(logId, mobile, apiTemplateId, templateParams); + result = doSendSms(logId, mobile, apiTemplateId, templateParams); } catch (Throwable ex) { // 打印异常日志 log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", @@ -84,17 +85,20 @@ public abstract class AbstractSmsClient implements SmsClient { return result; } - /** - * 发送消息 - * - * @param sendLogId 发送日志编号 - * @param mobile 手机号 - * @param apiTemplateId 短信 API 的模板编号 - * @param templateParams 短信模板参数 - * @return 短信发送结果 - */ - protected abstract SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) + protected abstract SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable; + @Override + public SmsCommonResult parseSmsReceiveStatus(String text) throws Throwable { + try { + return doParseSmsReceiveStatus(text); + } catch (Throwable ex) { + log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex); + throw ex; + } + } + + protected abstract SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable; + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java index 4f0db5c02..cd5197193 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -10,8 +10,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.util.Assert; import org.springframework.validation.annotation.Validated; -import java.util.Map; +import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * 短信客户端工厂接口 @@ -26,20 +27,45 @@ public class SmsClientFactoryImpl implements SmsClientFactory { * 短信客户端 Map * key:渠道编号,使用 {@link SmsChannelProperties#getId()} */ - private final Map clients = new ConcurrentHashMap<>(); + private final ConcurrentMap channelIdClients = new ConcurrentHashMap<>(); + + /** + * 短信客户端 Map + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()} + * + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients} + */ + private final ConcurrentMap channelCodeClients = new ConcurrentHashMap<>(); + + public SmsClientFactoryImpl() { + // 初始化 channelCodeClients 集合 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { + // 创建一个空的 SmsChannelProperties 对象 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()); + // 创建 Sms 客户端 + AbstractSmsClient smsClient = createSmsClient(properties); + channelCodeClients.put(channel.getCode(), smsClient); + }); + } @Override public SmsClient getSmsClient(Long channelId) { - return clients.get(channelId); + return channelIdClients.get(channelId); + } + + @Override + public SmsClient getSmsClient(String channelCode) { + return channelCodeClients.get(channelCode); } @Override public void createOrUpdateSmsClient(SmsChannelProperties properties) { - AbstractSmsClient client = clients.get(properties.getId()); + AbstractSmsClient client = channelIdClients.get(properties.getId()); if (client == null) { client = this.createSmsClient(properties); client.init(); - clients.put(client.getId(), client); + channelIdClients.put(client.getId(), client); } else { client.refresh(properties); } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index acc8a0193..cf7d25160 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; @@ -61,8 +61,8 @@ public class AliyunSmsClient extends AbstractSmsClient { } @Override - protected SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) { + protected SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) { // 构建参数 SendSmsRequest request = new SendSmsRequest(); request.setSysMethod(MethodType.POST); @@ -110,11 +110,10 @@ public class AliyunSmsClient extends AbstractSmsClient { * @return * @throws Exception */ - @Override - public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws Exception { + public SmsReceiveRespDTO smsSendCallbackHandle(ServletRequest request) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); String paramStr = reader.readLine(); - List> params = JsonUtils.parseByType(paramStr, new TypeReference>>() { + List> params = JsonUtils.parseObject(paramStr, new TypeReference>>() { }); if (CollectionUtil.isNotEmpty(params)) { Map sendResultParamMap = params.get(0); @@ -123,6 +122,11 @@ public class AliyunSmsClient extends AbstractSmsClient { return null; } + @Override + protected SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable { + return null; + } + /** * 短信发送回调辅助类 */ @@ -168,8 +172,8 @@ public class AliyunSmsClient extends AbstractSmsClient { return sendResultParamMap.get(CallbackField.OUT_ID).toString(); } - public SmsResultDetail toResultDetail() { - SmsResultDetail resultDetail = new SmsResultDetail(); + public SmsReceiveRespDTO toResultDetail() { + SmsReceiveRespDTO resultDetail = new SmsReceiveRespDTO(); resultDetail.setSendStatus(getSendStatus()); resultDetail.setApiId(getBizId()); resultDetail.setSendTime(getSendTime()); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 249d8c481..d67bc55be 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -2,33 +2,31 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; -import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsResultDetail; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; -import cn.iocoder.dashboard.framework.sms.core.enums.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; +import cn.iocoder.dashboard.util.date.DateUtils; import cn.iocoder.dashboard.util.json.JsonUtils; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; import com.yunpian.sdk.model.SmsSingleSend; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import javax.servlet.ServletRequest; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringJoiner; +import java.util.*; /** * 云片短信客户端的实现类 @@ -65,8 +63,8 @@ public class YunpianSmsClient extends AbstractSmsClient { } @Override - protected SmsCommonResult doSend(Long sendLogId, String mobile, - String apiTemplateId, List> templateParams) throws Throwable { + protected SmsCommonResult doSendSms(Long sendLogId, String mobile, + String apiTemplateId, List> templateParams) throws Throwable { // 构建参数 Map request = new HashMap<>(); request.put(YunpianConstant.APIKEY, properties.getApiKey()); @@ -74,7 +72,7 @@ public class YunpianSmsClient extends AbstractSmsClient { request.put(YunpianConstant.TPL_ID, apiTemplateId); request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); request.put(YunpianConstant.UID, String.valueOf(sendLogId)); - request.put(Helper.CALLBACK, properties.getCallbackUrl()); + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); // 执行发送 Result sendResult = client.sms().tpl_single_send(request); @@ -107,15 +105,6 @@ public class YunpianSmsClient extends AbstractSmsClient { return sendResult.getMsg() + " => " + sendResult.getDetail(); } - /** - * 云片的比较复杂,又是加密又是套娃的 - */ - @Override - public SmsResultDetail smsSendCallbackHandle(ServletRequest request) throws UnsupportedEncodingException { - Map map = getRequestParams(request); - return Helper.getSmsResultDetailByParam(map); - } - /** * 从 request 中获取请求中传入的短信发送结果信息 * @@ -127,7 +116,7 @@ public class YunpianSmsClient extends AbstractSmsClient { Map parameterMap = request.getParameterMap(); String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); - List> paramList = JsonUtils.parseByType(encode, callbackType); + List> paramList = JsonUtils.parseObject(encode, callbackType); if (CollectionUtil.isNotEmpty(paramList)) { return paramList.get(0); } @@ -135,46 +124,63 @@ public class YunpianSmsClient extends AbstractSmsClient { + JsonUtils.toJsonString(request.getParameterMap())); } - /** - * 云片的回调函数的一些辅助方法 - */ - private static class Helper { - - //短信唯一标识 - private final static String API_ID = "sid"; - - //回调地址· - private final static String CALLBACK = "callback"; - - //手机号 - private final static String MOBILE = "mobile"; - - //错误信息 - private final static String ERROR_MSG = "error_msg"; - - //用户接收时间 字符串 标准格式 - private final static String USER_RECEIVE_TIME = "user_receive_time"; - - //发送状态 - private final static String REPORT_STATUS = "report_status"; - - private static int getSendStatus(Map map) { - String reportStatus = map.get(REPORT_STATUS); - return SmsConstants.SUCCESS.equals(reportStatus) - ? SysSmsSendStatusEnum.SUCCESS.getStatus() - : SysSmsSendStatusEnum.FAILURE.getStatus(); - } - - public static SmsResultDetail getSmsResultDetailByParam(Map map) { - SmsResultDetail detail = new SmsResultDetail(); - detail.setPhone(map.get(MOBILE)); - detail.setMessage(map.get(ERROR_MSG)); - detail.setSendTime(DateUtil.parseTime(map.get(USER_RECEIVE_TIME))); - detail.setSendStatus(getSendStatus(map)); - detail.setApiId(API_ID); - - detail.setCallbackResponseBody(SmsConstants.SUCCESS); - return detail; - } + @Override + protected SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable { + return null; } + + /** + * 短信接收状态 + * + * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档 + * + * @author 芋道源码 + */ + @Data + public static class SmsReceiveStatus { + + /** + * 运营商反馈代码的中文解释 + * + * 默认不推送此字段,如需推送,请联系客服 + */ + @JsonProperty("error_detail") + private String errorDetail; + /** + * 短信编号 + */ + private Long sid; + /** + * 用户自定义 id + * + * 这里我们传递的是 SysSmsLogDO 的日志编号 + */ + private Long uid; + /** + * 用户接收时间 + */ + @JsonProperty("user_receive_time") + @JsonFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date userReceiveTime; + /** + * 运营商返回的代码,如:"DB:0103" + * + * 由于不同运营商信息不同,此字段仅供参考; + */ + @JsonProperty("error_msg") + private String errorMsg; + /** + * 接收手机号 + */ + private String mobile; + /** + * 接收状态 + * + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 + */ + @JsonProperty("report_status") + private String reportStatus; + + } + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java index 213034882..f2e675198 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java @@ -16,8 +16,9 @@ public enum SmsChannelEnum { YUN_PIAN("YUN_PIAN", "云片"), ALIYUN("ALIYUN", "阿里云"), - TENCENT("TENCENT", "腾讯云"), - HUA_WEI("HUA_WEI", "华为云"),; +// TENCENT("TENCENT", "腾讯云"), +// HUA_WEI("HUA_WEI", "华为云"), + ; /** * 编码 diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java deleted file mode 100644 index e699db96e..000000000 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsConstants.java +++ /dev/null @@ -1,16 +0,0 @@ -package cn.iocoder.dashboard.framework.sms.core.enums; - -/** - * 短信相关常量类 - * - * @author zzf - * @date 2021/3/5 10:42 - */ -public interface SmsConstants { - - - String COMMA = ","; - - String SUCCESS = "SUCCESS"; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java new file mode 100644 index 000000000..f8e845380 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java @@ -0,0 +1,34 @@ +package cn.iocoder.dashboard.modules.system.controller.sms; + +import cn.hutool.core.util.URLUtil; +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +@Api(tags = "短信回调") +@RestController +@RequestMapping("/system/sms/callback") +public class SmsCallbackController { + + @Resource + private SysSmsService smsService; + + @PostMapping("/sms/yunpian") + @ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档") + @ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = Long.class) + public CommonResult receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable { + String text = URLUtil.decode(smsStatus); // decode 解码参数,因为它被 encode + smsService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text); + return CommonResult.success(true); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java deleted file mode 100644 index 3d4661076..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsDefaultCallbackController.java +++ /dev/null @@ -1,48 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms; - -import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; -import javax.servlet.ServletRequest; - -/** - * 短信默认回调接口 - * - * @author zzf - * @date 2021/3/5 8:59 - */ -@Api(tags = "短信回调api") -@RestController -@RequestMapping("/sms/callback") -public class SmsDefaultCallbackController { - - @Resource - private SysSmsService smsService; - - - @ApiOperation(value = "短信发送回调接口") - @PostMapping("/sms-send") - public Object sendSmsCallback(ServletRequest request) { - return smsService.smsSendCallbackHandle(request); - } - -/* - @Resource - private SmsSendStreamProducer smsSendStreamProducer; - - @ApiOperation("redis stream测试") - @GetMapping("/test/redis/stream") - public void test() { - SmsBody smsBody = new SmsBody(); - smsBody.setSmsLogId(1L); - smsBody.setTemplateCode("sdf"); - smsBody.setTemplateContent("sdf"); - smsSendStreamProducer.sendSmsSendMessage(smsBody, "18216466755"); - }*/ - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java index 34fcf4e9c..ec3691377 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsService.java @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; -import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; @@ -24,11 +23,12 @@ public interface SysSmsService { void doSendSms(SysSmsSendMessage message); /** - * 处理短信发送回调函数 + * 接收短信的接收结果 * - * @param request 请求 - * @return 响应数据 + * @param channelCode 渠道编码 + * @param text 结果内容 + * @throws Throwable 处理失败时,抛出异常 */ - Object smsSendCallbackHandle(ServletRequest request); + void receiveSmsStatus(String channelCode, String text) throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 87f8298da..2e6624de6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -7,6 +7,7 @@ import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; @@ -21,7 +22,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; -import javax.servlet.ServletRequest; import java.util.List; import java.util.Map; import java.util.Objects; @@ -139,7 +139,7 @@ public class SysSmsServiceImpl implements SysSmsService { SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId()); Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", message.getChannelId())); // 发送短信 - SmsCommonResult sendResult = smsClient.send(message.getLogId(), message.getMobile(), + SmsCommonResult sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(), message.getApiTemplateId(), message.getTemplateParams()); smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(), sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(), @@ -147,11 +147,12 @@ public class SysSmsServiceImpl implements SysSmsService { } @Override - public Object smsSendCallbackHandle(ServletRequest request) { -// SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); -// logService.updateSendLogByResultDetail(smsResultDetail); -// return smsResultDetail.getCallbackResponseBody(); - return null; + public void receiveSmsStatus(String channelCode, String text) throws Throwable { + // 获得渠道对应的 SmsClient 客户端 + SmsClient smsClient = smsClientFactory.getSmsClient(channelCode); + Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode)); + // 解析内容 + SmsCommonResult receiveResult = smsClient.parseSmsReceiveStatus(text); } } diff --git a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java index 2a735e214..c7a9483eb 100644 --- a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java @@ -2,12 +2,14 @@ package cn.iocoder.dashboard.util.json; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** * JSON 工具类 @@ -59,7 +61,7 @@ public class JsonUtils { } } - public static Object parseObject(String text, TypeReference> typeReference) { + public static T parseObject(String text, TypeReference typeReference) { try { return objectMapper.readValue(text, typeReference); } catch (IOException e) { @@ -67,12 +69,21 @@ public class JsonUtils { } } - public static T parseByType(String text, TypeReference typeReference) { + public static List parseArray(String text, Class clazz) { + if (StrUtil.isEmpty(text)) { + return new ArrayList<>(); + } try { - return objectMapper.readValue(text, typeReference); + return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); } catch (IOException e) { throw new RuntimeException(e); } } + public static void main(String[] args) { + String text = "[{\"sid\":9527,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"},{\"sid\":9528,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:23\",\"error_msg\":\"\",\"mobile\":\"15212341234\",\"report_status\":\"SUCCESS\"}]"; + List result = parseArray(text, YunpianSmsClient.SmsReceiveStatus.class); + System.out.println(result); + } + } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java index baae08886..4e3fccba4 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -32,7 +32,7 @@ public class AliyunSmsClientTest { templateParams.add(new KeyValue<>("code", "1024")); // templateParams.put("operation", "嘿嘿"); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsCommonResult result = smsClient.send(1L, "15601691399", "SMS_207945135", templateParams); + SmsCommonResult result = smsClient.sendSms(1L, "15601691399", "SMS_207945135", templateParams); System.out.println(result); } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java index 6e4d4315c..039ed3bff 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java @@ -31,7 +31,7 @@ public class YunpianSmsClientIntegrationTest { templateParams.add(new KeyValue<>("code", "1024")); templateParams.add(new KeyValue<>("operation", "嘿嘿")); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsCommonResult result = smsClient.send(1L, "15601691399", "4383920", templateParams); + SmsCommonResult result = smsClient.sendSms(1L, "15601691399", "4383920", templateParams); System.out.println(result); } From 8ab29d2a257e7fbbdbae4230137a83ea64a7f5a6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 4 Apr 2021 13:12:42 +0800 Subject: [PATCH 29/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E7=9A=84=E8=A7=A3=E6=9E=90=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/core/client/SmsClient.java | 2 +- .../core/client/dto/SmsReceiveRespDTO.java | 44 ++-- .../core/client/impl/AbstractSmsClient.java | 4 +- .../client/impl/aliyun/AliyunSmsClient.java | 205 +++++++----------- .../client/impl/yunpian/YunpianSmsClient.java | 83 +++---- .../service/sms/impl/SysSmsServiceImpl.java | 2 +- .../dashboard/util/date/DateUtils.java | 5 + .../dashboard/util/json/JsonUtils.java | 7 - ...va => AliyunSmsClientIntegrationTest.java} | 2 +- .../sms/SysSmsServiceIntegrationTest.java | 4 +- .../dashboard/framework/package-info.java | 1 + .../impl/aliyun/AliyunSmsClientTest.java | 60 +++++ .../impl/yunpian/YunpianSmsClientTest.java | 50 +++++ 13 files changed, 254 insertions(+), 215 deletions(-) rename src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/{AliyunSmsClientTest.java => AliyunSmsClientIntegrationTest.java} (97%) create mode 100644 src/test/java/cn/iocoder/dashboard/framework/package-info.java create mode 100644 src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java create mode 100644 src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index fc84c5df2..591ded92e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -39,6 +39,6 @@ public interface SmsClient { * @return 结果内容 * @throws Throwable 当解析 text 发生异常时,则会抛出异常 */ - SmsCommonResult parseSmsReceiveStatus(String text) throws Throwable; + List parseSmsReceiveStatus(String text) throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java index b120ca3dd..c1ccd1e65 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -1,9 +1,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.dto; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import lombok.Data; -import java.io.Serializable; import java.util.Date; /** @@ -12,35 +10,39 @@ import java.util.Date; * @author 芋道源码 */ @Data -public class SmsReceiveRespDTO implements Serializable { +public class SmsReceiveRespDTO { /** - * 唯一标识 + * 是否接收成功 */ - private String apiId; + private Boolean success; + /** + * API 接收结果编码 + */ + private String errorCode; + /** + * API 接收结果说明 + */ + private String errorMsg; /** - * 短信发送状态 {@link SysSmsSendStatusEnum} + * 手机号 */ - private Integer sendStatus; + private String mobile; + /** + * 用户接收时间 + */ + private Date receiveTime; /** - * 接收手机号 + * 短信 API 发送返回的序号 */ - private String phone; - + private String serialNo; /** - * 提示 + * 短信日志编号 + * + * 对应 SysSmsLogDO 的编号 */ - private String message; + private Long logId; - /** - * 时间 - */ - private Date sendTime; - - /** - * 接口返回值 - */ - private Object callbackResponseBody; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index 8eb681868..a443e5e11 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -90,7 +90,7 @@ public abstract class AbstractSmsClient implements SmsClient { throws Throwable; @Override - public SmsCommonResult parseSmsReceiveStatus(String text) throws Throwable { + public List parseSmsReceiveStatus(String text) throws Throwable { try { return doParseSmsReceiveStatus(text); } catch (Throwable ex) { @@ -99,6 +99,6 @@ public abstract class AbstractSmsClient implements SmsClient { } } - protected abstract SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable; + protected abstract List doParseSmsReceiveStatus(String text) throws Throwable; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index cf7d25160..954250788 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -1,7 +1,5 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; -import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; @@ -9,7 +7,6 @@ import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.util.collection.MapUtils; import cn.iocoder.dashboard.util.json.JsonUtils; import com.aliyuncs.DefaultAcsClient; @@ -20,16 +17,17 @@ import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; -import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; import lombok.extern.slf4j.Slf4j; -import javax.servlet.ServletRequest; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.stream.Collectors; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT; /** * 阿里短信客户端的实现类 @@ -40,8 +38,9 @@ import java.util.Map; @Slf4j public class AliyunSmsClient extends AbstractSmsClient { - private static final String PRODUCT = "Dystopi"; - private static final String DOMAIN = "dysmsapi.aliyuncs.com"; + /** + * REGION, 使用杭州 + */ private static final String ENDPOINT = "cn-hangzhou"; /** @@ -56,7 +55,6 @@ public class AliyunSmsClient extends AbstractSmsClient { @Override protected void doInit() { IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret()); - DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); acsClient = new DefaultAcsClient(profile); } @@ -93,133 +91,80 @@ public class AliyunSmsClient extends AbstractSmsClient { return ex.getErrMsg() + " => " + ex.getErrorDescription(); } - /** - * [{ - * "send_time" : "2017-08-30 00:00:00", - * "report_time" : "2017-08-30 00:00:00", - * "success" : true, - * "err_msg" : "用户接收成功", - * "err_code" : "DELIVERED", - * "phone_number" : "18612345678", - * "sms_size" : "1", - * "biz_id" : "932702304080415357^0", - * "out_id" : "1184585343" - * }] - * - * @param request 请求 - * @return - * @throws Exception - */ - public SmsReceiveRespDTO smsSendCallbackHandle(ServletRequest request) throws Exception { - BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); - String paramStr = reader.readLine(); - List> params = JsonUtils.parseObject(paramStr, new TypeReference>>() { - }); - if (CollectionUtil.isNotEmpty(params)) { - Map sendResultParamMap = params.get(0); - return CallbackHelper.of(sendResultParamMap).toResultDetail(); - } - return null; - } - @Override - protected SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable { - return null; + protected List doParseSmsReceiveStatus(String text) throws Throwable { + List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return statuses.stream().map(status -> { + SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); + resp.setSuccess(status.getSuccess()); + resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg()); + resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime()); + resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())); + return resp; + }).collect(Collectors.toList()); } /** - * 短信发送回调辅助类 + * 短信接收状态 + * + * 参见 https://help.aliyun.com/document_detail/101867.html 文档 + * + * @author 芋道源码 */ - private static class CallbackHelper { - - private final Map sendResultParamMap; - - private CallbackHelper(Map sendResultParamMap) { - this.sendResultParamMap = sendResultParamMap; - } - - public static CallbackHelper of(Map sendResultParamMap) { - return new CallbackHelper(sendResultParamMap); - } - - public Integer getSendStatus() { - return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) - ? SysSmsSendStatusEnum.SUCCESS.getStatus() - : SysSmsSendStatusEnum.FAILURE.getStatus(); - } - - public String getBizId() { - return sendResultParamMap.get(CallbackField.BIZ_ID).toString(); - } - - public String getErrMsg() { - return sendResultParamMap.get(CallbackField.ERR_MSG).toString(); - } - - public String getErrCode() { - return sendResultParamMap.get(CallbackField.ERR_CODE).toString(); - } - - public Date getSendTime() { - return DateUtil.parseTime(sendResultParamMap.get(CallbackField.SEND_TIME).toString()); - } - - public String getPhoneNumber() { - return sendResultParamMap.get(CallbackField.PHONE_NUMBER).toString(); - } - - public String getOutId() { - return sendResultParamMap.get(CallbackField.OUT_ID).toString(); - } - - public SmsReceiveRespDTO toResultDetail() { - SmsReceiveRespDTO resultDetail = new SmsReceiveRespDTO(); - resultDetail.setSendStatus(getSendStatus()); - resultDetail.setApiId(getBizId()); - resultDetail.setSendTime(getSendTime()); - resultDetail.setPhone(getPhoneNumber()); - resultDetail.setMessage(getErrMsg()); - - resultDetail.setCallbackResponseBody(generateSuccessResponseBody()); - return resultDetail; - } + @Data + public static class SmsReceiveStatus { /** - * 生成回调成功的返回对象 + * 手机号 */ - private Map generateSuccessResponseBody() { - Map result = new HashMap<>(); - result.put("code", 0); - result.put("msg", "成功"); - return result; - } + @JsonProperty("phone_number") + private String phoneNumber; + /** + * 发送时间 + */ + @JsonProperty("send_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date sendTime; + /** + * 状态报告时间 + */ + @JsonProperty("report_time") + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date reportTime; + /** + * 是否接收成功 + */ + private Boolean success; + /** + * 状态报告说明 + */ + @JsonProperty("err_msg") + private String errMsg; + /** + * 状态报告编码 + */ + @JsonProperty("err_code") + private String errCode; + /** + * 发送序列号 + */ + @JsonProperty("biz_id") + private String bizId; + /** + * 用户序列号 + * + * 这里我们传递的是 SysSmsLogDO 的日志编号 + */ + @JsonProperty("out_id") + private String outId; + /** + * 短信长度,例如说 1、2、3 + * + * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送 + */ + @JsonProperty("sms_size") + private Integer smsSize; } - /** - * 回调接口字段定义 - */ - private interface CallbackField { - //是否成功 boolean - String SUCCESS = "success"; - - //发送时间 - String SEND_TIME = "send_time"; - - //错误信息 - String ERR_MSG = "err_msg"; - - //错误编码 - String ERR_CODE = "err_code"; - - //手机号 - String PHONE_NUMBER = "phone_number"; - - //用户序列号 out_id - String OUT_ID = "out_id"; - - //biz_id 即 apiId 唯一标识 - String BIZ_ID = "biz_id"; - } - } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index d67bc55be..ea0aedf13 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -1,8 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.CollectionUtil; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.common.core.KeyValue; @@ -11,11 +9,9 @@ import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.dashboard.util.date.DateUtils; import cn.iocoder.dashboard.util.json.JsonUtils; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.type.TypeReference; import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; @@ -23,10 +19,11 @@ import com.yunpian.sdk.model.SmsSingleSend; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import javax.servlet.ServletRequest; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT; /** * 云片短信客户端的实现类 @@ -42,9 +39,6 @@ public class YunpianSmsClient extends AbstractSmsClient { */ private volatile YunpianClient client; - private final TypeReference>> callbackType = new TypeReference>>() { - }; - public YunpianSmsClient(SmsChannelProperties properties) { super(properties, new YunpianSmsCodeMapping()); } @@ -105,28 +99,17 @@ public class YunpianSmsClient extends AbstractSmsClient { return sendResult.getMsg() + " => " + sendResult.getDetail(); } - /** - * 从 request 中获取请求中传入的短信发送结果信息 - * - * @param request 回调请求 - * @return 短信发送结果信息 - * @throws UnsupportedEncodingException 解码异常 - */ - private Map getRequestParams(ServletRequest request) throws UnsupportedEncodingException { - Map parameterMap = request.getParameterMap(); - String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS); - String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8); - List> paramList = JsonUtils.parseObject(encode, callbackType); - if (CollectionUtil.isNotEmpty(paramList)) { - return paramList.get(0); - } - throw new IllegalArgumentException("YunpianSmsClient getRequestParams fail! can't format RequestParam: " - + JsonUtils.toJsonString(request.getParameterMap())); - } - @Override - protected SmsCommonResult doParseSmsReceiveStatus(String text) throws Throwable { - return null; + protected List doParseSmsReceiveStatus(String text) throws Throwable { + List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); + return statuses.stream().map(status -> { + SmsReceiveRespDTO resp = new SmsReceiveRespDTO(); + resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS")); + resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail()); + resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime()); + resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid()); + return resp; + }).collect(Collectors.toList()); } /** @@ -139,6 +122,24 @@ public class YunpianSmsClient extends AbstractSmsClient { @Data public static class SmsReceiveStatus { + /** + * 接收状态 + * + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 + */ + @JsonProperty("report_status") + private String reportStatus; + /** + * 接收手机号 + */ + private String mobile; + /** + * 运营商返回的代码,如:"DB:0103" + * + * 由于不同运营商信息不同,此字段仅供参考; + */ + @JsonProperty("error_msg") + private String errorMsg; /** * 运营商反馈代码的中文解释 * @@ -160,26 +161,8 @@ public class YunpianSmsClient extends AbstractSmsClient { * 用户接收时间 */ @JsonProperty("user_receive_time") - @JsonFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) private Date userReceiveTime; - /** - * 运营商返回的代码,如:"DB:0103" - * - * 由于不同运营商信息不同,此字段仅供参考; - */ - @JsonProperty("error_msg") - private String errorMsg; - /** - * 接收手机号 - */ - private String mobile; - /** - * 接收状态 - * - * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收 - */ - @JsonProperty("report_status") - private String reportStatus; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 2e6624de6..5a3487a5f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -152,7 +152,7 @@ public class SysSmsServiceImpl implements SysSmsService { SmsClient smsClient = smsClientFactory.getSmsClient(channelCode); Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode)); // 解析内容 - SmsCommonResult receiveResult = smsClient.parseSmsReceiveStatus(text); + List receiveResults = smsClient.parseSmsReceiveStatus(text); } } diff --git a/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java b/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java index 3ae810982..78ec48392 100644 --- a/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/date/DateUtils.java @@ -9,6 +9,11 @@ import java.util.Date; */ public class DateUtils { + /** + * 时区 - 默认 + */ + public static final String TIME_ZONE_DEFAULT = "GMT+8"; + public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss"; public static Date addTime(Duration duration) { diff --git a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java index c7a9483eb..2291235dc 100644 --- a/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/json/JsonUtils.java @@ -2,7 +2,6 @@ package cn.iocoder.dashboard.util.json; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -80,10 +79,4 @@ public class JsonUtils { } } - public static void main(String[] args) { - String text = "[{\"sid\":9527,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"},{\"sid\":9528,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:23\",\"error_msg\":\"\",\"mobile\":\"15212341234\",\"report_status\":\"SUCCESS\"}]"; - List result = parseArray(text, YunpianSmsClient.SmsReceiveStatus.class); - System.out.println(result); - } - } diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java similarity index 97% rename from src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java rename to src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java index 4e3fccba4..8643a3a6c 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java @@ -13,7 +13,7 @@ import java.util.List; /** * {@link AliyunSmsClient} 的集成测试 */ -public class AliyunSmsClientTest { +public class AliyunSmsClientIntegrationTest { @Test public void testSend() { diff --git a/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java index b4d57a719..7ec704b5d 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsServiceIntegrationTest.java @@ -34,7 +34,7 @@ public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest private SysUserService userService; @Test - public void testSendSingleSms_云片发送成功() { + public void testSendSingleSms_yunpianSuccess() { // 参数准备 String mobile = "15601691399"; Long userId = 1L; @@ -50,7 +50,7 @@ public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest } @Test - public void testSendSingleSms_阿里云发送成功() { + public void testSendSingleSms_aliyunSuccess() { // 参数准备 String mobile = "15601691399"; Long userId = 1L; diff --git a/src/test/java/cn/iocoder/dashboard/framework/package-info.java b/src/test/java/cn/iocoder/dashboard/framework/package-info.java new file mode 100644 index 000000000..0274647fb --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/framework/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.dashboard.framework; diff --git a/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java b/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java new file mode 100644 index 000000000..3744a29f6 --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java @@ -0,0 +1,60 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; + +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.dashboard.util.date.DateUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link AliyunSmsClient} 的单元测试 + */ +public class AliyunSmsClientTest { + + @InjectMocks + private final AliyunSmsClient smsClient = new AliyunSmsClient(null); + + @Test + void doInit() { + } + + @Test + void doSendSms() { + } + + @Test + public void testDoTParseSmsReceiveStatus() throws Throwable { + // 准备参数 + String text = "[\n" + + " {\n" + + " \"phone_number\" : \"13900000001\",\n" + + " \"send_time\" : \"2017-01-01 11:12:13\",\n" + + " \"report_time\" : \"2017-02-02 22:23:24\",\n" + + " \"success\" : true,\n" + + " \"err_code\" : \"DELIVERED\",\n" + + " \"err_msg\" : \"用户接收成功\",\n" + + " \"sms_size\" : \"1\",\n" + + " \"biz_id\" : \"12345\",\n" + + " \"out_id\" : \"67890\"\n" + + " }\n" + + "]"; + // mock 方法 + + // 调用 + List statuses = smsClient.doParseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("DELIVERED", statuses.get(0).getErrorCode()); + assertEquals("用户接收成功", statuses.get(0).getErrorMsg()); + assertEquals("13900000001", statuses.get(0).getMobile()); + assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime()); + assertEquals("12345", statuses.get(0).getSerialNo()); + assertEquals(67890L, statuses.get(0).getLogId()); + } + +} diff --git a/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java b/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java new file mode 100644 index 000000000..c4bd38cfb --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java @@ -0,0 +1,50 @@ +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; + +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; +import cn.iocoder.dashboard.util.date.DateUtils; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 对 {@link YunpianSmsClient} 的单元测试 + */ +public class YunpianSmsClientTest { + + @InjectMocks + private final YunpianSmsClient smsClient = new YunpianSmsClient(null); + + @Test + void doInit() { + } + + @Test + void doSendSms() { + } + + @Test + void testDoParseSmsReceiveStatus() throws Throwable { + // 准备参数 + String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]"; + // mock 方法 + + // 调用 + + // 断言 + // 调用 + List statuses = smsClient.doParseSmsReceiveStatus(text); + // 断言 + assertEquals(1, statuses.size()); + assertTrue(statuses.get(0).getSuccess()); + assertEquals("", statuses.get(0).getErrorCode()); + assertNull(statuses.get(0).getErrorMsg()); + assertEquals("15205201314", statuses.get(0).getMobile()); + assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime()); + assertEquals("9527", statuses.get(0).getSerialNo()); + assertEquals(1024L, statuses.get(0).getLogId()); + } + +} From 86cbf21d6d659b7580e1f1c90f2558aa6e1df0e6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 4 Apr 2021 23:28:00 +0800 Subject: [PATCH 30/54] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=91=E7=89=87?= =?UTF-8?q?=E7=9A=84=E5=8F=91=E9=80=81=E5=9B=9E=E6=89=A7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/client/dto/SmsReceiveRespDTO.java | 4 ++-- .../controller/sms/SmsCallbackController.java | 7 +++--- .../dal/dataobject/sms/SysSmsLogDO.java | 23 +++++++++++++++---- .../enums/sms/SysSmsReceiveStatusEnum.java | 23 +++++++++++++++++++ .../system/service/sms/SysSmsLogService.java | 14 ++++++++++- .../sms/impl/SysSmsLogServiceImpl.java | 14 ++++++++++- .../service/sms/impl/SysSmsServiceImpl.java | 9 ++++++++ 7 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsReceiveStatusEnum.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java index c1ccd1e65..ecfdb045c 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java @@ -17,11 +17,11 @@ public class SmsReceiveRespDTO { */ private Boolean success; /** - * API 接收结果编码 + * API 接收结果的编码 */ private String errorCode; /** - * API 接收结果说明 + * API 接收结果的说明 */ private String errorMsg; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java index f8e845380..d81ecfa4b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java @@ -1,7 +1,7 @@ package cn.iocoder.dashboard.modules.system.controller.sms; import cn.hutool.core.util.URLUtil; -import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import io.swagger.annotations.Api; @@ -25,10 +25,11 @@ public class SmsCallbackController { @PostMapping("/sms/yunpian") @ApiOperation(value = "云片短信的回调", notes = "参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档") @ApiImplicitParam(name = "sms_status", value = "发送状态", required = true, example = "[{具体内容}]", dataTypeClass = Long.class) - public CommonResult receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable { + @OperateLog(enable = false) + public String receiveYunpianSmsStatus(@RequestParam("sms_status") String smsStatus) throws Throwable { String text = URLUtil.decode(smsStatus); // decode 解码参数,因为它被 encode smsService.receiveSmsStatus(SmsChannelEnum.YUN_PIAN.getCode(), text); - return CommonResult.success(true); + return "SUCCESS"; // 约定返回 SUCCESS 为成功 } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java index 44d0da639..78e04e117 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/dataobject/sms/SysSmsLogDO.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; import cn.iocoder.dashboard.common.enums.UserTypeEnum; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsReceiveStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; @@ -150,9 +151,23 @@ public class SysSmsLogDO extends BaseDO { // ========= 接收相关字段 ========= -// /** -// * 是否获取过结果[0否 1是] -// */ -// private Integer gotResult; + /** + * 接收状态 + * + * 枚举 {@link SysSmsReceiveStatusEnum} + */ + private Integer receiveStatus; + /** + * 接收时间 + */ + private Date receiveTime; + /** + * 短信 API 接收结果的编码 + */ + private String apiReceiveCode; + /** + * 短信 API 接收结果的提示 + */ + private String apiReceiveMsg; } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsReceiveStatusEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsReceiveStatusEnum.java new file mode 100644 index 000000000..880238822 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/sms/SysSmsReceiveStatusEnum.java @@ -0,0 +1,23 @@ +package cn.iocoder.dashboard.modules.system.enums.sms; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信的接收状态枚举 + * + * @author 芋道源码 + * @date 2021/2/1 13:39 + */ +@Getter +@AllArgsConstructor +public enum SysSmsReceiveStatusEnum { + + INIT(0), // 初始化 + SUCCESS(10), // 接收成功 + FAILURE(20), // 接收失败 + ; + + private final int status; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java index a7a6f8fee..33fb86a36 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsLogService.java @@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import java.util.Date; import java.util.Map; /** @@ -28,7 +29,7 @@ public interface SysSmsLogService { SysSmsTemplateDO template, String templateContent, Map templateParams); /** - * 更新发送日志的结果 + * 更新日志的发送结果 * * @param id 日志编号 * @param sendCode 发送结果的编码 @@ -41,4 +42,15 @@ public interface SysSmsLogService { void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo); + /** + * 更新日志的接收结果 + * + * @param id 日志编号 + * @param success 是否接收成功 + * @param receiveTime 用户接收时间 + * @param apiReceiveCode API 接收结果的编码 + * @param apiReceiveMsg API 接收结果的说明 + */ + void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java index 32f4883e0..6dcd9de7c 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsLogServiceImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsLogMapper; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsReceiveStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsLogService; import lombok.extern.slf4j.Slf4j; @@ -41,6 +42,8 @@ public class SysSmsLogServiceImpl implements SysSmsLogService { logBuilder.templateContent(templateContent).templateParams(templateParams).apiTemplateId(template.getApiTemplateId()); // 设置渠道相关字段 logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode()); + // 设置接收相关字段 + logBuilder.receiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus()); // 插入数据库 SysSmsLogDO logDO = logBuilder.build(); @@ -51,10 +54,19 @@ public class SysSmsLogServiceImpl implements SysSmsLogService { @Override public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg, String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) { - SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE; + SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS + : SysSmsSendStatusEnum.FAILURE; smsLogMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date()) .sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg) .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build()); } + @Override + public void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg) { + SysSmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ? SysSmsReceiveStatusEnum.SUCCESS + : SysSmsReceiveStatusEnum.FAILURE; + smsLogMapper.updateById(SysSmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus()).receiveTime(receiveTime) + .apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build()); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index 5a3487a5f..c5a12797f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; @@ -153,6 +154,14 @@ public class SysSmsServiceImpl implements SysSmsService { Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode)); // 解析内容 List receiveResults = smsClient.parseSmsReceiveStatus(text); + if (CollUtil.isEmpty(receiveResults)) { + return; + } + // 更新短信日志的接收结果. 因为量一般不打,所以先使用 for 循环更新 + receiveResults.forEach(result -> { + smsLogService.updateSmsReceiveResult(result.getLogId(), result.getSuccess(), result.getReceiveTime(), + result.getErrorCode(), result.getErrorCode()); + }); } } From d8d458a0249f2138be8c5eb13e8086202399a7be Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Apr 2021 02:52:58 +0800 Subject: [PATCH 31/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=B8=A0=E9=81=93?= =?UTF-8?q?=E7=9A=84=20CRUD=20=E5=90=8E=E7=AB=AF=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=9A=84=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sms/SmsCallbackController.java | 14 ++ .../controller/sms/SmsChannelController.java | 60 +++++-- .../controller/sms/vo/SmsChannelAllVO.java | 58 ------- .../sms/vo/channel/SysSmsChannelBaseVO.java | 36 +++++ .../vo/channel/SysSmsChannelCreateReqVO.java | 21 +++ .../vo/channel/SysSmsChannelPageReqVO.java | 35 ++++ .../sms/vo/channel/SysSmsChannelRespVO.java | 26 +++ .../vo/channel/SysSmsChannelUpdateReqVO.java | 21 +++ .../sms/vo/req/SmsChannelCreateReqVO.java | 44 ------ .../sms/vo/req/SmsChannelPageReqVO.java | 21 --- .../sms/vo/resp/SmsChannelPageRespVO.java | 43 ----- .../system/convert/sms/SmsChannelConvert.java | 28 ---- .../convert/sms/SysSmsChannelConvert.java | 36 +++++ .../dal/mysql/sms/SysSmsChannelMapper.java | 16 +- .../system/enums/SysErrorCodeConstants.java | 18 +-- .../system/enums/dict/SysDictTypeEnum.java | 1 + .../service/sms/SysSmsChannelService.java | 55 +++++-- .../sms/impl/SysSmsChannelServiceImpl.java | 80 ++++++---- .../service/dept/SysDeptServiceTest.java | 1 + .../service/sms/SysSmsChannelServiceTest.java | 149 ++++++++++++++++++ src/test/resources/sql/clean.sql | 1 + src/test/resources/sql/create_tables.sql | 26 ++- 22 files changed, 520 insertions(+), 270 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java create mode 100644 src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java index d81ecfa4b..30d75bca5 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsCallbackController.java @@ -1,6 +1,8 @@ package cn.iocoder.dashboard.modules.system.controller.sms; import cn.hutool.core.util.URLUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; @@ -13,6 +15,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import static cn.iocoder.dashboard.common.pojo.CommonResult.success; @Api(tags = "短信回调") @RestController @@ -32,4 +37,13 @@ public class SmsCallbackController { return "SUCCESS"; // 约定返回 SUCCESS 为成功 } + @PostMapping("/sms/aliyun") + @ApiOperation(value = "阿里云短信的回调", notes = "参见 https://help.aliyun.com/document_detail/120998.html 文档") + @OperateLog(enable = false) + public CommonResult receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable { + String text = ServletUtil.getBody(request); + smsService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text); + return success(true); + } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index 3d6ccc575..359f17f0b 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -2,37 +2,71 @@ package cn.iocoder.dashboard.modules.system.controller.sms; import cn.iocoder.dashboard.common.pojo.CommonResult; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsChannelConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; -import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.validation.Valid; import static cn.iocoder.dashboard.common.pojo.CommonResult.success; -@Api("短信 渠道/签名 API") +@Api(tags = "短信渠道") @RestController @RequestMapping("/sms/channel") public class SmsChannelController { @Resource - private SysSmsChannelService service; + private SysSmsChannelService smsChannelService; - @ApiOperation("获取渠道/签名分页") - @GetMapping("/page") - public CommonResult> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) { - return success(service.pageSmsChannels(reqVO)); + @PostMapping("/create") + @ApiOperation("创建短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:create')") + public CommonResult createSmsChannel(@Valid @RequestBody SysSmsChannelCreateReqVO createReqVO) { + return success(smsChannelService.createSmsChannel(createReqVO)); } - @ApiOperation("添加消息渠道") - @PostMapping("/create") - public CommonResult add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) { - return success(service.createSmsChannel(reqVO)); + @PutMapping("/update") + @ApiOperation("更新短信渠道") + @PreAuthorize("@ss.hasPermission('system:sms-channel:update')") + public CommonResult updateSmsChannel(@Valid @RequestBody SysSmsChannelUpdateReqVO updateReqVO) { + smsChannelService.updateSmsChannel(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除短信渠道") + @ApiImplicitParam(name = "id", value = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-channel:delete')") + public CommonResult deleteSmsChannel(@RequestParam("id") Long id) { + smsChannelService.deleteSmsChannel(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得短信渠道") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult getSmsChannel(@RequestParam("id") Long id) { + SysSmsChannelDO smsChannel = smsChannelService.getSmsChannel(id); + return success(SysSmsChannelConvert.INSTANCE.convert(smsChannel)); + } + + @GetMapping("/page") + @ApiOperation("获得短信渠道分页") + @PreAuthorize("@ss.hasPermission('system:sms-channel:query')") + public CommonResult> getSmsChannelPage(@Valid SysSmsChannelPageReqVO pageVO) { + PageResult pageResult = smsChannelService.getSmsChannelPage(pageVO); + return success(SysSmsChannelConvert.INSTANCE.convertPage(pageResult)); } } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java deleted file mode 100644 index 042cddaa2..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms.vo; - -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.util.List; - -/** - * 渠道(包含模板)信息VO类 - * - * @author zzf - * @date 2021/1/25 17:01 - */ -@Data -@EqualsAndHashCode -public class SmsChannelAllVO implements Serializable { - - /** - * id - */ - private Long id; - - /** - * 编码(来自枚举类 阿里、华为、七牛等) - */ - private String code; - - /** - * 渠道账号id - */ - private String apiKey; - - /** - * 渠道账号秘钥 - */ - private String apiSecret; - - /** - * 实际渠道签名唯一标识 - */ - private String apiSignatureId; - - /** - * 签名值 - */ - private String signature; - - /** - * 该渠道名下的短信模板集合 - */ - private List templateList; - - public SmsTemplateVO getTemplateByTemplateCode(String tempCode) { - return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get(); - } - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java new file mode 100644 index 000000000..141033082 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** +* 短信渠道 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class SysSmsChannelBaseVO { + + @ApiModelProperty(value = "短信签名", required = true, example = "芋道源码") + @NotNull(message = "短信签名不能为空") + private String signature; + + @ApiModelProperty(value = "任务状态", required = true, example = "1") + @NotNull(message = "任务状态不能为空") + private Integer status; + + @ApiModelProperty(value = "备注", example = "好吃!") + private String remark; + + @ApiModelProperty(value = "短信 API 的账号", required = true, example = "yudao") + @NotNull(message = "短信 API 的账号不能为空") + private String apiKey; + + @ApiModelProperty(value = "短信 API 的秘钥", example = "yuanma") + private String apiSecret; + + @ApiModelProperty(value = "短信发送回调 URL", example = "http://www.iocoder.cn") + private String callbackUrl; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java new file mode 100644 index 000000000..a21cbb71d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelCreateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@ApiModel("短信渠道创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsChannelCreateReqVO extends SysSmsChannelBaseVO { + + @ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类") + @NotNull(message = "渠道编码不能为空") + private String code; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java new file mode 100644 index 000000000..523a6c375 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelPageReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; + +import cn.iocoder.dashboard.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("短信渠道分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsChannelPageReqVO extends PageParam { + + @ApiModelProperty(value = "任务状态", example = "1") + private Integer status; + + @ApiModelProperty(value = "短信签名", example = "芋道源码", notes = "模糊匹配") + private String signature; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始创建时间") + private Date beginCreateTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束创建时间") + private Date endCreateTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java new file mode 100644 index 000000000..20770689a --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("短信渠道 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsChannelRespVO extends SysSmsChannelBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "渠道编码", required = true, example = "YUN_PIAN", notes = "参见 SmsChannelEnum 枚举类") + private String code; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java new file mode 100644 index 000000000..66ab79412 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelUpdateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@ApiModel("短信渠道更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsChannelUpdateReqVO extends SysSmsChannelBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java deleted file mode 100644 index b38f7c832..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java +++ /dev/null @@ -1,44 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms.vo.req; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.io.Serializable; - - -@ApiModel("消息渠道创建 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode -public class SmsChannelCreateReqVO implements Serializable { - - @ApiModelProperty("编码(来自枚举类 阿里、华为、七牛等)") - private String code; - - @ApiModelProperty("渠道账号id") - private String apiKey; - - @ApiModelProperty("渠道账号秘钥") - private String apiSecret; - - @ApiModelProperty("优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)") - private Integer priority; - - @ApiModelProperty("名称") - private String name; - - @ApiModelProperty("签名值") - private String signature; - - @ApiModelProperty("备注") - private String remark; - - @ApiModelProperty("启用状态(0正常 1停用)") - private Integer status; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java deleted file mode 100644 index 9b941edf3..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java +++ /dev/null @@ -1,21 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms.vo.req; - -import cn.iocoder.dashboard.common.pojo.PageParam; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -@ApiModel("消息渠道分页 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class SmsChannelPageReqVO extends PageParam { - - @ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配") - private String signature; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java deleted file mode 100644 index 2ad1ce357..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms.vo.resp; - -import cn.iocoder.dashboard.common.pojo.PageParam; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import org.springframework.format.annotation.DateTimeFormat; - -import java.util.Date; - -import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -@ApiModel("用户分页 Request VO") -@Data -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class SmsChannelPageRespVO extends PageParam { - - @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配") - private String username; - - @ApiModelProperty(value = "手机号码", example = "yudao", notes = "模糊匹配") - private String mobile; - - @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类") - private Integer status; - - @ApiModelProperty(value = "开始时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date beginTime; - - @ApiModelProperty(value = "结束时间", example = "2020-10-24") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private Date endTime; - - @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门") - private Long deptId; - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java deleted file mode 100644 index c8a0f7591..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.dashboard.modules.system.convert.sms; - -import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import org.mapstruct.Mapper; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -@Mapper -public interface SmsChannelConvert { - - SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); - - SysSmsChannelDO convert(SmsChannelCreateReqVO bean); - - SysSmsChannelDO convert(SysUserUpdateReqVO bean); - - List convert(List bean); - - List convertProperty(List list); - - List convertList(List list); - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java new file mode 100644 index 000000000..11b036a86 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsChannelConvert.java @@ -0,0 +1,36 @@ +package cn.iocoder.dashboard.modules.system.convert.sms; + +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelRespVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 短信渠道 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface SysSmsChannelConvert { + + SysSmsChannelConvert INSTANCE = Mappers.getMapper(SysSmsChannelConvert.class); + + SysSmsChannelDO convert(SysSmsChannelCreateReqVO bean); + + SysSmsChannelDO convert(SysSmsChannelUpdateReqVO bean); + + SysSmsChannelRespVO convert(SysSmsChannelDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java index e6371e9c9..10155a1b4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsChannelMapper.java @@ -1,9 +1,9 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; -import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; @@ -13,14 +13,16 @@ import java.util.List; @Mapper public interface SysSmsChannelMapper extends BaseMapperX { - default PageResult selectChannelPage(SmsChannelPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapper() - .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getSignature, reqVO.getSignature())); + default PageResult selectPage(SysSmsChannelPageReqVO reqVO) { + return selectPage(reqVO, new QueryWrapperX() + .likeIfPresent("signature", reqVO.getSignature()) + .eqIfPresent("status", reqVO.getStatus()) + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .orderByDesc("id")); } default List selectListByStatus(Integer status) { - return selectList(new LambdaQueryWrapper() - .eq(SysSmsChannelDO::getStatus, status) + return selectList(new LambdaQueryWrapper().eq(SysSmsChannelDO::getStatus, status) .orderByAsc(SysSmsChannelDO::getId)); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 87271a655..6fbd295b4 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -78,19 +78,15 @@ public interface SysErrorCodeConstants { ErrorCode FILE_UPLOAD_FAILED = new ErrorCode(1002009002, "文件上传失败"); ErrorCode FILE_IS_EMPTY= new ErrorCode(1002009003, "文件为空"); + // ========== 短信渠道 1002011000 ========== + ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在"); - // ========== 短信模板 1002010000 ========== - ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002010000, "短信模板不存在"); + // ========== 短信模板 1002011000 ========== + ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在"); - // ========== 短信发送 1002011000 ========== - ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002011000, "手机号不存在"); - ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002011001, "模板参数({})缺失"); + // ========== 短信发送 1002012000 ========== + ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在"); + ErrorCode SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS = new ErrorCode(1002012001, "模板参数({})缺失"); - ErrorCode SMS_CHANNEL_NOT_INIT = new ErrorCode(1003001001, - "短信渠道没有初始化, 请调用SmsClientWrapper#initSmsClient()或SmsClientWrapper#addSmsClient"); - ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001002, "没有短信渠道信息, 请初始化sms_channel表数据。"); - ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001004, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据"); - ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001005, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。"); - ErrorCode PARAM_VALUE_IS_NULL = new ErrorCode(1003001006, "参数【{}】不能为空"); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java index c31b3ae5f..705662126 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java @@ -18,6 +18,7 @@ public enum SysDictTypeEnum { SYS_LOGIN_RESULT("sys_login_result"), // 登陆结果 SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 + SYS_SMS_CHANNEL_CODE("sys_sms_channel_code"), // 短信渠道编码 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java index 142812b3c..6864bf6f6 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelService.java @@ -1,10 +1,15 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; + /** * 短信渠道Service接口 * @@ -19,19 +24,49 @@ public interface SysSmsChannelService { void initSmsClients(); /** - * 分页查询短信渠道信息 + * 创建短信渠道 * - * @param reqVO 参数对象 - * @return 短信渠道分页对象 + * @param createReqVO 创建信息 + * @return 编号 */ - PageResult pageSmsChannels(SmsChannelPageReqVO reqVO); + Long createSmsChannel(@Valid SysSmsChannelCreateReqVO createReqVO); /** - * 创建新的渠道信息 + * 更新短信渠道 * - * @param reqVO 参数对象 - * @return 渠道id + * @param updateReqVO 更新信息 */ - Long createSmsChannel(SmsChannelCreateReqVO reqVO); + void updateSmsChannel(@Valid SysSmsChannelUpdateReqVO updateReqVO); + + /** + * 删除短信渠道 + * + * @param id 编号 + */ + void deleteSmsChannel(Long id); + + /** + * 获得短信渠道 + * + * @param id 编号 + * @return 短信渠道 + */ + SysSmsChannelDO getSmsChannel(Long id); + + /** + * 获得短信渠道列表 + * + * @param ids 编号 + * @return 短信渠道列表 + */ + List getSmsChannelList(Collection ids); + + /** + * 获得短信渠道分页 + * + * @param pageReqVO 分页查询 + * @return 短信渠道分页 + */ + PageResult getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java index a34d511bb..70c176c76 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java @@ -4,9 +4,10 @@ import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; -import cn.iocoder.dashboard.modules.system.convert.sms.SmsChannelConvert; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsChannelConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; @@ -14,8 +15,12 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.Resource; +import java.util.Collection; import java.util.List; +import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; + /** * 短信渠道Service实现类 * @@ -29,46 +34,65 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService { private SmsClientFactory smsClientFactory; @Resource - private SysSmsChannelMapper channelMapper; + private SysSmsChannelMapper smsChannelMapper; @Override @PostConstruct public void initSmsClients() { // 查询有效渠道信息 - List channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); + List channelDOList = smsChannelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); // 创建渠道 Client - List propertiesList = SmsChannelConvert.INSTANCE.convertList(channelDOList); + List propertiesList = SysSmsChannelConvert.INSTANCE.convertList02(channelDOList); propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties)); } // TODO 芋艿:刷新缓存 @Override - public PageResult pageSmsChannels(SmsChannelPageReqVO reqVO) { - return channelMapper.selectChannelPage(reqVO); + public Long createSmsChannel(SysSmsChannelCreateReqVO createReqVO) { + // 插入 + SysSmsChannelDO smsChannel = SysSmsChannelConvert.INSTANCE.convert(createReqVO); + smsChannelMapper.insert(smsChannel); + // 返回 + return smsChannel.getId(); } @Override - public Long createSmsChannel(SmsChannelCreateReqVO reqVO) { - SysSmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO); - channelMapper.insert(channelDO); - return channelDO.getId(); + public void updateSmsChannel(SysSmsChannelUpdateReqVO updateReqVO) { + // 校验存在 + this.validateSmsChannelExists(updateReqVO.getId()); + // 更新 + SysSmsChannelDO updateObj = SysSmsChannelConvert.INSTANCE.convert(updateReqVO); + smsChannelMapper.updateById(updateObj); + } + + @Override + public void deleteSmsChannel(Long id) { + // 校验存在 + this.validateSmsChannelExists(id); + // 更新 + smsChannelMapper.deleteById(id); + } + + private void validateSmsChannelExists(Long id) { + if (smsChannelMapper.selectById(id) == null) { + throw exception(SMS_CHANNEL_NOT_EXISTS); + } + } + + @Override + public SysSmsChannelDO getSmsChannel(Long id) { + return smsChannelMapper.selectById(id); + } + + @Override + public List getSmsChannelList(Collection ids) { + return smsChannelMapper.selectBatchIds(ids); + } + + @Override + public PageResult getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO) { + return smsChannelMapper.selectPage(pageReqVO); } -// @Override -// public List listSmsChannelAllEnabledInfo() { -// List channelDOList = channelMapper.selectListByStatus(); -// if (ObjectUtil.isNull(channelDOList)) { -// return null; -// } -// List channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList); -// channelAllVOList.forEach(smsChannelDO -> { -// List templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId()); -// if (ObjectUtil.isNull(templateDOList)) { -// templateDOList = new ArrayList<>(); -// } -// smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList)); -// }); -// return channelAllVOList; -// } } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java index 373665546..48a80056e 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/dept/SysDeptServiceTest.java @@ -270,4 +270,5 @@ class SysDeptServiceTest extends BaseDbUnitTest { }; return randomPojo(SysDeptDO.class, ArrayUtils.append(consumer, consumers)); } + } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java new file mode 100644 index 000000000..60eae778b --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsChannelServiceTest.java @@ -0,0 +1,149 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +import cn.iocoder.dashboard.BaseDbUnitTest; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsChannelServiceImpl; +import cn.iocoder.dashboard.util.collection.ArrayUtils; +import cn.iocoder.dashboard.util.object.ObjectUtils; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.function.Consumer; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS; +import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; +import static cn.iocoder.dashboard.util.RandomUtils.*; +import static cn.iocoder.dashboard.util.date.DateUtils.buildTime; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link SysSmsChannelServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(SysSmsChannelServiceImpl.class) +public class SysSmsChannelServiceTest extends BaseDbUnitTest { + + @Resource + private SysSmsChannelServiceImpl smsChannelService; + + @MockBean + private SmsClientFactory smsClientFactory; + + @Resource + private SysSmsChannelMapper smsChannelMapper; + + @Test + public void testCreateSmsChannel_success() { + // 准备参数 + SysSmsChannelCreateReqVO reqVO = randomPojo(SysSmsChannelCreateReqVO.class, o -> o.setStatus(randomCommonStatus())); + + // 调用 + Long smsChannelId = smsChannelService.createSmsChannel(reqVO); + // 断言 + assertNotNull(smsChannelId); + // 校验记录的属性是否正确 + SysSmsChannelDO smsChannel = smsChannelMapper.selectById(smsChannelId); + assertPojoEquals(reqVO, smsChannel); + } + + @Test + public void testUpdateSmsChannel_success() { + // mock 数据 + SysSmsChannelDO dbSmsChannel = randomSmsChannelDO(); + smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SysSmsChannelUpdateReqVO reqVO = randomPojo(SysSmsChannelUpdateReqVO.class, o -> { + o.setId(dbSmsChannel.getId()); // 设置更新的 ID + o.setStatus(randomCommonStatus()); + }); + + // 调用 + smsChannelService.updateSmsChannel(reqVO); + // 校验是否更新正确 + SysSmsChannelDO smsChannel = smsChannelMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, smsChannel); + } + + @Test + public void testUpdateSmsChannel_notExists() { + // 准备参数 + SysSmsChannelUpdateReqVO reqVO = randomPojo(SysSmsChannelUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> smsChannelService.updateSmsChannel(reqVO), SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testDeleteSmsChannel_success() { + // mock 数据 + SysSmsChannelDO dbSmsChannel = randomSmsChannelDO(); + smsChannelMapper.insert(dbSmsChannel);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsChannel.getId(); + + // 调用 + smsChannelService.deleteSmsChannel(id); + // 校验数据不存在了 + assertNull(smsChannelMapper.selectById(id)); + } + + @Test + public void testDeleteSmsChannel_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> smsChannelService.deleteSmsChannel(id), SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testGetSmsChannelPage() { + // mock 数据 + SysSmsChannelDO dbSmsChannel = randomPojo(SysSmsChannelDO.class, o -> { // 等会查询到 + o.setSignature("芋道源码"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(buildTime(2020, 12, 12)); + }); + smsChannelMapper.insert(dbSmsChannel); + // 测试 signature 不匹配 + smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setSignature("源码"))); + // 测试 status 不匹配 + smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 createTime 不匹配 + smsChannelMapper.insert(ObjectUtils.clone(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11)))); + // 准备参数 + SysSmsChannelPageReqVO reqVO = new SysSmsChannelPageReqVO(); + reqVO.setSignature("芋道"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setBeginCreateTime(buildTime(2020, 12, 1)); + reqVO.setEndCreateTime(buildTime(2020, 12, 24)); + + // 调用 + PageResult pageResult = smsChannelService.getSmsChannelPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsChannel, pageResult.getList().get(0)); + } + + @SafeVarargs + private static SysSmsChannelDO randomSmsChannelDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + }; + return randomPojo(SysSmsChannelDO.class, ArrayUtils.append(consumer, consumers)); + } + +} diff --git a/src/test/resources/sql/clean.sql b/src/test/resources/sql/clean.sql index c2d1d63d8..ae95d824e 100644 --- a/src/test/resources/sql/clean.sql +++ b/src/test/resources/sql/clean.sql @@ -19,3 +19,4 @@ DELETE FROM "sys_post"; DELETE FROM "sys_login_log"; DELETE FROM "sys_operate_log"; DELETE FROM "sys_user"; +DELETE FROM "sys_sms_channel"; diff --git a/src/test/resources/sql/create_tables.sql b/src/test/resources/sql/create_tables.sql index 23bf9c07b..6ef2d705d 100644 --- a/src/test/resources/sql/create_tables.sql +++ b/src/test/resources/sql/create_tables.sql @@ -47,8 +47,7 @@ CREATE TABLE IF NOT EXISTS "inf_job" ( PRIMARY KEY ("id") ) COMMENT='定时任务表'; -DROP TABLE IF EXISTS "inf_job_log"; -CREATE TABLE "inf_job_log" ( +CREATE TABLE IF NOT EXISTS "inf_job_log" ( "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '日志编号', "job_id" bigint(20) NOT NULL COMMENT '任务编号', "handler_name" varchar(64) NOT NULL COMMENT '处理器的名字', @@ -192,8 +191,7 @@ CREATE TABLE IF NOT EXISTS `sys_user_session` ( PRIMARY KEY (`id`) ) COMMENT '用户在线 Session'; -CREATE TABLE IF NOT EXISTS "sys_post" -( +CREATE TABLE IF NOT EXISTS "sys_post" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "code" varchar(64) NOT NULL, "name" varchar(50) NOT NULL, @@ -208,7 +206,6 @@ CREATE TABLE IF NOT EXISTS "sys_post" PRIMARY KEY ("id") ) COMMENT '岗位信息表'; - CREATE TABLE IF NOT EXISTS "sys_notice" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "title" varchar(50) NOT NULL COMMENT '公告标题', @@ -223,7 +220,6 @@ CREATE TABLE IF NOT EXISTS "sys_notice" ( PRIMARY KEY("id") ) COMMENT '通知公告表'; - CREATE TABLE IF NOT EXISTS `sys_login_log` ( `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, `log_type` bigint(4) NOT NULL, @@ -240,7 +236,6 @@ CREATE TABLE IF NOT EXISTS `sys_login_log` ( PRIMARY KEY (`id`) ) COMMENT ='系统访问记录'; - CREATE TABLE IF NOT EXISTS `sys_operate_log` ( `id` bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY, `trace_id` varchar(64) NOT NULL DEFAULT '', @@ -346,3 +341,20 @@ CREATE TABLE IF NOT EXISTS "inf_api_error_log" ( "deleted" bit not null default false, primary key ("id") ) COMMENT '系统异常日志'; + +CREATE TABLE IF NOT EXISTS "sys_sms_channel" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "signature" varchar(10) NOT NULL, + "code" varchar(63) NOT NULL, + "status" tinyint NOT NULL, + "remark" varchar(255) DEFAULT NULL, + "api_key" varchar(63) NOT NULL, + "api_secret" varchar(63) DEFAULT NULL, + "callback_url" varchar(255) DEFAULT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信渠道'; From cb1f9a580874e27fdd37c7c6a05b414563d94ca1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Apr 2021 21:17:20 +0800 Subject: [PATCH 32/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=B8=A0=E9=81=93?= =?UTF-8?q?=E7=9A=84=E5=89=8D=E7=AB=AF=E4=BB=A3=E7=A0=81=E7=9A=84=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/api/system/sms/smsChannel.js | 44 ++ ruoyi-ui/src/utils/dict.js | 1 + ruoyi-ui/src/views/system/sms/smsChannel.vue | 541 ++++++++++++++++++ .../client/impl/SmsClientFactoryImpl.java | 3 +- .../client/impl/aliyun/AliyunSmsClient.java | 3 + .../client/impl/yunpian/YunpianSmsClient.java | 2 + .../controller/sms/SmsChannelController.java | 2 +- .../sms/vo/channel/SysSmsChannelBaseVO.java | 7 +- 8 files changed, 599 insertions(+), 4 deletions(-) create mode 100644 ruoyi-ui/src/api/system/sms/smsChannel.js create mode 100644 ruoyi-ui/src/views/system/sms/smsChannel.vue diff --git a/ruoyi-ui/src/api/system/sms/smsChannel.js b/ruoyi-ui/src/api/system/sms/smsChannel.js new file mode 100644 index 000000000..0b4b8c338 --- /dev/null +++ b/ruoyi-ui/src/api/system/sms/smsChannel.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 创建短信渠道 +export function createSmsChannel(data) { + return request({ + url: '/system/sms-channel/create', + method: 'post', + data: data + }) +} + +// 更新短信渠道 +export function updateSmsChannel(data) { + return request({ + url: '/system/sms-channel/update', + method: 'put', + data: data + }) +} + +// 删除短信渠道 +export function deleteSmsChannel(id) { + return request({ + url: '/system/sms-channel/delete?id=' + id, + method: 'delete' + }) +} + +// 获得短信渠道 +export function getSmsChannel(id) { + return request({ + url: '/system/sms-channel/get?id=' + id, + method: 'get' + }) +} + +// 获得短信渠道分页 +export function getSmsChannelPage(query) { + return request({ + url: '/system/sms-channel/page', + method: 'get', + params: query + }) +} diff --git a/ruoyi-ui/src/utils/dict.js b/ruoyi-ui/src/utils/dict.js index 3817a86fe..bf6d72587 100644 --- a/ruoyi-ui/src/utils/dict.js +++ b/ruoyi-ui/src/utils/dict.js @@ -17,6 +17,7 @@ export const DICT_TYPE = { SYS_OPERATE_TYPE: 'sys_operate_type', SYS_LOGIN_RESULT: 'sys_login_result', SYS_CONFIG_TYPE: 'sys_config_type', + SYS_SMS_CHANNEL_CODE: 'sys_sms_channel_code', INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', INF_JOB_STATUS: 'inf_job_status', diff --git a/ruoyi-ui/src/views/system/sms/smsChannel.vue b/ruoyi-ui/src/views/system/sms/smsChannel.vue new file mode 100644 index 000000000..5b19f6a8d --- /dev/null +++ b/ruoyi-ui/src/views/system/sms/smsChannel.vue @@ -0,0 +1,541 @@ + + + + + diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java index cd5197193..35961fa8f 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java @@ -42,7 +42,8 @@ public class SmsClientFactoryImpl implements SmsClientFactory { // 初始化 channelCodeClients 集合 Arrays.stream(SmsChannelEnum.values()).forEach(channel -> { // 创建一个空的 SmsChannelProperties 对象 - SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()); + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode()) + .setApiKey("default").setApiSecret("default"); // 创建 Sms 客户端 AbstractSmsClient smsClient = createSmsClient(properties); channelCodeClients.put(channel.getCode(), smsClient); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index 954250788..8dae88586 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -1,5 +1,6 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; @@ -50,6 +51,8 @@ public class AliyunSmsClient extends AbstractSmsClient { public AliyunSmsClient(SmsChannelProperties properties) { super(properties, new AliyunSmsCodeMapping()); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空"); } @Override diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index ea0aedf13..59c61e45e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -1,6 +1,7 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.iocoder.dashboard.common.core.KeyValue; @@ -41,6 +42,7 @@ public class YunpianSmsClient extends AbstractSmsClient { public YunpianSmsClient(SmsChannelProperties properties) { super(properties, new YunpianSmsCodeMapping()); + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空"); } @Override diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java index 359f17f0b..1000a9b02 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java @@ -22,7 +22,7 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success; @Api(tags = "短信渠道") @RestController -@RequestMapping("/sms/channel") +@RequestMapping("system/sms-channel") public class SmsChannelController { @Resource diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java index 141033082..df760c862 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelBaseVO.java @@ -2,6 +2,7 @@ package cn.iocoder.dashboard.modules.system.controller.sms.vo.channel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import org.hibernate.validator.constraints.URL; import javax.validation.constraints.NotNull; @@ -16,8 +17,8 @@ public class SysSmsChannelBaseVO { @NotNull(message = "短信签名不能为空") private String signature; - @ApiModelProperty(value = "任务状态", required = true, example = "1") - @NotNull(message = "任务状态不能为空") + @ApiModelProperty(value = "启用状态", required = true, example = "1") + @NotNull(message = "启用状态不能为空") private Integer status; @ApiModelProperty(value = "备注", example = "好吃!") @@ -31,6 +32,8 @@ public class SysSmsChannelBaseVO { private String apiSecret; @ApiModelProperty(value = "短信发送回调 URL", example = "http://www.iocoder.cn") + @URL(message = "回调 URL 格式不正确") private String callbackUrl; + } From 58d368cfdc7ce56b94be67d4cb2d88c0be11056b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Apr 2021 22:32:05 +0800 Subject: [PATCH 33/54] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E7=9F=AD?= =?UTF-8?q?=E4=BF=A1=E6=A8=A1=E6=9D=BF=E7=9A=84=E5=9F=BA=E7=A1=80=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/sms/SmsTemplateController.java | 14 -- ...ller.java => SysSmsChannelController.java} | 2 +- .../sms/SysSmsTemplateController.java | 87 ++++++++ .../sms/vo/template/SysSmsTemplateBaseVO.java | 46 +++++ .../template/SysSmsTemplateCreateReqVO.java | 14 ++ .../vo/template/SysSmsTemplateExcelVO.java | 56 +++++ .../template/SysSmsTemplateExportReqVO.java | 42 ++++ .../vo/template/SysSmsTemplatePageReqVO.java | 47 +++++ .../sms/vo/template/SysSmsTemplateRespVO.java | 26 +++ .../template/SysSmsTemplateUpdateReqVO.java | 21 ++ .../convert/sms/SmsTemplateConvert.java | 26 --- .../convert/sms/SysSmsTemplateConvert.java | 31 +++ .../dal/mysql/sms/SysSmsTemplateMapper.java | 50 ++--- .../system/enums/dict/SysDictTypeEnum.java | 1 + .../service/sms/SysSmsTemplateService.java | 62 ++++++ .../sms/impl/SysSmsTemplateServiceImpl.java | 63 ++++++ .../sms/SysSmsTemplateServiceTest.java | 194 ++++++++++++++++++ 17 files changed, 717 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java rename src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/{SmsChannelController.java => SysSmsChannelController.java} (98%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExportReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplatePageReqVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateRespVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateUpdateReqVO.java delete mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsTemplateConvert.java create mode 100644 src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java deleted file mode 100644 index 53eefad46..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java +++ /dev/null @@ -1,14 +0,0 @@ -package cn.iocoder.dashboard.modules.system.controller.sms; - -import io.swagger.annotations.Api; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Api("认证 API") -@RestController -@RequestMapping("/sms/template") -public class SmsTemplateController { - - - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsChannelController.java similarity index 98% rename from src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java rename to src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsChannelController.java index 1000a9b02..cc7b496aa 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsChannelController.java @@ -23,7 +23,7 @@ import static cn.iocoder.dashboard.common.pojo.CommonResult.success; @Api(tags = "短信渠道") @RestController @RequestMapping("system/sms-channel") -public class SmsChannelController { +public class SysSmsChannelController { @Resource private SysSmsChannelService smsChannelService; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.java new file mode 100644 index 000000000..c70cbc9f8 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.java @@ -0,0 +1,87 @@ +package cn.iocoder.dashboard.modules.system.controller.sms; + +import cn.iocoder.dashboard.common.pojo.CommonResult; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils; +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.*; +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsTemplateConvert; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.dashboard.common.pojo.CommonResult.success; +import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT; + +@Api("短信模板") +@RestController +@RequestMapping("/system/sms-template") +public class SysSmsTemplateController { + + @Resource + private SysSmsTemplateService smsTemplateService; + + @PostMapping("/create") + @ApiOperation("创建短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:create')") + public CommonResult createSmsTemplate(@Valid @RequestBody SysSmsTemplateCreateReqVO createReqVO) { + return success(smsTemplateService.createSmsTemplate(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新短信模板") + @PreAuthorize("@ss.hasPermission('system:sms-template:update')") + public CommonResult updateSmsTemplate(@Valid @RequestBody SysSmsTemplateUpdateReqVO updateReqVO) { + smsTemplateService.updateSmsTemplate(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除短信模板") + @ApiImplicitParam(name = "id", value = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:sms-template:delete')") + public CommonResult deleteSmsTemplate(@RequestParam("id") Long id) { + smsTemplateService.deleteSmsTemplate(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得短信模板") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult getSmsTemplate(@RequestParam("id") Long id) { + SysSmsTemplateDO smsTemplate = smsTemplateService.getSmsTemplate(id); + return success(SysSmsTemplateConvert.INSTANCE.convert(smsTemplate)); + } + + @GetMapping("/page") + @ApiOperation("获得短信模板分页") + @PreAuthorize("@ss.hasPermission('system:sms-template:query')") + public CommonResult> getSmsTemplatePage(@Valid SysSmsTemplatePageReqVO pageVO) { + PageResult pageResult = smsTemplateService.getSmsTemplatePage(pageVO); + return success(SysSmsTemplateConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/export-excel") + @ApiOperation("导出短信模板 Excel") + @PreAuthorize("@ss.hasPermission('system:sms-template:export')") + @OperateLog(type = EXPORT) + public void exportSmsTemplateExcel(@Valid SysSmsTemplateExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = smsTemplateService.getSmsTemplateList(exportReqVO); + // 导出 Excel + List datas = SysSmsTemplateConvert.INSTANCE.convertList02(list); + ExcelUtils.write(response, "短信模板.xls", "数据", SysSmsTemplateExcelVO.class, datas); + } + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java new file mode 100644 index 000000000..f2ef6ac16 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** +* 短信模板 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class SysSmsTemplateBaseVO { + + @ApiModelProperty(value = "短信签名", required = true, example = "1", notes = "参见 SysSmsTemplateTypeEnum 枚举类") + @NotNull(message = "短信签名不能为空") + private Integer type; + + @ApiModelProperty(value = "开启状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类") + @NotNull(message = "开启状态不能为空") + private Integer status; + + @ApiModelProperty(value = "模板编码", required = true, example = "test_01") + @NotNull(message = "模板编码不能为空") + private String code; + + @ApiModelProperty(value = "模板名称", required = true, example = "yudao") + @NotNull(message = "模板名称不能为空") + private String name; + + @ApiModelProperty(value = "模板内容", required = true, example = "你好,{name}。你长的太{like}啦!") + @NotNull(message = "模板内容不能为空") + private String content; + + @ApiModelProperty(value = "备注", example = "哈哈哈") + private String remark; + + @ApiModelProperty(value = "短信 API 的模板编号", required = true, example = "4383920") + @NotNull(message = "短信 API 的模板编号不能为空") + private String apiTemplateId; + + @ApiModelProperty(value = "短信渠道编号", required = true, example = "10") + @NotNull(message = "短信渠道编号不能为空") + private Long channelId; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java new file mode 100644 index 000000000..8f847556d --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("短信模板创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsTemplateCreateReqVO extends SysSmsTemplateBaseVO { + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java new file mode 100644 index 000000000..3eef8133b --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java @@ -0,0 +1,56 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat; +import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.Date; + +import static cn.iocoder.dashboard.modules.system.enums.dict.SysDictTypeEnum.*; + +/** + * 短信模板 Excel VO + * + * @author 芋道源码 + */ +@Data +public class SysSmsTemplateExcelVO { + + @ExcelProperty("编号") + private Long id; + + @ExcelProperty(value = "短信签名", converter = DictConvert.class) + @DictFormat(SYS_SMS_TEMPLATE_TYPE) + private Integer type; + + @ExcelProperty(value = "开启状态", converter = DictConvert.class) + @DictFormat(SYS_COMMON_STATUS) + private Integer status; + + @ExcelProperty("模板编码") + private String code; + + @ExcelProperty("模板名称") + private String name; + + @ExcelProperty("模板内容") + private String content; + + @ExcelProperty("备注") + private String remark; + + @ExcelProperty("短信 API 的模板编号") + private String apiTemplateId; + + @ExcelProperty("短信渠道编号") + private Long channelId; + + @ExcelProperty(value = "短信渠道编码", converter = DictConvert.class) + @DictFormat(SYS_SMS_CHANNEL_CODE) + private String channelCode; + + @ExcelProperty("创建时间") + private Date createTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExportReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExportReqVO.java new file mode 100644 index 000000000..34f940253 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateExportReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel(value = "短信模板 Excel 导出 Request VO", description = "参数和 SysSmsTemplatePageReqVO 是一致的") +@Data +public class SysSmsTemplateExportReqVO { + + @ApiModelProperty(value = "短信签名", example = "1") + private Integer type; + + @ApiModelProperty(value = "开启状态", example = "1") + private Integer status; + + @ApiModelProperty(value = "模板编码", example = "test_01", notes = "模糊匹配") + private String code; + + @ApiModelProperty(value = "模板内容", example = "你好,{name}。你长的太{like}啦!", notes = "模糊匹配") + private String content; + + @ApiModelProperty(value = "短信 API 的模板编号", example = "4383920", notes = "模糊匹配") + private String apiTemplateId; + + @ApiModelProperty(value = "短信渠道编号", example = "10") + private Long channelId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始创建时间") + private Date beginCreateTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束创建时间") + private Date endCreateTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplatePageReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplatePageReqVO.java new file mode 100644 index 000000000..b5f1e5bfb --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplatePageReqVO.java @@ -0,0 +1,47 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import cn.iocoder.dashboard.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("短信模板分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsTemplatePageReqVO extends PageParam { + + @ApiModelProperty(value = "短信签名", example = "1") + private Integer type; + + @ApiModelProperty(value = "开启状态", example = "1") + private Integer status; + + @ApiModelProperty(value = "模板编码", example = "test_01", notes = "模糊匹配") + private String code; + + @ApiModelProperty(value = "模板内容", example = "你好,{name}。你长的太{like}啦!", notes = "模糊匹配") + private String content; + + @ApiModelProperty(value = "短信 API 的模板编号", example = "4383920", notes = "模糊匹配") + private String apiTemplateId; + + @ApiModelProperty(value = "短信渠道编号", example = "10") + private Long channelId; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "开始创建时间") + private Date beginCreateTime; + + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @ApiModelProperty(value = "结束创建时间") + private Date endCreateTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateRespVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateRespVO.java new file mode 100644 index 000000000..033d2a2f2 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("短信模板 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsTemplateRespVO extends SysSmsTemplateBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "短信渠道编码", required = true, example = "ALIYUN") + private String channelCode; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateUpdateReqVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateUpdateReqVO.java new file mode 100644 index 000000000..9b3aba840 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateUpdateReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.modules.system.controller.sms.vo.template; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; + +@ApiModel("短信模板更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class SysSmsTemplateUpdateReqVO extends SysSmsTemplateBaseVO { + + @ApiModelProperty(value = "编号", required = true, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java deleted file mode 100644 index 788fc8e19..000000000 --- a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.dashboard.modules.system.convert.sms; - -import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; -import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; -import com.baomidou.mybatisplus.core.metadata.IPage; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - -import java.util.List; - -@Mapper -public interface SmsTemplateConvert { - - SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class); - - @Mapping(source = "records", target = "list") - PageResult convertPage(IPage page); - - List convert(List bean); - - SmsTemplateVO convert(SysSmsTemplateDO bean); - -} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsTemplateConvert.java b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsTemplateConvert.java new file mode 100644 index 000000000..5d73771eb --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SysSmsTemplateConvert.java @@ -0,0 +1,31 @@ +package cn.iocoder.dashboard.modules.system.convert.sms; + +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExcelVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateRespVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +@Mapper +public interface SysSmsTemplateConvert { + + SysSmsTemplateConvert INSTANCE = Mappers.getMapper(SysSmsTemplateConvert.class); + + SysSmsTemplateDO convert(SysSmsTemplateCreateReqVO bean); + + SysSmsTemplateDO convert(SysSmsTemplateUpdateReqVO bean); + + SysSmsTemplateRespVO convert(SysSmsTemplateDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java index 3cfc898b3..ee1b3f2d9 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java @@ -1,8 +1,11 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.sms; -import cn.iocoder.dashboard.common.enums.CommonStatusEnum; + +import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -14,29 +17,28 @@ public interface SysSmsTemplateMapper extends BaseMapperX { return selectOne("code", code); } - /** - * 根据短信渠道id查询短信模板集合 - * - * @param channelId 渠道id - * @return 模板集合 - */ - default List selectListByChannelId(Long channelId) { - return selectList(new LambdaQueryWrapper() - .eq(SysSmsTemplateDO::getChannelId, channelId) - .eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SysSmsTemplateDO::getId) - ); + default PageResult selectPage(SysSmsTemplatePageReqVO reqVO) { + return selectPage(reqVO, new QueryWrapperX() + .eqIfPresent("type", reqVO.getType()) + .eqIfPresent("status", reqVO.getStatus()) + .likeIfPresent("code", reqVO.getCode()) + .likeIfPresent("content", reqVO.getContent()) + .likeIfPresent("api_template_id", reqVO.getApiTemplateId()) + .eqIfPresent("channel_id", reqVO.getChannelId()) + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .orderByDesc("id")); } - /** - * 查询有效短信模板集合 - * - * @return 有效短信模板集合 - */ - default List selectEnabledList() { - return selectList(new LambdaQueryWrapper() - .eq(SysSmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - .orderByAsc(SysSmsTemplateDO::getId) - ); + default List selectList(SysSmsTemplateExportReqVO reqVO) { + return selectList(new QueryWrapperX() + .eqIfPresent("type", reqVO.getType()) + .eqIfPresent("status", reqVO.getStatus()) + .likeIfPresent("code", reqVO.getCode()) + .likeIfPresent("content", reqVO.getContent()) + .likeIfPresent("api_template_id", reqVO.getApiTemplateId()) + .eqIfPresent("channel_id", reqVO.getChannelId()) + .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) + .orderByDesc("id")); } + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java index 705662126..0bc448fc1 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java @@ -19,6 +19,7 @@ public enum SysDictTypeEnum { SYS_CONFIG_TYPE("sys_config_type"), // 参数配置类型 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 SYS_SMS_CHANNEL_CODE("sys_sms_channel_code"), // 短信渠道编码 + SYS_SMS_TEMPLATE_TYPE("sys_sms_template_type"), // 短信模板类型 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举 diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java index 5faeeddcb..2c17b8a7a 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateService.java @@ -1,7 +1,15 @@ package cn.iocoder.dashboard.modules.system.service.sms; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; import java.util.Map; /** @@ -29,4 +37,58 @@ public interface SysSmsTemplateService { */ String formatSmsTemplateContent(String content, Map params); + /** + * 创建短信模板 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSmsTemplate(@Valid SysSmsTemplateCreateReqVO createReqVO); + + /** + * 更新短信模板 + * + * @param updateReqVO 更新信息 + */ + void updateSmsTemplate(@Valid SysSmsTemplateUpdateReqVO updateReqVO); + + /** + * 删除短信模板 + * + * @param id 编号 + */ + void deleteSmsTemplate(Long id); + + /** + * 获得短信模板 + * + * @param id 编号 + * @return 短信模板 + */ + SysSmsTemplateDO getSmsTemplate(Long id); + + /** + * 获得短信模板列表 + * + * @param ids 编号 + * @return 短信模板列表 + */ + List getSmsTemplateList(Collection ids); + + /** + * 获得短信模板分页 + * + * @param pageReqVO 分页查询 + * @return 短信模板分页 + */ + PageResult getSmsTemplatePage(SysSmsTemplatePageReqVO pageReqVO); + + /** + * 获得短信模板列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 短信模板分页 + */ + List getSmsTemplateList(SysSmsTemplateExportReqVO exportReqVO); + } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index c5c1a5127..ac54a2565 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -1,14 +1,25 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; +import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsTemplateConvert; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; import java.util.Map; +import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS; + /** * 短信模板Service实现类 * @@ -31,4 +42,56 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return StrUtil.format(content, params); } + @Override + public Long createSmsTemplate(SysSmsTemplateCreateReqVO createReqVO) { + // 插入 + SysSmsTemplateDO smsTemplate = SysSmsTemplateConvert.INSTANCE.convert(createReqVO); + smsTemplateMapper.insert(smsTemplate); + // 返回 + return smsTemplate.getId(); + } + + @Override + public void updateSmsTemplate(SysSmsTemplateUpdateReqVO updateReqVO) { + // 校验存在 + this.validateSmsTemplateExists(updateReqVO.getId()); + // 更新 + SysSmsTemplateDO updateObj = SysSmsTemplateConvert.INSTANCE.convert(updateReqVO); + smsTemplateMapper.updateById(updateObj); + } + + @Override + public void deleteSmsTemplate(Long id) { + // 校验存在 + this.validateSmsTemplateExists(id); + // 更新 + smsTemplateMapper.deleteById(id); + } + + private void validateSmsTemplateExists(Long id) { + if (smsTemplateMapper.selectById(id) == null) { + throw exception(SMS_TEMPLATE_NOT_EXISTS); + } + } + + @Override + public SysSmsTemplateDO getSmsTemplate(Long id) { + return smsTemplateMapper.selectById(id); + } + + @Override + public List getSmsTemplateList(Collection ids) { + return smsTemplateMapper.selectBatchIds(ids); + } + + @Override + public PageResult getSmsTemplatePage(SysSmsTemplatePageReqVO pageReqVO) { + return smsTemplateMapper.selectPage(pageReqVO); + } + + @Override + public List getSmsTemplateList(SysSmsTemplateExportReqVO exportReqVO) { + return smsTemplateMapper.selectList(exportReqVO); + } + } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java new file mode 100644 index 000000000..a04034155 --- /dev/null +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java @@ -0,0 +1,194 @@ +package cn.iocoder.dashboard.modules.system.service.sms; + +import cn.iocoder.dashboard.BaseDbUnitTest; +import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; +import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; +import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsTemplateServiceImpl; +import cn.iocoder.dashboard.util.object.ObjectUtils; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS; +import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; +import static cn.iocoder.dashboard.util.RandomUtils.randomLongId; +import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link SysSmsTemplateServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(SysSmsTemplateServiceImpl.class) +public class SysSmsTemplateServiceTest extends BaseDbUnitTest { + + @Resource + private SysSmsTemplateServiceImpl smsTemplateService; + + @Resource + private SysSmsTemplateMapper smsTemplateMapper; + + @Test + public void testCreateSmsTemplate_success() { + // 准备参数 + SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class); + + // 调用 + Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); + // 断言 + assertNotNull(smsTemplateId); + // 校验记录的属性是否正确 + SysSmsTemplateDO smsTemplate = smsTemplateMapper.selectById(smsTemplateId); + assertPojoEquals(reqVO, smsTemplate); + } + + @Test + public void testUpdateSmsTemplate_success() { + // mock 数据 + SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + SysSmsTemplateUpdateReqVO reqVO = randomPojo(SysSmsTemplateUpdateReqVO.class, o -> { + o.setId(dbSmsTemplate.getId()); // 设置更新的 ID + }); + + // 调用 + smsTemplateService.updateSmsTemplate(reqVO); + // 校验是否更新正确 + SysSmsTemplateDO smsTemplate = smsTemplateMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, smsTemplate); + } + + @Test + public void testUpdateSmsTemplate_notExists() { + // 准备参数 + SysSmsTemplateUpdateReqVO reqVO = randomPojo(SysSmsTemplateUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> smsTemplateService.updateSmsTemplate(reqVO), SMS_TEMPLATE_NOT_EXISTS); + } + + @Test + public void testDeleteSmsTemplate_success() { + // mock 数据 + SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class); + smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbSmsTemplate.getId(); + + // 调用 + smsTemplateService.deleteSmsTemplate(id); + // 校验数据不存在了 + assertNull(smsTemplateMapper.selectById(id)); + } + + @Test + public void testDeleteSmsTemplate_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> smsTemplateService.deleteSmsTemplate(id), SMS_TEMPLATE_NOT_EXISTS); + } + + @Test // TODO 请修改 null 为需要的值 + public void testGetSmsTemplatePage() { + // mock 数据 + SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class, o -> { // 等会查询到 + o.setType(null); + o.setStatus(null); + o.setCode(null); + o.setContent(null); + o.setApiTemplateId(null); + o.setChannelId(null); + o.setCreateTime(null); + }); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 type 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(null))); + // 测试 status 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(null))); + // 测试 code 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode(null))); + // 测试 content 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent(null))); + // 测试 apiTemplateId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId(null))); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(null))); + // 测试 createTime 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(null))); + // 准备参数 + SysSmsTemplatePageReqVO reqVO = new SysSmsTemplatePageReqVO(); + reqVO.setType(null); + reqVO.setStatus(null); + reqVO.setCode(null); + reqVO.setContent(null); + reqVO.setApiTemplateId(null); + reqVO.setChannelId(null); + reqVO.setBeginCreateTime(null); + reqVO.setEndCreateTime(null); + + // 调用 + PageResult pageResult = smsTemplateService.getSmsTemplatePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); + } + + @Test // TODO 请修改 null 为需要的值 + public void testGetSmsTemplateList() { + // mock 数据 + SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class, o -> { // 等会查询到 + o.setType(null); + o.setStatus(null); + o.setCode(null); + o.setContent(null); + o.setApiTemplateId(null); + o.setChannelId(null); + o.setCreateTime(null); + }); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 type 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(null))); + // 测试 status 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(null))); + // 测试 code 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode(null))); + // 测试 content 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent(null))); + // 测试 apiTemplateId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId(null))); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(null))); + // 测试 createTime 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(null))); + // 准备参数 + SysSmsTemplateExportReqVO reqVO = new SysSmsTemplateExportReqVO(); + reqVO.setType(null); + reqVO.setStatus(null); + reqVO.setCode(null); + reqVO.setContent(null); + reqVO.setApiTemplateId(null); + reqVO.setChannelId(null); + reqVO.setBeginCreateTime(null); + reqVO.setEndCreateTime(null); + + // 调用 + List list = smsTemplateService.getSmsTemplateList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbSmsTemplate, list.get(0)); + } + +} From fbbcd2717a8c8c0428d1655cad22bbc7ef79d702 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 Apr 2021 23:52:24 +0800 Subject: [PATCH 34/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=E5=88=9B=E5=BB=BA=20Test=20=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/ruoyi-vue-pro.sql | 192 ++++++++++++++++-- sql/sms.sql | 109 ---------- .../dal/mysql/sms/SysSmsTemplateMapper.java | 2 +- .../system/enums/SysErrorCodeConstants.java | 2 + .../sms/impl/SysSmsTemplateServiceImpl.java | 62 +++++- .../sms/SysSmsTemplateServiceTest.java | 50 ++++- src/test/resources/sql/create_tables.sql | 20 ++ 7 files changed, 305 insertions(+), 132 deletions(-) delete mode 100644 sql/sms.sql diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 8a95afdca..e636149fa 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -1,7 +1,7 @@ /* Navicat Premium Data Transfer - Source Server : 127.0.0.1 + Source Server : local-mysql001 Source Server Type : MySQL Source Server Version : 50718 Source Host : localhost:3306 @@ -11,7 +11,7 @@ Target Server Version : 50718 File Encoding : 65001 - Date: 21/03/2021 18:53:24 + Date: 05/04/2021 23:51:38 */ SET NAMES utf8mb4; @@ -43,7 +43,7 @@ CREATE TABLE `inf_api_access_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=1318 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表'; +) ENGINE=InnoDB AUTO_INCREMENT=1909 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表'; -- ---------------------------- -- Records of inf_api_access_log @@ -84,7 +84,7 @@ CREATE TABLE `inf_api_error_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志'; +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志'; -- ---------------------------- -- Records of inf_api_error_log @@ -201,7 +201,7 @@ CREATE TABLE `inf_job_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=627 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表'; +) ENGINE=InnoDB AUTO_INCREMENT=1035 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表'; -- ---------------------------- -- Records of inf_job_log @@ -264,7 +264,7 @@ CREATE TABLE `sys_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='字典数据表'; +) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8mb4 COMMENT='字典数据表'; -- ---------------------------- -- Records of sys_dict_data @@ -324,6 +324,11 @@ INSERT INTO `sys_dict_data` VALUES (61, 2, '管理员', '2', 'user_type', 0, NUL INSERT INTO `sys_dict_data` VALUES (62, 0, '未处理', '0', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:19', '', '2021-02-26 08:11:23', b'0'); INSERT INTO `sys_dict_data` VALUES (63, 1, '已处理', '1', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:26', '', '2021-02-26 08:11:29', b'0'); INSERT INTO `sys_dict_data` VALUES (64, 2, '已忽略', '2', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:34', '', '2021-02-26 08:11:34', b'0'); +INSERT INTO `sys_dict_data` VALUES (65, 0, '云片', 'YUN_PIAN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:14', '1', '2021-04-05 01:05:14', b'0'); +INSERT INTO `sys_dict_data` VALUES (66, 0, '阿里云', 'ALIYUN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:26', '1', '2021-04-05 01:05:26', b'0'); +INSERT INTO `sys_dict_data` VALUES (67, 1, '验证码', '1', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:57', '1', '2021-04-05 21:50:57', b'0'); +INSERT INTO `sys_dict_data` VALUES (68, 2, '通知', '2', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:08', '1', '2021-04-05 21:51:08', b'0'); +INSERT INTO `sys_dict_data` VALUES (69, 0, '营销', '3', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:15', '1', '2021-04-05 21:51:15', b'0'); COMMIT; -- ---------------------------- @@ -343,7 +348,7 @@ CREATE TABLE `sys_dict_type` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `dict_type` (`type`) -) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表'; +) ENGINE=InnoDB AUTO_INCREMENT=113 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表'; -- ---------------------------- -- Records of sys_dict_type @@ -366,6 +371,8 @@ INSERT INTO `sys_dict_type` VALUES (107, '定时任务状态', 'inf_job_status', INSERT INTO `sys_dict_type` VALUES (108, '定时任务日志状态', 'inf_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2021-02-08 10:03:51', b'0'); INSERT INTO `sys_dict_type` VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', b'0'); INSERT INTO `sys_dict_type` VALUES (110, 'API 异常数据的处理状态', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2021-02-26 07:07:01', b'0'); +INSERT INTO `sys_dict_type` VALUES (111, '短信渠道编码', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2021-04-05 01:04:50', b'0'); +INSERT INTO `sys_dict_type` VALUES (112, '短信模板的类型', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2021-04-05 21:50:43', b'0'); COMMIT; -- ---------------------------- @@ -386,7 +393,7 @@ CREATE TABLE `sys_login_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录'; +) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录'; -- ---------------------------- -- Records of sys_login_log @@ -415,7 +422,7 @@ CREATE TABLE `sys_menu` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=1093 DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表'; +) ENGINE=InnoDB AUTO_INCREMENT=1100 DEFAULT CHARSET=utf8mb4 COMMENT='菜单权限表'; -- ---------------------------- -- Records of sys_menu @@ -530,6 +537,12 @@ INSERT INTO `sys_menu` VALUES (1089, '日志查询', 'infra:api-error-log:query' INSERT INTO `sys_menu` VALUES (1090, '文件管理', '', 2, 0, 2, 'file', 'upload', 'infra/file/index', 0, '', '2021-03-12 20:16:20', '1', '2021-03-13 11:07:05', b'0'); INSERT INTO `sys_menu` VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0'); INSERT INTO `sys_menu` VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0'); +INSERT INTO `sys_menu` VALUES (1093, '短信管理', '', 1, 11, 1, 'sms', 'validCode', NULL, 0, '1', '2021-04-05 01:10:16', '1', '2021-04-05 01:11:38', b'0'); +INSERT INTO `sys_menu` VALUES (1094, '短信渠道', '', 2, 0, 1093, 'sms-channel', '', 'system/sms/smsChannel', 0, '', '2021-04-01 11:07:15', '1', '2021-04-05 20:32:53', b'0'); +INSERT INTO `sys_menu` VALUES (1095, '短信渠道查询', 'system:sms-channel:query', 3, 1, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0'); +INSERT INTO `sys_menu` VALUES (1096, '短信渠道创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0'); +INSERT INTO `sys_menu` VALUES (1097, '短信渠道更新', 'system:sms-channel:update', 3, 3, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0'); +INSERT INTO `sys_menu` VALUES (1098, '短信渠道删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0'); COMMIT; -- ---------------------------- @@ -589,7 +602,7 @@ CREATE TABLE `sys_operate_log` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录'; +) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录'; -- ---------------------------- -- Records of sys_operate_log @@ -834,6 +847,118 @@ INSERT INTO `sys_role_menu` VALUES (237, 101, 1064, '', '2021-01-21 03:23:27', ' INSERT INTO `sys_role_menu` VALUES (238, 101, 1065, '', '2021-01-21 03:23:27', '', '2021-01-21 03:23:27', b'0'); COMMIT; +-- ---------------------------- +-- Table structure for sys_sms_channel +-- ---------------------------- +DROP TABLE IF EXISTS `sys_sms_channel`; +CREATE TABLE `sys_sms_channel` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', + `signature` varchar(10) NOT NULL COMMENT '短信签名', + `code` varchar(63) NOT NULL COMMENT '渠道编码', + `status` tinyint(4) NOT NULL COMMENT '开启状态', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `api_key` varchar(63) NOT NULL COMMENT '短信 API 的账号', + `api_secret` varchar(63) DEFAULT NULL COMMENT '短信 API 的秘钥', + `callback_url` varchar(255) DEFAULT NULL COMMENT '短信发送回调 URL', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠道'; + +-- ---------------------------- +-- Records of sys_sms_channel +-- ---------------------------- +BEGIN; +INSERT INTO `sys_sms_channel` VALUES (1, '芋道', 'YUN_PIAN', 0, '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://java.nat300.top/api/system/sms/callback/sms/yunpian', '', '2021-03-31 06:12:20', '1', '2021-04-05 21:02:38', b'0'); +INSERT INTO `sys_sms_channel` VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-05 21:02:44', b'0'); +INSERT INTO `sys_sms_channel` VALUES (3, '测试', 'YUN_PIAN', 0, '哈哈哈', '23132', NULL, 'http://www.baidu.com', '1', '2021-04-05 21:10:34', '1', '2021-04-05 21:10:34', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_sms_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_sms_log`; +CREATE TABLE `sys_sms_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', + `channel_id` bigint(20) NOT NULL COMMENT '短信渠道编号', + `channel_code` varchar(63) NOT NULL COMMENT '短信渠道编码', + `template_id` bigint(20) NOT NULL COMMENT '模板编号', + `template_code` varchar(63) NOT NULL COMMENT '模板编码', + `template_type` tinyint(4) NOT NULL COMMENT '短信类型', + `template_content` varchar(255) NOT NULL COMMENT '短信内容', + `template_params` varchar(255) NOT NULL COMMENT '短信参数', + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模板编号', + `mobile` varchar(11) NOT NULL COMMENT '手机号', + `user_id` bigint(20) DEFAULT '0' COMMENT '用户编号', + `user_type` tinyint(4) DEFAULT '0' COMMENT '用户类型', + `send_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '发送状态', + `send_time` datetime DEFAULT NULL COMMENT '发送时间', + `send_code` int(11) DEFAULT NULL COMMENT '发送结果的编码', + `send_msg` varchar(255) DEFAULT NULL COMMENT '发送结果的提示', + `api_send_code` varchar(63) DEFAULT NULL COMMENT '短信 API 发送结果的编码', + `api_send_msg` varchar(255) DEFAULT NULL COMMENT '短信 API 发送失败的提示', + `api_request_id` varchar(255) DEFAULT NULL COMMENT '短信 API 发送返回的唯一请求 ID', + `api_serial_no` varchar(255) DEFAULT NULL COMMENT '短信 API 发送返回的序号', + `receive_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '接收状态', + `receive_time` datetime DEFAULT NULL COMMENT '接收时间', + `api_receive_code` varchar(63) DEFAULT NULL COMMENT 'API 接收结果的编码', + `api_receive_msg` varchar(255) DEFAULT NULL COMMENT 'API 接收结果的说明', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COMMENT='短信moan'; + +-- ---------------------------- +-- Records of sys_sms_log +-- ---------------------------- +BEGIN; +INSERT INTO `sys_sms_log` VALUES (15, 1, 'YUN_PIAN', 2, 'test_01', 1, '正在进行登录操作登陆,您的验证码是1234', '{\"code\":\"1234\",\"operation\":\"登陆\"}', '4383920', '15601691399', 1, 2, 10, '2021-04-04 23:24:13', 0, '成功', '0', '发送成功', NULL, '62922707786', 10, '2021-04-04 23:24:26', 'DELIVRD', 'DELIVRD', NULL, '2021-04-04 23:23:29', NULL, '2021-04-04 23:25:17', b'0'); +INSERT INTO `sys_sms_log` VALUES (16, 2, 'ALIYUN', 3, 'test_02', 1, '您的验证码1234,该验证码5分钟内有效,请勿泄漏于他人!', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:08:39', 999, '未知错误,需要解析', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 2EA9C6A5-579F-4D21-B7D3-0AD3BA4F7741', '2EA9C6A5-579F-4D21-B7D3-0AD3BA4F7741', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:08:39', NULL, '2021-04-05 00:08:39', b'0'); +INSERT INTO `sys_sms_log` VALUES (17, 2, 'ALIYUN', 3, 'test_02', 1, '您的验证码1234,该验证码5分钟内有效,请勿泄漏于他人!', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:09:43', 999, '未知错误,需要解析', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : BF766164-9C03-44FD-B6D3-ADA74118E432', 'BF766164-9C03-44FD-B6D3-ADA74118E432', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:09:43', NULL, '2021-04-05 00:09:43', b'0'); +INSERT INTO `sys_sms_log` VALUES (18, 2, 'ALIYUN', 3, 'test_02', 1, '您的验证码1234,该验证码5分钟内有效,请勿泄漏于他人!', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:11:13', 999, '未知错误,需要解析', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 2D7C0ABC-7538-45B4-BFEF-B610D591CE3D', '2D7C0ABC-7538-45B4-BFEF-B610D591CE3D', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:11:12', NULL, '2021-04-05 00:11:13', b'0'); +INSERT INTO `sys_sms_log` VALUES (19, 2, 'ALIYUN', 3, 'test_02', 1, '您的验证码1234,该验证码5分钟内有效,请勿泄漏于他人!', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:12:21', 999, '未知错误,需要解析', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 0A86DC5C-2985-474F-B076-748C9F2C5D3F', '0A86DC5C-2985-474F-B076-748C9F2C5D3F', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:12:01', NULL, '2021-04-05 00:12:21', b'0'); +INSERT INTO `sys_sms_log` VALUES (20, 1, 'YUN_PIAN', 2, 'test_01', 1, '正在进行登录操作登陆,您的验证码是1234', '{\"code\":\"1234\",\"operation\":\"登陆\"}', '4383920', '15601691399', 1, 2, 10, '2021-04-05 00:14:36', 0, '成功', '0', '发送成功', NULL, '62923244790', 0, NULL, NULL, NULL, NULL, '2021-04-05 00:13:42', NULL, '2021-04-05 00:14:36', b'0'); +INSERT INTO `sys_sms_log` VALUES (21, 2, 'ALIYUN', 3, 'test_02', 1, '您的验证码1234,该验证码5分钟内有效,请勿泄漏于他人!', '{\"code\":\"1234\"}', 'SMS_207945135', '15601691399', 1, 2, 20, '2021-04-05 00:19:43', 999, '未知错误,需要解析', 'SDK.InvalidAccessKeySecret', 'SDK.InvalidAccessKeySecret : Specified Access Key Secret is not valid.\r\nRequestId : 3837C6D3-B96F-428C-BBB2-86135D4B5B99', '3837C6D3-B96F-428C-BBB2-86135D4B5B99', NULL, 0, NULL, NULL, NULL, NULL, '2021-04-05 00:15:06', NULL, '2021-04-05 00:19:44', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for sys_sms_template +-- ---------------------------- +DROP TABLE IF EXISTS `sys_sms_template`; +CREATE TABLE `sys_sms_template` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', + `type` tinyint(4) NOT NULL COMMENT '短信签名', + `status` tinyint(4) NOT NULL COMMENT '开启状态', + `code` varchar(63) NOT NULL COMMENT '模板编码', + `name` varchar(63) NOT NULL COMMENT '模板名称', + `content` varchar(255) NOT NULL COMMENT '模板内容', + `params` varchar(255) NOT NULL COMMENT '参数数组', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模板编号', + `channel_id` bigint(20) NOT NULL COMMENT '短信渠道编号', + `channel_code` varchar(63) NOT NULL COMMENT '短信渠道编码', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='短信模板'; + +-- ---------------------------- +-- Records of sys_sms_template +-- ---------------------------- +BEGIN; +INSERT INTO `sys_sms_template` VALUES (2, 1, 0, 'test_01', '测试验证码短信', '正在进行登录操作{operation},您的验证码是{code}', '[\"operation\",\"code\"]', NULL, '4383920', 1, 'YUN_PIAN', '', '2021-03-31 10:49:38', '', '2021-03-31 12:01:38', b'0'); +INSERT INTO `sys_sms_template` VALUES (3, 1, 0, 'test_02', '公告通知', '您的验证码{code},该验证码5分钟内有效,请勿泄漏于他人!', '[\"code\"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '', '2021-03-31 11:56:30', b'0'); +COMMIT; + -- ---------------------------- -- Table structure for sys_user -- ---------------------------- @@ -865,8 +990,8 @@ CREATE TABLE `sys_user` ( -- Records of sys_user -- ---------------------------- BEGIN; -INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:8080/api/system/file/get/add5ec1891a7d97d2cc1d60847e16294.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '1', '2021-03-21 18:16:16', b'0'); -INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '若依', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0'); +INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://api-dashboard.yudao.iocoder.cn/api/infra/file/get/5e8609290e915c4fa8b08e67.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '1', '2021-04-05 02:16:10', b'0'); +INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '若依', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-04-01 04:50:36', b'1'); INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '1', '2021-03-14 22:35:17', b'0'); INSERT INTO `sys_user` VALUES (103, 'yuanma', '', '源码', NULL, 100, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '', NULL, '', '2021-01-13 23:50:35', '', '2021-01-13 23:50:35', b'0'); INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$.TOFpaIiI3PzEwkGrNq0Eu6Cc3rOqJMxTb1DqeSEM8StxaGPBRKoi', '测试号', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '1', '2021-03-14 22:36:38', b'0'); @@ -924,11 +1049,17 @@ CREATE TABLE `sys_user_session` ( -- Records of sys_user_session -- ---------------------------- BEGIN; +INSERT INTO `sys_user_session` VALUES ('04c6624c7bf14b1ba1a01cb976a9d876', 1, '2021-04-05 21:40:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 20:21:09', NULL, '2021-04-01 12:25:35', b'1'); +INSERT INTO `sys_user_session` VALUES ('0e235ce5ae7342a09b372a00bd7d1b41', 1, '2021-04-05 01:43:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 00:51:03', NULL, '2021-04-01 04:18:06', b'1'); +INSERT INTO `sys_user_session` VALUES ('0e6943f8ca9b4215a014843eb489ccc7', 1, '2021-04-05 22:53:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:43:59', NULL, '2021-04-05 22:23:22', b'0'); +INSERT INTO `sys_user_session` VALUES ('40d532d8900c43b791266429a7911751', 1, '2021-04-05 22:11:34', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:41:34', NULL, '2021-04-01 12:28:20', b'1'); INSERT INTO `sys_user_session` VALUES ('505b4e7d8b0d4b40aa23bf540da81234', 1, '2021-03-14 01:25:13', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 00:31:43', NULL, '2021-03-13 07:35:26', b'1'); INSERT INTO `sys_user_session` VALUES ('5a7248bf87d14e7e9f0578b05969986c', 1, '2021-03-13 10:42:50', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 09:37:36', NULL, '2021-03-12 19:53:07', b'1'); +INSERT INTO `sys_user_session` VALUES ('8b3eac5e4a104a4191c8070e03d553ea', 1, '2021-04-05 02:45:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 02:15:12', NULL, '2021-04-01 11:05:25', b'1'); INSERT INTO `sys_user_session` VALUES ('9ae27346d8b7491aad1385f51e8aa196', 1, '2021-03-13 14:02:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 10:43:06', NULL, '2021-03-13 06:40:35', b'1'); INSERT INTO `sys_user_session` VALUES ('ae9ee7452ee54e4b983d658188c15c4d', 1, '2021-03-14 21:32:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 20:25:00', NULL, '2021-03-13 15:19:10', b'1'); -INSERT INTO `sys_user_session` VALUES ('d0adf48f82914212b947e5ab04d9fb65', 1, '2021-03-21 19:16:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 18:13:37', NULL, '2021-03-21 18:46:28', b'0'); +INSERT INTO `sys_user_session` VALUES ('d0adf48f82914212b947e5ab04d9fb65', 1, '2021-03-21 19:16:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 18:13:37', NULL, '2021-03-15 05:53:20', b'1'); +INSERT INTO `sys_user_session` VALUES ('e80c2400724042a2ab73732166cde8fc', 1, '2021-03-21 21:17:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 20:47:12', NULL, '2021-03-15 08:18:56', b'1'); INSERT INTO `sys_user_session` VALUES ('e8872f5192584440a548641b83c877ef', 1, '2021-03-21 18:36:01', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 17:51:48', NULL, '2021-03-15 03:54:20', b'1'); INSERT INTO `sys_user_session` VALUES ('f1ab99b09b5a475795579ff99d60ac78', 1, '2021-03-14 23:04:31', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 21:12:44', NULL, '2021-03-15 03:32:38', b'1'); INSERT INTO `sys_user_session` VALUES ('f853b50d064340a581e9a49bba9411fc', 1, '2021-03-10 01:55:41', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-12 18:37:05', b'1'); @@ -964,7 +1095,7 @@ CREATE TABLE `tool_codegen_column` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=389 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表字段定义'; +) ENGINE=InnoDB AUTO_INCREMENT=418 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表字段定义'; -- ---------------------------- -- Records of tool_codegen_column @@ -1126,6 +1257,35 @@ INSERT INTO `tool_codegen_column` VALUES (385, 33, 'create_time', 'datetime', ' INSERT INTO `tool_codegen_column` VALUES (386, 33, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 6, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); INSERT INTO `tool_codegen_column` VALUES (387, 33, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 7, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); INSERT INTO `tool_codegen_column` VALUES (388, 33, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 8, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); +INSERT INTO `tool_codegen_column` VALUES (389, 34, 'id', 'bigint(20)', '编号', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (390, 34, 'signature', 'varchar(8)', '短信签名', b'0', b'0', '0', 2, 'String', 'signature', '', '芋道源码', b'1', b'1', b'1', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (391, 34, 'code', 'varchar(63)', '渠道编码', b'0', b'0', '0', 3, 'String', 'code', 'sys_sms_channel_code', 'YUN_PIAN', b'1', b'0', b'0', '=', b'1', 'select', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (392, 34, 'status', 'tinyint(4)', '启用状态', b'0', b'0', '0', 4, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (393, 34, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 5, 'String', 'remark', '', '好吃!', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (394, 34, 'api_key', 'varchar(63)', '短信 API 的账号', b'0', b'0', '0', 6, 'String', 'apiKey', '', 'yudao', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (395, 34, 'api_secret', 'varchar(63)', '短信 API 的秘钥', b'1', b'0', '0', 7, 'String', 'apiSecret', '', 'yuanma', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (396, 34, 'callback_url', 'varchar(255)', '短信发送回调 URL', b'1', b'0', '0', 8, 'String', 'callbackUrl', '', 'http://www.iocoder.cn', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (397, 34, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (398, 34, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 10, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (399, 34, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (400, 34, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 12, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (401, 34, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 13, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_column` VALUES (402, 35, 'id', 'bigint(20)', '编号', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (403, 35, 'type', 'tinyint(4)', '短信签名', b'0', b'0', '0', 2, 'Integer', 'type', 'sys_sms_template_type', '1', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (404, 35, 'status', 'tinyint(4)', '开启状态', b'0', b'0', '0', 3, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (405, 35, 'code', 'varchar(63)', '模板编码', b'0', b'0', '0', 4, 'String', 'code', '', 'test_01', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (406, 35, 'name', 'varchar(63)', '模板名称', b'0', b'0', '0', 5, 'String', 'name', '', 'yudao', b'1', b'1', b'0', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (407, 35, 'content', 'varchar(255)', '模板内容', b'0', b'0', '0', 6, 'String', 'content', '', '你好,{name}。你长的太{like}啦!', b'1', b'1', b'1', 'LIKE', b'1', 'editor', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (408, 35, 'params', 'varchar(255)', '参数数组', b'0', b'0', '0', 7, 'String', 'params', '', 'name,code', b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (409, 35, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 8, 'String', 'remark', '', '哈哈哈', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (410, 35, 'api_template_id', 'varchar(63)', '短信 API 的模板编号', b'0', b'0', '0', 9, 'String', 'apiTemplateId', '', '4383920', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (411, 35, 'channel_id', 'bigint(20)', '短信渠道编号', b'0', b'0', '0', 10, 'Long', 'channelId', '', '10', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (412, 35, 'channel_code', 'varchar(63)', '短信渠道编码', b'0', b'0', '0', 11, 'String', 'channelCode', 'sys_sms_channel_code', 'ALIYUN', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (413, 35, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 12, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (414, 35, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 13, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (415, 35, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 14, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (416, 35, 'update_time', 'datetime', '更新时间', b'0', b'0', '0', 15, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); +INSERT INTO `tool_codegen_column` VALUES (417, 35, 'deleted', 'bit(1)', '是否删除', b'0', b'0', '0', 16, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0'); COMMIT; -- ---------------------------- @@ -1151,7 +1311,7 @@ CREATE TABLE `tool_codegen_table` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表定义'; +) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COMMENT='代码生成表定义'; -- ---------------------------- -- Records of tool_codegen_table @@ -1169,6 +1329,8 @@ INSERT INTO `tool_codegen_table` VALUES (28, 1, 'sys_dict_type', '字典类型 INSERT INTO `tool_codegen_table` VALUES (29, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dict', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:52:57', '', '2021-03-06 04:03:52', b'0'); INSERT INTO `tool_codegen_table` VALUES (30, 1, 'sys_dict_data', '字典数据表', NULL, 'system', 'type', 'SysDictData', '字典数据', '芋道源码', 1, NULL, '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:47', b'0'); INSERT INTO `tool_codegen_table` VALUES (33, 1, 'inf_file', '文件表', NULL, 'infra', 'file', 'InfFile', '文件', '芋艿', 1, 2, '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0'); +INSERT INTO `tool_codegen_table` VALUES (34, 1, 'sys_sms_channel', '短信渠道', NULL, 'system', 'sms', 'SysSmsChannel', '短信渠道', '芋道源码', 1, 1093, '1', '2021-04-03 13:39:06', '1', '2021-04-05 20:52:09', b'0'); +INSERT INTO `tool_codegen_table` VALUES (35, 1, 'sys_sms_template', '短信模板', NULL, 'system', 'sms', 'SysSmsTemplate', '短信模板', '芋道源码', 1, 1093, '1', '2021-04-03 13:58:55', '1', '2021-04-05 22:23:38', b'0'); COMMIT; -- ---------------------------- diff --git a/sql/sms.sql b/sql/sms.sql deleted file mode 100644 index 6d9c3c8e5..000000000 --- a/sql/sms.sql +++ /dev/null @@ -1,109 +0,0 @@ -/* - --2021.02.01 by fight, sms about table info -*/ - --- ---------------------------- --- Table structure for sms_channel --- ---------------------------- -DROP TABLE IF EXISTS `sms_channel`; -CREATE TABLE `sms_channel` -( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `code` varchar(50) NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)', - `api_key` varchar(100) NOT NULL COMMENT '账号id', - `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', - `callback_url` varchar(100) NOT NULL default '' COMMENT '回调请求路径', - `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识', - `name` varchar(50) NOT NULL COMMENT '名称', - `signature` varchar(50) NOT NULL COMMENT '签名值', - `remark` varchar(200) NOT NULL COMMENT '备注', - - `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)', - `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB - AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信渠道'; -/* - 优先级值一样时,按照id顺序取值 -*/ - --- ---------------------------- --- Table structure for sms_template --- ---------------------------- -DROP TABLE IF EXISTS `sms_template`; -CREATE TABLE `sms_template` -( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', - `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', - `type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]', - `biz_code` varchar(50) NOT NULL COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', - `code` varchar(50) NOT NULL COMMENT '编码', - `name` varchar(50) NOT NULL COMMENT '名称', - `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识', - `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', - `remark` varchar(200) NOT NULL COMMENT '备注', - - `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)', - `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB - AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板'; -/* --- ---------------------------- --- Table structure for sms_query_log --- ---------------------------- -DROP TABLE IF EXISTS `sms_query_log`; -CREATE TABLE `sms_query_log` -( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `api_id` varchar(100) NOT NULL COMMENT '第三方唯一标识', - `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', - `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', - `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `phone` char(11) NOT NULL COMMENT '手机号', - `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `send_result_param` varchar(200) NOT NULL DEFAULT '' COMMENT '查询短信发送结果的参数', - `send_status` tinyint(1) NOT NULL DEFAULT 2 COMMENT '发送状态(0本地异步中 1发送请求失败 2发送请求成功)', - `got_result` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否获取发送结果', - `had_callback` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数', - `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB - AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志';*/ - --- ---------------------------- --- Table structure for sms_log --- ---------------------------- -DROP TABLE IF EXISTS `sms_query_log`; -CREATE TABLE `sms_query_log` -( - `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号', - `api_id` varchar(100) NOT NULL COMMENT '第三方唯一标识', - `channel_code` varchar(50) NOT NULL COMMENT '短信渠道编码(来自枚举类)', - `channel_id` bigint(20) NOT NULL COMMENT '短信渠道id', - `template_code` varchar(50) NOT NULL COMMENT '渠道编码', - `phone` char(11) NOT NULL COMMENT '手机号', - `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容', - `send_status` tinyint(1) NOT NULL DEFAULT 0 COMMENT '发送状态 详情见:SmsSendStatusEnum', - `remark` varchar(200) DEFAULT NULL COMMENT '备注', - `create_by` varchar(64) NOT NULL DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `send_time` datetime DEFAULT NULL COMMENT '发送时间', - PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB - AUTO_INCREMENT = 1 - DEFAULT CHARSET = utf8mb4 COMMENT ='短信发送日志'; diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java index ee1b3f2d9..cebfb9c17 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java @@ -13,7 +13,7 @@ import java.util.List; @Mapper public interface SysSmsTemplateMapper extends BaseMapperX { - default SysSmsTemplateDO selectOneByCode(String code) { + default SysSmsTemplateDO selectByCode(String code) { return selectOne("code", code); } diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java index 6fbd295b4..e9eb648ac 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java @@ -80,9 +80,11 @@ public interface SysErrorCodeConstants { // ========== 短信渠道 1002011000 ========== ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在"); + ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1002011001, "短信渠道不处于开启状态,不允许选择"); // ========== 短信模板 1002011000 ========== ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在"); + ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}}】的短信模板"); // ========== 短信发送 1002012000 ========== ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在"); diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index ac54a2565..768301147 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -1,24 +1,31 @@ package cn.iocoder.dashboard.modules.system.service.sms.impl; +import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsTemplateConvert; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; +import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; +import com.google.common.annotations.VisibleForTesting; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.regex.Pattern; import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; /** * 短信模板Service实现类 @@ -29,12 +36,20 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SM @Service public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { + /** + * 正则表达式,匹配 {} 中的变量 + */ + private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}"); + @Resource private SysSmsTemplateMapper smsTemplateMapper; + @Resource + private SysSmsChannelService smsChannelService; + @Override public SysSmsTemplateDO getSmsTemplateByCode(String code) { - return smsTemplateMapper.selectOneByCode(code); + return smsTemplateMapper.selectByCode(code); } @Override @@ -42,13 +57,25 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return StrUtil.format(content, params); } + @VisibleForTesting + public List parseTemplateContentParams(String content) { + return ReUtil.findAllGroup1(PATTERN_PARAMS, content); + } + @Override public Long createSmsTemplate(SysSmsTemplateCreateReqVO createReqVO) { + // 校验短信渠道 + SysSmsChannelDO channelDO = checkSmsChannel(createReqVO.getChannelId()); + // 校验短信编码是否重复 + checkSmsTemplateCodeDuplicate(null, createReqVO.getCode()); + // 插入 - SysSmsTemplateDO smsTemplate = SysSmsTemplateConvert.INSTANCE.convert(createReqVO); - smsTemplateMapper.insert(smsTemplate); + SysSmsTemplateDO template = SysSmsTemplateConvert.INSTANCE.convert(createReqVO); + template.setParams(parseTemplateContentParams(template.getContent())); + template.setChannelCode(channelDO.getCode()); + smsTemplateMapper.insert(template); // 返回 - return smsTemplate.getId(); + return template.getId(); } @Override @@ -94,4 +121,29 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return smsTemplateMapper.selectList(exportReqVO); } + private SysSmsChannelDO checkSmsChannel(Long channelId) { + SysSmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); + if (channelDO == null) { + throw exception(SMS_CHANNEL_NOT_EXISTS); + } + if (!Objects.equals(channelDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) { + throw exception(SMS_CHANNEL_DISABLE); + } + return channelDO; + } + + private void checkSmsTemplateCodeDuplicate(Long id, String code) { + SysSmsTemplateDO template = smsTemplateMapper.selectByCode(code); + if (template == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的字典类型 + if (id == null) { + throw exception(SMS_TEMPLATE_CODE_DUPLICATE); + } + if (!template.getId().equals(id)) { + throw exception(SMS_TEMPLATE_CODE_DUPLICATE); + } + } + } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java index a04034155..baac614d2 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java @@ -1,27 +1,37 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.BaseDbUnitTest; +import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; +import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; +import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum; import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsTemplateServiceImpl; +import cn.iocoder.dashboard.util.collection.ArrayUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; +import com.google.common.collect.Lists; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.List; +import java.util.function.Consumer; +import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS; import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; import static cn.iocoder.dashboard.util.RandomUtils.randomLongId; import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; /** * {@link SysSmsTemplateServiceImpl} 的单元测试类 @@ -37,10 +47,35 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { @Resource private SysSmsTemplateMapper smsTemplateMapper; + @MockBean + private SysSmsChannelService smsChannelService; + + @Test + public void testParseTemplateContentParams() { + // 准备参数 + String content = "正在进行登录操作{operation},您的验证码是{code}"; + // mock 方法 + + // 调用 + List params = smsTemplateService.parseTemplateContentParams(content); + // 断言 + assertEquals(Lists.newArrayList("operation", "code"), params); + } + @Test public void testCreateSmsTemplate_success() { // 准备参数 - SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class); + SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class, o -> { + o.setContent("正在进行登录操作{operation},您的验证码是{code}"); + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微 + }); + // mock 方法 + SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> { + o.setId(reqVO.getChannelId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); // 调用 Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); @@ -49,6 +84,8 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { // 校验记录的属性是否正确 SysSmsTemplateDO smsTemplate = smsTemplateMapper.selectById(smsTemplateId); assertPojoEquals(reqVO, smsTemplate); + assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); + assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); } @Test @@ -80,7 +117,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { @Test public void testDeleteSmsTemplate_success() { // mock 数据 - SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class); + SysSmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 // 准备参数 Long id = dbSmsTemplate.getId(); @@ -191,4 +228,13 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { assertPojoEquals(dbSmsTemplate, list.get(0)); } + @SafeVarargs + private static SysSmsTemplateDO randomSmsTemplateDO(Consumer... consumers) { + Consumer consumer = (o) -> { + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微 + }; + return randomPojo(SysSmsTemplateDO.class, ArrayUtils.append(consumer, consumers)); + } + } diff --git a/src/test/resources/sql/create_tables.sql b/src/test/resources/sql/create_tables.sql index 6ef2d705d..2d758f7a5 100644 --- a/src/test/resources/sql/create_tables.sql +++ b/src/test/resources/sql/create_tables.sql @@ -358,3 +358,23 @@ CREATE TABLE IF NOT EXISTS "sys_sms_channel" ( "deleted" bit NOT NULL DEFAULT FALSE, PRIMARY KEY ("id") ) COMMENT '短信渠道'; + +CREATE TABLE "sys_sms_template" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "type" tinyint NOT NULL, + "status" tinyint NOT NULL, + "code" varchar(63) NOT NULL, + "name" varchar(63) NOT NULL, + "content" varchar(255) NOT NULL, + "params" varchar(255) NOT NULL, + "remark" varchar(255) DEFAULT NULL, + "api_template_id" varchar(63) NOT NULL, + "channel_id" bigint NOT NULL, + "channel_code" varchar(63) NOT NULL, + "creator" varchar(64) DEFAULT '', + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar(64) DEFAULT '', + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '短信模板'; From 4a40771057bf80e5260f0e139c0c569f5ab27d0b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Apr 2021 00:04:02 +0800 Subject: [PATCH 35/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sms/impl/SysSmsTemplateServiceImpl.java | 13 +- .../permission/SysMenuServiceTest.java | 11 +- .../sms/SysSmsTemplateServiceTest.java | 218 ++++++++++++------ src/test/resources/sql/clean.sql | 1 + 4 files changed, 167 insertions(+), 76 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index 768301147..f3e50547d 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -82,8 +82,15 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { public void updateSmsTemplate(SysSmsTemplateUpdateReqVO updateReqVO) { // 校验存在 this.validateSmsTemplateExists(updateReqVO.getId()); + // 校验短信渠道 + SysSmsChannelDO channelDO = checkSmsChannel(updateReqVO.getChannelId()); + // 校验短信编码是否重复 + checkSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + // 更新 SysSmsTemplateDO updateObj = SysSmsTemplateConvert.INSTANCE.convert(updateReqVO); + updateObj.setParams(parseTemplateContentParams(updateObj.getContent())); + updateObj.setChannelCode(channelDO.getCode()); smsTemplateMapper.updateById(updateObj); } @@ -121,7 +128,8 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return smsTemplateMapper.selectList(exportReqVO); } - private SysSmsChannelDO checkSmsChannel(Long channelId) { + @VisibleForTesting + public SysSmsChannelDO checkSmsChannel(Long channelId) { SysSmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId); if (channelDO == null) { throw exception(SMS_CHANNEL_NOT_EXISTS); @@ -132,7 +140,8 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { return channelDO; } - private void checkSmsTemplateCodeDuplicate(Long id, String code) { + @VisibleForTesting + public void checkSmsTemplateCodeDuplicate(Long id, String code) { SysSmsTemplateDO template = smsTemplateMapper.selectByCode(code); if (template == null) { return; diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java index 35a88e741..21d3d3f58 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuServiceTest.java @@ -12,7 +12,6 @@ import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum; import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer; import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl; import cn.iocoder.dashboard.util.AopTargetUtils; -import cn.iocoder.dashboard.util.AssertUtils; import cn.iocoder.dashboard.util.RandomUtils; import cn.iocoder.dashboard.util.object.ObjectUtils; import com.google.common.collect.Multimap; @@ -22,7 +21,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import javax.annotation.Resource; - import java.util.*; import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; @@ -273,10 +271,10 @@ public class SysMenuServiceTest extends BaseDbUnitTest { menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2); mockCacheMap.put(menuDO.getId(), menuDO); - List menuDOS = sysMenuService.listMenusFromCache(Arrays.asList(1L), - Arrays.asList(MenuTypeEnum.MENU.getType()), Arrays.asList(1)); + List menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(1L), + Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(1)); Assert.isTrue(menuDOS.size() == idMenuMap.size()); - menuDOS.stream().forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu)); + menuDOS.forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu)); } @Test @@ -354,14 +352,13 @@ public class SysMenuServiceTest extends BaseDbUnitTest { } private SysMenuDO createMenuDO(Long id, MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) { - SysMenuDO sonMenuDO = RandomUtils.randomPojo(SysMenuDO.class, o -> { + return RandomUtils.randomPojo(SysMenuDO.class, o -> { o.setId(id); o.setParentId(parentId); o.setType(typeEnum.getType()); o.setStatus(status); o.setName(menuName); }); - return sonMenuDO; } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java index baac614d2..7e79d3aa7 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java @@ -3,10 +3,7 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.*; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; @@ -24,11 +21,11 @@ import java.util.List; import java.util.function.Consumer; import static cn.hutool.core.util.RandomUtil.randomEle; -import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS; +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals; import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException; -import static cn.iocoder.dashboard.util.RandomUtils.randomLongId; -import static cn.iocoder.dashboard.util.RandomUtils.randomPojo; +import static cn.iocoder.dashboard.util.RandomUtils.*; +import static cn.iocoder.dashboard.util.date.DateUtils.buildTime; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -91,18 +88,29 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { @Test public void testUpdateSmsTemplate_success() { // mock 数据 - SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class); + SysSmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据 // 准备参数 SysSmsTemplateUpdateReqVO reqVO = randomPojo(SysSmsTemplateUpdateReqVO.class, o -> { o.setId(dbSmsTemplate.getId()); // 设置更新的 ID + o.setContent("正在进行登录操作{operation},您的验证码是{code}"); + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 + o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微 }); + // mock 方法 + SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> { + o.setId(reqVO.getChannelId()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); // 调用 smsTemplateService.updateSmsTemplate(reqVO); // 校验是否更新正确 SysSmsTemplateDO smsTemplate = smsTemplateMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, smsTemplate); + assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams()); + assertEquals(channelDO.getCode(), smsTemplate.getChannelCode()); } @Test @@ -137,43 +145,43 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { assertServiceException(() -> smsTemplateService.deleteSmsTemplate(id), SMS_TEMPLATE_NOT_EXISTS); } - @Test // TODO 请修改 null 为需要的值 + @Test public void testGetSmsTemplatePage() { // mock 数据 SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class, o -> { // 等会查询到 - o.setType(null); - o.setStatus(null); - o.setCode(null); - o.setContent(null); - o.setApiTemplateId(null); - o.setChannelId(null); - o.setCreateTime(null); + o.setType(SysSmsTemplateTypeEnum.PROMOTION.getType()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCode("yudaoyuanma"); + o.setContent("芋道源码"); + o.setApiTemplateId("yunai"); + o.setChannelId(1L); + o.setCreateTime(buildTime(2021, 11, 11)); }); smsTemplateMapper.insert(dbSmsTemplate); // 测试 type 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); // 测试 status 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); // 测试 code 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode("yuanma"))); // 测试 content 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent("源码"))); // 测试 apiTemplateId 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); // 测试 channelId 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(2L))); // 测试 createTime 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(null))); + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); // 准备参数 SysSmsTemplatePageReqVO reqVO = new SysSmsTemplatePageReqVO(); - reqVO.setType(null); - reqVO.setStatus(null); - reqVO.setCode(null); - reqVO.setContent(null); - reqVO.setApiTemplateId(null); - reqVO.setChannelId(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); + reqVO.setType(SysSmsTemplateTypeEnum.PROMOTION.getType()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCode("yudao"); + reqVO.setContent("芋道"); + reqVO.setApiTemplateId("yu"); + reqVO.setChannelId(1L); + reqVO.setBeginCreateTime(buildTime(2021, 11, 1)); + reqVO.setEndCreateTime(buildTime(2021, 12, 1)); // 调用 PageResult pageResult = smsTemplateService.getSmsTemplatePage(reqVO); @@ -183,43 +191,43 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0)); } - @Test // TODO 请修改 null 为需要的值 + @Test public void testGetSmsTemplateList() { - // mock 数据 - SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class, o -> { // 等会查询到 - o.setType(null); - o.setStatus(null); - o.setCode(null); - o.setContent(null); - o.setApiTemplateId(null); - o.setChannelId(null); - o.setCreateTime(null); - }); - smsTemplateMapper.insert(dbSmsTemplate); - // 测试 type 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(null))); - // 测试 status 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(null))); - // 测试 code 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode(null))); - // 测试 content 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent(null))); - // 测试 apiTemplateId 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId(null))); - // 测试 channelId 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(null))); - // 测试 createTime 不匹配 - smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(null))); - // 准备参数 - SysSmsTemplateExportReqVO reqVO = new SysSmsTemplateExportReqVO(); - reqVO.setType(null); - reqVO.setStatus(null); - reqVO.setCode(null); - reqVO.setContent(null); - reqVO.setApiTemplateId(null); - reqVO.setChannelId(null); - reqVO.setBeginCreateTime(null); - reqVO.setEndCreateTime(null); + // mock 数据 + SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class, o -> { // 等会查询到 + o.setType(SysSmsTemplateTypeEnum.PROMOTION.getType()); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCode("yudaoyuanma"); + o.setContent("芋道源码"); + o.setApiTemplateId("yunai"); + o.setChannelId(1L); + o.setCreateTime(buildTime(2021, 11, 11)); + }); + smsTemplateMapper.insert(dbSmsTemplate); + // 测试 type 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setType(SysSmsTemplateTypeEnum.VERIFICATION_CODE.getType()))); + // 测试 status 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); + // 测试 code 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCode("yuanma"))); + // 测试 content 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setContent("源码"))); + // 测试 apiTemplateId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setApiTemplateId("nai"))); + // 测试 channelId 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setChannelId(2L))); + // 测试 createTime 不匹配 + smsTemplateMapper.insert(ObjectUtils.clone(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12)))); + // 准备参数 + SysSmsTemplateExportReqVO reqVO = new SysSmsTemplateExportReqVO(); + reqVO.setType(SysSmsTemplateTypeEnum.PROMOTION.getType()); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setCode("yudao"); + reqVO.setContent("芋道"); + reqVO.setApiTemplateId("yu"); + reqVO.setChannelId(1L); + reqVO.setBeginCreateTime(buildTime(2021, 11, 1)); + reqVO.setEndCreateTime(buildTime(2021, 12, 1)); // 调用 List list = smsTemplateService.getSmsTemplateList(reqVO); @@ -228,6 +236,82 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { assertPojoEquals(dbSmsTemplate, list.get(0)); } + @Test + public void testCheckSmsChannel_success() { + // 准备参数 + Long channelId = randomLongId(); + // mock 方法 + SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> { + o.setId(channelId); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 + }); + when(smsChannelService.getSmsChannel(eq(channelId))).thenReturn(channelDO); + + // 调用 + SysSmsChannelDO returnChannelDO = smsTemplateService.checkSmsChannel(channelId); + // 断言 + assertPojoEquals(returnChannelDO, channelDO); + } + + @Test + public void testCheckSmsChannel_notExists() { + // 准备参数 + Long channelId = randomLongId(); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.checkSmsChannel(channelId), + SMS_CHANNEL_NOT_EXISTS); + } + + @Test + public void testCheckSmsChannel_disable() { + // 准备参数 + Long channelId = randomLongId(); + // mock 方法 + SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> { + o.setId(channelId); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); // 保证 status 禁用,触发失败 + }); + when(smsChannelService.getSmsChannel(eq(channelId))).thenReturn(channelDO); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.checkSmsChannel(channelId), + SMS_CHANNEL_DISABLE); + } + + @Test + public void testCheckDictDataValueUnique_success() { + // 调用,成功 + smsTemplateService.checkSmsTemplateCodeDuplicate(randomLongId(), randomString()); + } + + @Test + public void testCheckDictDataValueUnique_valueDuplicateForCreate() { + // 准备参数 + String code = randomString(); + // mock 数据 + smsTemplateMapper.insert(randomSmsTemplateDO(o -> o.setCode(code))); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.checkSmsTemplateCodeDuplicate(null, code), + SMS_TEMPLATE_CODE_DUPLICATE); + } + + @Test + public void testCheckDictDataValueUnique_valueDuplicateForUpdate() { + // 准备参数 + Long id = randomLongId(); + String code = randomString(); + // mock 数据 + smsTemplateMapper.insert(randomSmsTemplateDO(o -> o.setCode(code))); + + // 调用,校验异常 + assertServiceException(() -> smsTemplateService.checkSmsTemplateCodeDuplicate(id, code), + SMS_TEMPLATE_CODE_DUPLICATE); + } + + // ========== 随机对象 ========== + @SafeVarargs private static SysSmsTemplateDO randomSmsTemplateDO(Consumer... consumers) { Consumer consumer = (o) -> { diff --git a/src/test/resources/sql/clean.sql b/src/test/resources/sql/clean.sql index ae95d824e..c1965cbda 100644 --- a/src/test/resources/sql/clean.sql +++ b/src/test/resources/sql/clean.sql @@ -20,3 +20,4 @@ DELETE FROM "sys_login_log"; DELETE FROM "sys_operate_log"; DELETE FROM "sys_user"; DELETE FROM "sys_sms_channel"; +DELETE FROM "sys_sms_template"; From e52f0b7dacbffb4b2023d807af08f861cf1c1c21 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 7 Apr 2021 00:49:10 +0800 Subject: [PATCH 36/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=20ui=20=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/api/system/sms/smsTemplate.js | 54 ++++ ruoyi-ui/src/utils/dict.js | 1 + ruoyi-ui/src/views/system/sms/smsTemplate.vue | 306 ++++++++++++++++++ .../sms/vo/template/SysSmsTemplateBaseVO.java | 4 +- 4 files changed, 363 insertions(+), 2 deletions(-) create mode 100644 ruoyi-ui/src/api/system/sms/smsTemplate.js create mode 100644 ruoyi-ui/src/views/system/sms/smsTemplate.vue diff --git a/ruoyi-ui/src/api/system/sms/smsTemplate.js b/ruoyi-ui/src/api/system/sms/smsTemplate.js new file mode 100644 index 000000000..b68998e1e --- /dev/null +++ b/ruoyi-ui/src/api/system/sms/smsTemplate.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +// 创建短信模板 +export function createSmsTemplate(data) { + return request({ + url: '/system/sms-template/create', + method: 'post', + data: data + }) +} + +// 更新短信模板 +export function updateSmsTemplate(data) { + return request({ + url: '/system/sms-template/update', + method: 'put', + data: data + }) +} + +// 删除短信模板 +export function deleteSmsTemplate(id) { + return request({ + url: '/system/sms-template/delete?id=' + id, + method: 'delete' + }) +} + +// 获得短信模板 +export function getSmsTemplate(id) { + return request({ + url: '/system/sms-template/get?id=' + id, + method: 'get' + }) +} + +// 获得短信模板分页 +export function getSmsTemplatePage(query) { + return request({ + url: '/system/sms-template/page', + method: 'get', + params: query + }) +} + +// 导出短信模板 Excel +export function exportSmsTemplateExcel(query) { + return request({ + url: '/system/sms-template/export-excel', + method: 'get', + params: query, + responseType: 'blob' + }) +} diff --git a/ruoyi-ui/src/utils/dict.js b/ruoyi-ui/src/utils/dict.js index bf6d72587..1a61a989a 100644 --- a/ruoyi-ui/src/utils/dict.js +++ b/ruoyi-ui/src/utils/dict.js @@ -18,6 +18,7 @@ export const DICT_TYPE = { SYS_LOGIN_RESULT: 'sys_login_result', SYS_CONFIG_TYPE: 'sys_config_type', SYS_SMS_CHANNEL_CODE: 'sys_sms_channel_code', + SYS_SMS_TEMPLATE_TYPE: 'sys_sms_template_type', INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', INF_JOB_STATUS: 'inf_job_status', diff --git a/ruoyi-ui/src/views/system/sms/smsTemplate.vue b/ruoyi-ui/src/views/system/sms/smsTemplate.vue new file mode 100644 index 000000000..b8a3a7b17 --- /dev/null +++ b/ruoyi-ui/src/views/system/sms/smsTemplate.vue @@ -0,0 +1,306 @@ + + + diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java index f2ef6ac16..584050d55 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateBaseVO.java @@ -12,8 +12,8 @@ import javax.validation.constraints.NotNull; @Data public class SysSmsTemplateBaseVO { - @ApiModelProperty(value = "短信签名", required = true, example = "1", notes = "参见 SysSmsTemplateTypeEnum 枚举类") - @NotNull(message = "短信签名不能为空") + @ApiModelProperty(value = "短信类型", required = true, example = "1", notes = "参见 SysSmsTemplateTypeEnum 枚举类") + @NotNull(message = "短信类型不能为空") private Integer type; @ApiModelProperty(value = "开启状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类") From bdbc5b2626823c8715e310f09fd9b3bfd9751b05 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 8 Apr 2021 00:51:59 +0800 Subject: [PATCH 37/54] =?UTF-8?q?1.=20=E9=98=BF=E9=87=8C=E4=BA=91=20sms=20?= =?UTF-8?q?client=20=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=E5=B0=81=E8=A3=85=202.=20=E9=87=8D=E6=9E=84=E9=98=BF?= =?UTF-8?q?=E9=87=8C=E4=BA=91=20sms=20client=20=E5=AE=A2=E6=88=B7=E7=AB=AF?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20invoke=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/sms/core/client/SmsClient.java | 9 +++ .../core/client/dto/SmsTemplateRespDTO.java | 33 +++++++++ .../core/client/impl/AbstractSmsClient.java | 20 +++++- .../client/impl/aliyun/AliyunSmsClient.java | 68 ++++++++++++++----- .../impl/aliyun/AliyunSmsCodeMapping.java | 1 + .../client/impl/yunpian/YunpianSmsClient.java | 6 ++ .../enums/SmsTemplateAuditStatusEnum.java | 21 ++++++ .../AliyunSmsClientIntegrationTest.java | 25 +++++-- 8 files changed, 161 insertions(+), 22 deletions(-) create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java create mode 100644 src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java index 591ded92e..9d156dd69 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.sms.core.client; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import java.util.List; @@ -41,4 +42,12 @@ public interface SmsClient { */ List parseSmsReceiveStatus(String text) throws Throwable; + /** + * 查询指定的短信模板 + * + * @param apiTemplateId 短信 API 的模板编号 + * @return 短信模板 + */ + SmsCommonResult getSmsTemplate(String apiTemplateId); + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java new file mode 100644 index 000000000..938310e71 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java @@ -0,0 +1,33 @@ +package cn.iocoder.dashboard.framework.sms.core.client.dto; + +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; +import lombok.Data; + +/** + * 短信模板 Response DTO + * + * @author 芋道源码 + */ +@Data +public class SmsTemplateRespDTO { + + /** + * 模板编号 + */ + private String id; + /** + * 短信内容 + */ + private String content; + /** + * 审核状态 + * + * 枚举 {@link SmsTemplateAuditStatusEnum} + */ + private Integer auditStatus; + /** + * 审核未通过的理由 + */ + private String auditReason; + +} diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java index a443e5e11..254040229 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java @@ -6,6 +6,7 @@ import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import lombok.extern.slf4j.Slf4j; @@ -77,7 +78,7 @@ public abstract class AbstractSmsClient implements SmsClient { result = doSendSms(logId, mobile, apiTemplateId, templateParams); } catch (Throwable ex) { // 打印异常日志 - log.error("[send][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", + log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]", logId, mobile, apiTemplateId, templateParams, ex); // 封装返回 return SmsCommonResult.error(ex); @@ -101,4 +102,21 @@ public abstract class AbstractSmsClient implements SmsClient { protected abstract List doParseSmsReceiveStatus(String text) throws Throwable; + @Override + public SmsCommonResult getSmsTemplate(String apiTemplateId) { + // 执行短信发送 + SmsCommonResult result; + try { + result = doGetSmsTemplate(apiTemplateId); + } catch (Throwable ex) { + // 打印异常日志 + log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex); + // 封装返回 + return SmsCommonResult.error(ex); + } + return result; + } + + protected abstract SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable; + } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index 8dae88586..b2c4c13ad 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -1,21 +1,25 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.util.collection.MapUtils; import cn.iocoder.dashboard.util.json.JsonUtils; +import com.aliyuncs.AcsRequest; +import com.aliyuncs.AcsResponse; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; -import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.aliyuncs.exceptions.ClientException; -import com.aliyuncs.http.MethodType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import com.fasterxml.jackson.annotation.JsonFormat; @@ -25,6 +29,8 @@ import lombok.extern.slf4j.Slf4j; import java.util.Date; import java.util.List; +import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -66,25 +72,13 @@ public class AliyunSmsClient extends AbstractSmsClient { String apiTemplateId, List> templateParams) { // 构建参数 SendSmsRequest request = new SendSmsRequest(); - request.setSysMethod(MethodType.POST); request.setPhoneNumbers(mobile); request.setSignName(properties.getSignature()); request.setTemplateCode(apiTemplateId); request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams))); request.setOutId(String.valueOf(sendLogId)); - - try { - // 执行发送 - SendSmsResponse sendResult = acsClient.getAcsResponse(request); - // 解析结果 - SmsSendRespDTO data = null; - if (sendResult.getBizId() != null) { - data = new SmsSendRespDTO().setSerialNo(sendResult.getBizId()); - } - return SmsCommonResult.build(sendResult.getCode(), sendResult.getMessage(), sendResult.getRequestId(), data, codeMapping); - } catch (ClientException ex) { - return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); - } + // 执行请求 + return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId())); } private static String formatResultMsg(ClientException ex) { @@ -107,6 +101,48 @@ public class AliyunSmsClient extends AbstractSmsClient { }).collect(Collectors.toList()); } + @Override + protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) { + // 构建参数 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest(); + request.setTemplateCode(apiTemplateId); + // 执行请求 + return invoke(request, response -> { + SmsTemplateRespDTO data = new SmsTemplateRespDTO(); + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent()); + data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason()); + return data; + }); + } + + private Integer convertSmsTemplateAuditStatus(Integer templateStatus) { + switch (templateStatus) { + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus)); + } + } + + private SmsCommonResult invoke(AcsRequest request, Function consumer) { + try { + // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 + T sendResult = acsClient.getAcsResponse(request); + String code = (String) ReflectUtil.getFieldValue(sendResult, "code"); + String message = (String) ReflectUtil.getFieldValue(sendResult, "message"); + String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId"); + // 解析结果 + R data = null; + if (Objects.equals(code, "OK")) { // 请求成功的情况下 + data = consumer.apply(sendResult); + } + // 拼接结果 + return SmsCommonResult.build(code, message, requestId, data, codeMapping); + } catch (ClientException ex) { + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping); + } + } + /** * 短信接收状态 * diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java index 8a804de0c..ee491ef5e 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java @@ -21,6 +21,7 @@ public class AliyunSmsCodeMapping implements SmsCodeMapping { case "isp.RAM_PERMISSION_DENY": return SMS_CHANNEL_PERMISSION_DENY; case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR; case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_LIMIT_CONTROL; + case "isv.SMS_TEMPLATE_ILLEGAL": return SMS_TEMPLATE_NOT_EXISTS; } return SMS_UNKNOWN; } diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index 59c61e45e..f72db456b 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -8,6 +8,7 @@ import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.util.json.JsonUtils; @@ -114,6 +115,11 @@ public class YunpianSmsClient extends AbstractSmsClient { }).collect(Collectors.toList()); } + @Override + protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable { + return null; + } + /** * 短信接收状态 * diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java new file mode 100644 index 000000000..888b2eeb5 --- /dev/null +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java @@ -0,0 +1,21 @@ +package cn.iocoder.dashboard.framework.sms.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 短信模板的审核状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum SmsTemplateAuditStatusEnum { + + CHECKING(1), + SUCCESS(2), + FAIL(3); + + private final Integer status; + +} diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java index 8643a3a6c..dc1904a3a 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClientIntegrationTest.java @@ -3,8 +3,10 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -15,8 +17,10 @@ import java.util.List; */ public class AliyunSmsClientIntegrationTest { - @Test - public void testSend() { + private static AliyunSmsClient smsClient; + + @BeforeAll + public static void before() { // 创建配置类 SmsChannelProperties properties = new SmsChannelProperties(); properties.setId(1L); @@ -25,14 +29,25 @@ public class AliyunSmsClientIntegrationTest { properties.setApiKey(System.getenv("ALIYUN_ACCESS_KEY")); properties.setApiSecret(System.getenv("ALIYUN_SECRET_KEY")); // 创建客户端 - AliyunSmsClient smsClient = new AliyunSmsClient(properties); + smsClient = new AliyunSmsClient(properties); smsClient.init(); - // 发送短信 + } + + @Test + public void testSendSms() { List> templateParams = new ArrayList<>(); templateParams.add(new KeyValue<>("code", "1024")); // templateParams.put("operation", "嘿嘿"); // SmsResult result = smsClient.send(1L, "15601691399", "4372216", templateParams); - SmsCommonResult result = smsClient.sendSms(1L, "15601691399", "SMS_207945135", templateParams); + SmsCommonResult result = smsClient.sendSms(1L, "15601691399", + "SMS_207945135", templateParams); + System.out.println(result); + } + + @Test + public void testGetSmsTemplate() { + String apiTemplateId = "SMS_2079451351"; + SmsCommonResult result = smsClient.getSmsTemplate(apiTemplateId); System.out.println(result); } From f4aba034cfd748fcdee6d4aebeeb4995f0cea8c9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 8 Apr 2021 01:21:04 +0800 Subject: [PATCH 38/54] =?UTF-8?q?1.=20=E4=BA=91=E7=89=87=20sms=20client=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9F=A5=E8=AF=A2=E6=A8=A1=E6=9D=BF=E7=9A=84?= =?UTF-8?q?=E5=B0=81=E8=A3=85=202.=20=E9=87=8D=E6=9E=84=E4=BA=91=E7=89=87?= =?UTF-8?q?=20sms=20client=20=E5=AE=A2=E6=88=B7=E7=AB=AF=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20invoke=20=E5=9F=BA=E7=A1=80=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/impl/aliyun/AliyunSmsClient.java | 4 +- .../client/impl/yunpian/YunpianSmsClient.java | 84 ++++++++++++------- .../YunpianSmsClientIntegrationTest.java | 22 ++++- 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java index b2c4c13ad..79829c0f9 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java @@ -124,7 +124,7 @@ public class AliyunSmsClient extends AbstractSmsClient { } } - private SmsCommonResult invoke(AcsRequest request, Function consumer) { + private SmsCommonResult invoke(AcsRequest request, Function responseConsumer) { try { // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射 T sendResult = acsClient.getAcsResponse(request); @@ -134,7 +134,7 @@ public class AliyunSmsClient extends AbstractSmsClient { // 解析结果 R data = null; if (Objects.equals(code, "OK")) { // 请求成功的情况下 - data = consumer.apply(sendResult); + data = responseConsumer.apply(sendResult); } // 拼接结果 return SmsCommonResult.build(code, message, requestId, data, codeMapping); diff --git a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java index f72db456b..a494658c7 100644 --- a/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java +++ b/src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java @@ -10,6 +10,7 @@ import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient; +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; import cn.iocoder.dashboard.util.json.JsonUtils; import com.fasterxml.jackson.annotation.JsonFormat; @@ -17,11 +18,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.model.Result; -import com.yunpian.sdk.model.SmsSingleSend; +import com.yunpian.sdk.model.Template; import lombok.Data; import lombok.extern.slf4j.Slf4j; import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -62,27 +65,15 @@ public class YunpianSmsClient extends AbstractSmsClient { @Override protected SmsCommonResult doSendSms(Long sendLogId, String mobile, String apiTemplateId, List> templateParams) throws Throwable { - // 构建参数 - Map request = new HashMap<>(); - request.put(YunpianConstant.APIKEY, properties.getApiKey()); - request.put(YunpianConstant.MOBILE, mobile); - request.put(YunpianConstant.TPL_ID, apiTemplateId); - request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); - request.put(YunpianConstant.UID, String.valueOf(sendLogId)); - request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); - - // 执行发送 - Result sendResult = client.sms().tpl_single_send(request); - if (sendResult.getThrowable() != null) { - throw sendResult.getThrowable(); - } - // 解析结果 - SmsSendRespDTO data = null; - if (sendResult.getData() != null) { - data = new SmsSendRespDTO().setSerialNo(String.valueOf(sendResult.getData().getSid())); - } - return SmsCommonResult.build(String.valueOf(sendResult.getCode()), formatResultMsg(sendResult), null, - data, codeMapping); + return invoke(() -> { + Map request = new HashMap<>(); + request.put(YunpianConstant.MOBILE, mobile); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams)); + request.put(YunpianConstant.UID, String.valueOf(sendLogId)); + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl()); + return client.sms().tpl_single_send(request); + }, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid()))); } private static String formatTplValue(List> templateParams) { @@ -95,13 +86,6 @@ public class YunpianSmsClient extends AbstractSmsClient { return joiner.toString(); } - private static String formatResultMsg(Result sendResult) { - if (StrUtil.isEmpty(sendResult.getDetail())) { - return sendResult.getMsg(); - } - return sendResult.getMsg() + " => " + sendResult.getDetail(); - } - @Override protected List doParseSmsReceiveStatus(String text) throws Throwable { List statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); @@ -117,7 +101,47 @@ public class YunpianSmsClient extends AbstractSmsClient { @Override protected SmsCommonResult doGetSmsTemplate(String apiTemplateId) throws Throwable { - return null; + return invoke(() -> { + Map request = new HashMap<>(); + request.put(YunpianConstant.APIKEY, properties.getApiKey()); + request.put(YunpianConstant.TPL_ID, apiTemplateId); + return client.tpl().get(request); + }, response -> { + Template template = response.get(0); + return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content()) + .setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason()); + }); + } + + private Integer convertSmsTemplateAuditStatus(String checkStatus) { + switch (checkStatus) { + case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus(); + case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus(); + case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus(); + default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus)); + } + } + + private SmsCommonResult invoke(Supplier> requestConsumer, Function responseConsumer) throws Throwable { + // 执行请求 + Result result = requestConsumer.get(); + if (result.getThrowable() != null) { + throw result.getThrowable(); + } + // 解析结果 + R data = null; + if (result.getData() != null) { + data = responseConsumer.apply(result.getData()); + } + // 拼接结果 + return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping); + } + + private static String formatResultMsg(Result sendResult) { + if (StrUtil.isEmpty(sendResult.getDetail())) { + return sendResult.getMsg(); + } + return sendResult.getMsg() + " => " + sendResult.getDetail(); } /** diff --git a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java index 039ed3bff..73f1a472d 100644 --- a/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java +++ b/src/test-integration/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClientIntegrationTest.java @@ -3,8 +3,10 @@ package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian; import cn.iocoder.dashboard.common.core.KeyValue; import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -15,8 +17,10 @@ import java.util.List; */ public class YunpianSmsClientIntegrationTest { - @Test - public void testSend() { + private static YunpianSmsClient smsClient; + + @BeforeAll + public static void init() { // 创建配置类 SmsChannelProperties properties = new SmsChannelProperties(); properties.setId(1L); @@ -24,9 +28,12 @@ public class YunpianSmsClientIntegrationTest { properties.setCode(SmsChannelEnum.YUN_PIAN.getCode()); properties.setApiKey("1555a14277cb8a608cf45a9e6a80d510"); // 创建客户端 - YunpianSmsClient smsClient = new YunpianSmsClient(properties); + smsClient = new YunpianSmsClient(properties); smsClient.init(); - // 发送短信 + } + + @Test + public void testSendSms() { List> templateParams = new ArrayList<>(); templateParams.add(new KeyValue<>("code", "1024")); templateParams.add(new KeyValue<>("operation", "嘿嘿")); @@ -35,4 +42,11 @@ public class YunpianSmsClientIntegrationTest { System.out.println(result); } + @Test + public void testGetSmsTemplate() { + String apiTemplateId = "4383920"; + SmsCommonResult result = smsClient.getSmsTemplate(apiTemplateId); + System.out.println(result); + } + } From fc3810e77c43e5acb58910641929b3fd9cc7cb73 Mon Sep 17 00:00:00 2001 From: hexiaowu Date: Fri, 9 Apr 2021 00:11:11 +0800 Subject: [PATCH 39/54] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=AF=B9=E8=B1=A1=E7=9A=84=E5=8E=BB=E9=87=8D=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20convertMap=20=E7=9A=84=E9=87=8D=E8=BD=BD?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/collection/CollectionUtils.java | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java b/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java index 186bf1201..ccd075a96 100644 --- a/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java +++ b/src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java @@ -4,8 +4,10 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import java.util.*; +import java.util.function.BinaryOperator; import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @@ -30,6 +32,20 @@ public class CollectionUtils { return from.stream().filter(predicate).collect(Collectors.toList()); } + public static List distinct(Collection from, Function keyMapper) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return distinct(from, keyMapper, (t1, t2) -> t1); + } + + public static List distinct(Collection from, Function keyMapper, BinaryOperator cover) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return new ArrayList<>(convertMap(from, keyMapper, Function.identity(), cover).values()); + } + public static List convertList(Collection from, Function func) { if (CollUtil.isEmpty(from)) { return new ArrayList<>(); @@ -48,30 +64,57 @@ public class CollectionUtils { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } - return from.stream().collect(Collectors.toMap(keyFunc, item -> item)); + return convertMap(from, keyFunc, Function.identity()); + } + + public static Map convertMap(Collection from, Function keyFunc, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return supplier.get(); + } + return convertMap(from, keyFunc, Function.identity(), supplier); } public static Map convertMap(Collection from, Function keyFunc, Function valueFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } - return from.stream().collect(Collectors.toMap(keyFunc, valueFunc)); + return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, BinaryOperator mergeFunction) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return convertMap(from, keyFunc, valueFunc, mergeFunction, HashMap::new); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return supplier.get(); + } + return convertMap(from, keyFunc, valueFunc, (v1, v2) -> v1, supplier); + } + + public static Map convertMap(Collection from, Function keyFunc, Function valueFunc, BinaryOperator mergeFunction, Supplier> supplier) { + if (CollUtil.isEmpty(from)) { + return new HashMap<>(); + } + return from.stream().collect(Collectors.toMap(keyFunc, valueFunc, mergeFunction, supplier)); } public static Map> convertMultiMap(Collection from, Function keyFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } - return from.stream().collect(Collectors.groupingBy(keyFunc, - Collectors.mapping(t -> t, Collectors.toList()))); + return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(t -> t, Collectors.toList()))); } public static Map> convertMultiMap(Collection from, Function keyFunc, Function valueFunc) { if (CollUtil.isEmpty(from)) { return new HashMap<>(); } - return from.stream().collect(Collectors.groupingBy(keyFunc, - Collectors.mapping(valueFunc, Collectors.toList()))); + return from.stream() + .collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toList()))); } // 暂时没想好名字,先以 2 结尾噶 From 9f794ecb1593c025193bb665bcfaf333a7524aaf Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 9 Apr 2021 00:40:42 +0800 Subject: [PATCH 40/54] =?UTF-8?q?1.=20=E5=88=9B=E5=BB=BA=E5=92=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=9F=AD=E4=BF=A1=E6=A8=A1=E6=9D=BF=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=20API=20=E7=9F=AD=E4=BF=A1=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/sms/impl/SysSmsServiceImpl.java | 3 +- .../sms/impl/SysSmsTemplateServiceImpl.java | 30 +++++++++++++++++++ .../sms/SysSmsTemplateServiceTest.java | 27 +++++++++++++++-- .../iocoder/dashboard/util/RandomUtils.java | 11 +++++++ 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java index c5a12797f..1ccb090cd 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsServiceImpl.java @@ -77,8 +77,7 @@ public class SysSmsServiceImpl implements SysSmsService { @Override public void sendBatchSms(List mobiles, List userIds, Integer userType, String templateCode, Map templateParams) { - // 校验短信模板是否存在 - SysSmsTemplateDO template = this.checkSmsTemplateValid(templateCode); + throw new IllegalArgumentException("暂时不支持该操作,感兴趣可以实现该功能哟!"); } private SysSmsTemplateDO checkSmsTemplateValid(String templateCode) { diff --git a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java index f3e50547d..fc1c0dc5f 100644 --- a/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java +++ b/src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java @@ -4,6 +4,10 @@ import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; import cn.iocoder.dashboard.common.pojo.PageResult; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; @@ -16,6 +20,8 @@ import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService; import com.google.common.annotations.VisibleForTesting; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.util.Collection; @@ -34,6 +40,7 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*; * @date 2021/1/25 9:25 */ @Service +@Validated public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { /** @@ -47,6 +54,9 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { @Resource private SysSmsChannelService smsChannelService; + @Resource + private SmsClientFactory smsClientFactory; + @Override public SysSmsTemplateDO getSmsTemplateByCode(String code) { return smsTemplateMapper.selectByCode(code); @@ -68,6 +78,8 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { SysSmsChannelDO channelDO = checkSmsChannel(createReqVO.getChannelId()); // 校验短信编码是否重复 checkSmsTemplateCodeDuplicate(null, createReqVO.getCode()); + // 校验短信模板 + checkApiTemplate(createReqVO.getChannelId(), createReqVO.getApiTemplateId()); // 插入 SysSmsTemplateDO template = SysSmsTemplateConvert.INSTANCE.convert(createReqVO); @@ -86,6 +98,8 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { SysSmsChannelDO channelDO = checkSmsChannel(updateReqVO.getChannelId()); // 校验短信编码是否重复 checkSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode()); + // 校验短信模板 + checkApiTemplate(updateReqVO.getChannelId(), updateReqVO.getApiTemplateId()); // 更新 SysSmsTemplateDO updateObj = SysSmsTemplateConvert.INSTANCE.convert(updateReqVO); @@ -155,4 +169,20 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService { } } + /** + * 校验 API 短信平台的模板是否有效 + * + * @param channelId 渠道编号 + * @param apiTemplateId API 模板编号 + */ + @VisibleForTesting + public void checkApiTemplate(Long channelId, String apiTemplateId) { + // 获得短信模板 + SmsClient smsClient = smsClientFactory.getSmsClient(channelId); + Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId)); + SmsCommonResult templateResult = smsClient.getSmsTemplate(apiTemplateId); + // 校验短信模板是否正确 + templateResult.checkError(); + } + } diff --git a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java index 7e79d3aa7..51db4bed0 100644 --- a/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java +++ b/src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java @@ -2,8 +2,16 @@ package cn.iocoder.dashboard.modules.system.service.sms; import cn.iocoder.dashboard.BaseDbUnitTest; import cn.iocoder.dashboard.common.enums.CommonStatusEnum; +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.dashboard.common.pojo.PageResult; -import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.*; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient; +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory; +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult; +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO; +import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper; @@ -47,6 +55,11 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { @MockBean private SysSmsChannelService smsChannelService; + @MockBean + private SmsClientFactory smsClientFactory; + @MockBean + private SmsClient smsClient; + @Test public void testParseTemplateContentParams() { // 准备参数 @@ -60,6 +73,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { } @Test + @SuppressWarnings("unchecked") public void testCreateSmsTemplate_success() { // 准备参数 SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class, o -> { @@ -67,12 +81,16 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微 }); - // mock 方法 + // mock Channel 的方法 SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> { o.setId(reqVO.getChannelId()); o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 }); when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); + // mock 获得 API 短信模板成功 + when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class, + o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); // 调用 Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO); @@ -86,6 +104,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { } @Test + @SuppressWarnings("unchecked") public void testUpdateSmsTemplate_success() { // mock 数据 SysSmsTemplateDO dbSmsTemplate = randomSmsTemplateDO(); @@ -103,6 +122,10 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest { o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态 }); when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO); + // mock 获得 API 短信模板成功 + when(smsClientFactory.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient); + when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class, + o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode()))); // 调用 smsTemplateService.updateSmsTemplate(reqVO); diff --git a/src/test/java/cn/iocoder/dashboard/util/RandomUtils.java b/src/test/java/cn/iocoder/dashboard/util/RandomUtils.java index c668f980c..1979e091f 100644 --- a/src/test/java/cn/iocoder/dashboard/util/RandomUtils.java +++ b/src/test/java/cn/iocoder/dashboard/util/RandomUtils.java @@ -7,6 +7,7 @@ import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import uk.co.jemos.podam.api.PodamFactory; import uk.co.jemos.podam.api.PodamFactoryImpl; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.Date; import java.util.Set; @@ -87,4 +88,14 @@ public class RandomUtils { return pojo; } + @SafeVarargs + public static T randomPojo(Class clazz, Type type, Consumer... consumers) { + T pojo = PODAM_FACTORY.manufacturePojo(clazz, type); + // 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理 + if (ArrayUtil.isNotEmpty(consumers)) { + Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); + } + return pojo; + } + } From 73a2f4d84ce3b3538f400131ac2ec86275f215b0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 10 Apr 2021 01:39:27 +0800 Subject: [PATCH 41/54] =?UTF-8?q?1.=20=E7=BC=96=E5=86=99=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E7=9A=84=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/.env.demo1024 | 7 ++ ruoyi-ui/package.json | 1 + ruoyi-ui/src/api/system/sms/smsChannel.js | 8 ++ ruoyi-ui/src/views/system/sms/smsChannel.vue | 5 +- ruoyi-ui/src/views/system/sms/smsTemplate.vue | 81 ++++++++++++------- .../dashboard/common/pojo/CommonResult.java | 2 +- .../enums/SmsFrameworkErrorCodeConstants.java | 20 ++--- .../dict/SysDictDataController.java | 2 +- ...leVO.java => SysDictDataSimpleRespVO.java} | 4 +- .../sms/SysSmsChannelController.java | 16 +++- .../sms/SysSmsTemplateController.http | 12 +++ .../sms/SysSmsTemplateController.java | 7 ++ .../vo/channel/SysSmsChannelSimpleRespVO.java | 24 ++++++ .../vo/template/SysSmsTemplateSendReqVO.java | 21 +++++ .../convert/dict/SysDictDataConvert.java | 2 +- .../convert/sms/SysSmsChannelConvert.java | 3 + .../system/enums/SysErrorCodeConstants.java | 4 +- .../service/sms/SysSmsChannelService.java | 7 ++ .../sms/impl/SysSmsChannelServiceImpl.java | 5 ++ .../sms/impl/SysSmsTemplateServiceImpl.java | 4 +- .../resources/codegen/vue/views/index.vue.vm | 4 +- 21 files changed, 181 insertions(+), 58 deletions(-) create mode 100644 ruoyi-ui/.env.demo1024 rename src/main/java/cn/iocoder/dashboard/modules/system/controller/dict/vo/data/{SysDictDataSimpleVO.java => SysDictDataSimpleRespVO.java} (86%) create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SysSmsTemplateController.http create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/channel/SysSmsChannelSimpleRespVO.java create mode 100644 src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/template/SysSmsTemplateSendReqVO.java diff --git a/ruoyi-ui/.env.demo1024 b/ruoyi-ui/.env.demo1024 new file mode 100644 index 000000000..ffeadbf8c --- /dev/null +++ b/ruoyi-ui/.env.demo1024 @@ -0,0 +1,7 @@ +NODE_ENV = production + +# 测试环境配置 +ENV = 'staging' + +# 芋道管理系统/测试环境 +VUE_APP_BASE_API = 'http://127.0.0.1:48080' diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index 46718e1b0..1249d16b3 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -8,6 +8,7 @@ "dev": "vue-cli-service serve", "build:prod": "vue-cli-service build", "build:stage": "vue-cli-service build --mode staging", + "build:demo1024": "vue-cli-service build --mode demo1024", "preview": "node build/index.js --preview", "lint": "eslint --ext .js,.vue src" }, diff --git a/ruoyi-ui/src/api/system/sms/smsChannel.js b/ruoyi-ui/src/api/system/sms/smsChannel.js index 0b4b8c338..4e38de05f 100644 --- a/ruoyi-ui/src/api/system/sms/smsChannel.js +++ b/ruoyi-ui/src/api/system/sms/smsChannel.js @@ -42,3 +42,11 @@ export function getSmsChannelPage(query) { params: query }) } + +// 获得短信渠道精简列表 +export function getSimpleSmsChannels() { + return request({ + url: '/system/sms-channel/list-all-simple', + method: 'get', + }) +} diff --git a/ruoyi-ui/src/views/system/sms/smsChannel.vue b/ruoyi-ui/src/views/system/sms/smsChannel.vue index 5b19f6a8d..ae4b9d7f2 100644 --- a/ruoyi-ui/src/views/system/sms/smsChannel.vue +++ b/ruoyi-ui/src/views/system/sms/smsChannel.vue @@ -108,7 +108,8 @@ From 3dc36ecced0cea0d9e96941634ec5bf8d3e28aea Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 11 Apr 2021 21:48:51 +0800 Subject: [PATCH 46/54] =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E5=8F=91=E9=80=81?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=9A=84=E5=89=8D=E7=AB=AF=EF=BC=8C=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/utils/dict.js | 2 + .../src/views/system/operatelog/index.vue | 1 - ruoyi-ui/src/views/system/sms/smsLog.vue | 157 +++++++++++++----- ruoyi-ui/src/views/system/sms/smsTemplate.vue | 8 +- .../framework/sms/core/client/SmsClient.java | 5 +- .../dict/SysDictTypeController.java | 2 +- .../system/enums/dict/SysDictTypeEnum.java | 2 + .../resources/codegen/vue/views/index.vue.vm | 2 +- 8 files changed, 130 insertions(+), 49 deletions(-) diff --git a/ruoyi-ui/src/utils/dict.js b/ruoyi-ui/src/utils/dict.js index 1a61a989a..e3dc92d5b 100644 --- a/ruoyi-ui/src/utils/dict.js +++ b/ruoyi-ui/src/utils/dict.js @@ -19,6 +19,8 @@ export const DICT_TYPE = { SYS_CONFIG_TYPE: 'sys_config_type', SYS_SMS_CHANNEL_CODE: 'sys_sms_channel_code', SYS_SMS_TEMPLATE_TYPE: 'sys_sms_template_type', + SYS_SMS_SEND_STATUS: 'sys_sms_send_status', + SYS_SMS_RECEIVE_STATUS: 'sys_sms_receive_status', INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', INF_JOB_STATUS: 'inf_job_status', diff --git a/ruoyi-ui/src/views/system/operatelog/index.vue b/ruoyi-ui/src/views/system/operatelog/index.vue index 8833a749e..7131654bf 100644 --- a/ruoyi-ui/src/views/system/operatelog/index.vue +++ b/ruoyi-ui/src/views/system/operatelog/index.vue @@ -163,7 +163,6 @@ export default { businessType: undefined, status: undefined }, - }; }, created() { diff --git a/ruoyi-ui/src/views/system/sms/smsLog.vue b/ruoyi-ui/src/views/system/sms/smsLog.vue index 8b3c2db53..8ec2d9488 100644 --- a/ruoyi-ui/src/views/system/sms/smsLog.vue +++ b/ruoyi-ui/src/views/system/sms/smsLog.vue @@ -2,16 +2,20 @@

- - - + + + + + + + + - - - @@ -52,46 +56,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -99,13 +108,59 @@ - + + + + + + {{ form.id }} + + + {{ form.traceId }} + + + {{ form.userId }} | {{ form.userNickname }} | {{ form.userIp }} | {{ form.userAgent}} + + + + {{ form.module }} | {{ form.name }} | {{ getDictDataLabel(DICT_TYPE.SYS_OPERATE_TYPE, form.type) }} +
{{ form.content }} +
{{ form.exts }} +
+
+ + {{ form.requestMethod }} | {{ form.requestUrl }} + + + {{ form.javaMethod }} + + + {{ form.javaMethodArgs }} + + + + {{ parseTime(form.startTime) }} | {{ form.duration }} ms + + + + +
正常 | {{ form.resultData}}
+
失败 | {{ form.resultCode }} || {{ form.resultMsg}}
+
+
+
+
+ +