Commit df8bda53e867f5c4d5b8b55157ca5b8163d661a6

Authored by zefeng_java
1 parent 842496a5

增加短信功能实现

Showing 42 changed files with 1660 additions and 72 deletions
@@ -222,6 +222,18 @@ @@ -222,6 +222,18 @@
222 <version>${easyexcel.verion}</version> 222 <version>${easyexcel.verion}</version>
223 </dependency> 223 </dependency>
224 224
  225 + <dependency>
  226 + <groupId>com.aliyun</groupId>
  227 + <artifactId>aliyun-java-sdk-core</artifactId>
  228 + <version>4.5.18</version>
  229 + </dependency>
  230 +
  231 + <dependency>
  232 + <groupId>com.aliyun</groupId>
  233 + <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  234 + <version>2.1.0</version>
  235 + </dependency>
  236 +
225 </dependencies> 237 </dependencies>
226 238
227 239
sql/ruoyi-vue-pro.sql
@@ -884,4 +884,77 @@ INSERT INTO `sys_user_role` VALUES (5, 100, 1, &#39;&#39;, NULL, &#39;&#39;, NULL, b&#39;0&#39;); @@ -884,4 +884,77 @@ INSERT INTO `sys_user_role` VALUES (5, 100, 1, &#39;&#39;, NULL, &#39;&#39;, NULL, b&#39;0&#39;);
884 INSERT INTO `sys_user_role` VALUES (6, 100, 2, '', NULL, '', NULL, b'0'); 884 INSERT INTO `sys_user_role` VALUES (6, 100, 2, '', NULL, '', NULL, b'0');
885 COMMIT; 885 COMMIT;
886 886
  887 +
  888 +-- ----------------------------
  889 +-- Table structure for sms_channel
  890 +-- ----------------------------
  891 +DROP TABLE IF EXISTS `sms_channel`;
  892 +CREATE TABLE `sms_channel` (
  893 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
  894 + `code` varchar(50) not null COMMENT '编码(来自枚举类 阿里、华为、七牛等)',
  895 + `api_key` varchar(100) NOT NULL COMMENT '账号id', -- add
  896 + `api_secret` varchar(100) NOT NULL COMMENT '账号秘钥', -- add
  897 + `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)', -- add
  898 + `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识',
  899 + `name` varchar(50) not null COMMENT '名称',
  900 + `signature` varchar(50) not null COMMENT '签名值',
  901 + `remark` varchar(200) NOT NULL COMMENT '备注',
  902 +
  903 + `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)',
  904 + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者',
  905 + `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  906 + `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  907 + `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  908 + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除',
  909 + PRIMARY KEY (`id`) USING BTREE
  910 +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠道';
  911 +/*
  912 + 优先级值一样时,按照id顺序取值
  913 +*/
  914 +
  915 +-- ----------------------------
  916 +-- Table structure for sms_template
  917 +-- ----------------------------
  918 +DROP TABLE IF EXISTS `sms_template`;
  919 +CREATE TABLE `sms_template` (
  920 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
  921 + `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)',
  922 + `channel_id` bigint(20) not null COMMENT '短信渠道id (对于前端来说就是绑定一个签名)', -- add
  923 + `type` tinyint(4) NOT NULL default 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]',
  924 + `biz_code` varchar(50) not null COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)', -- add
  925 + `priority` tinyint(8) NOT NULL default 1 COMMENT '优先级(默认直接继承渠道表的,逻辑也与渠道表的一致,可以针对每个biz_code进行修改)',-- add
  926 + `code` varchar(50) not null COMMENT '编码',
  927 + `name` varchar(50) not null COMMENT '名称',
  928 + `api_template_id` varchar(100) NOT NULL COMMENT '实际渠道模板唯一标识',
  929 + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容',
  930 + `params` varchar(200) NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)', -- add
  931 + `remark` varchar(200) NOT NULL COMMENT '备注',
  932 +
  933 + `status` tinyint(4) NOT NULL default 0 COMMENT '启用状态(0正常 1停用)',
  934 + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者',
  935 + `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  936 + `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  937 + `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  938 + `deleted` bit(1) DEFAULT b'0' COMMENT '是否删除',
  939 + PRIMARY KEY (`id`) USING BTREE
  940 +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信模板';
  941 +
  942 +-- ----------------------------
  943 +-- Table structure for sms_log
  944 +-- ----------------------------
  945 +DROP TABLE IF EXISTS `sms_log`;
  946 +CREATE TABLE `sms_log` (
  947 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增编号',
  948 + `channel_code` varchar(50) not null COMMENT '短信渠道编码(来自枚举类)',
  949 + `api_sms_id` varchar(50) not null COMMENT '实际渠道短信唯一标识',
  950 + `template_id` bigint(20) NOT NULL COMMENT '模板id',
  951 + `phone` char(11) not null COMMENT '手机号',
  952 + `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '内容',
  953 + `remark` varchar(200) NOT NULL COMMENT '备注',
  954 + `send_status` tinyint(4) NOT NULL default 0 COMMENT '发送状态(0发送中 1成功 2失败)',
  955 + `create_by` varchar(64) not null DEFAULT '' COMMENT '创建者',
  956 + `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  957 + PRIMARY KEY (`id`) USING BTREE
  958 +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='短信日志';
  959 +
887 SET FOREIGN_KEY_CHECKS = 1; 960 SET FOREIGN_KEY_CHECKS = 1;
src/main/java/cn/iocoder/dashboard/DashboardApplication.java
1 -package cn.iocoder.dashboard;  
2 -  
3 -import de.codecentric.boot.admin.server.config.EnableAdminServer;  
4 -import org.springframework.boot.SpringApplication;  
5 -import org.springframework.boot.autoconfigure.SpringBootApplication;  
6 -  
7 -@SpringBootApplication  
8 -@EnableAdminServer  
9 -public class DashboardApplication {  
10 -  
11 - public static void main(String[] args) {  
12 - SpringApplication.run(DashboardApplication.class, args);  
13 - }  
14 -  
15 -} 1 +//package cn.iocoder.dashboard;
  2 +//
  3 +//import de.codecentric.boot.admin.server.config.EnableAdminServer;
  4 +//import org.springframework.boot.SpringApplication;
  5 +//import org.springframework.boot.autoconfigure.SpringBootApplication;
  6 +//
  7 +//@SpringBootApplication
  8 +//@EnableAdminServer
  9 +//public class DashboardApplication {
  10 +//
  11 +// public static void main(String[] args) {
  12 +// SpringApplication.run(DashboardApplication.class, args);
  13 +// }
  14 +//
  15 +//}
src/main/java/cn/iocoder/dashboard/common/enums/SmsChannelEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信渠道枚举
  8 + *
  9 + * @author zzf
  10 + * @date 2021/1/25 10:56
  11 + */
  12 +@Getter
  13 +@AllArgsConstructor
  14 +public enum SmsChannelEnum {
  15 +
  16 + ALI("ALI", "阿里"),
  17 + HUA_WEI("HUA_WEI", "华为"),
  18 + QI_NIU("QI_NIU", "七牛"),
  19 + TEN_XUN("TEN_XUN", "腾讯");
  20 +
  21 + private final String code;
  22 +
  23 + private final String name;
  24 +
  25 + public static SmsChannelEnum getByCode(String code) {
  26 + for (SmsChannelEnum value : SmsChannelEnum.values()) {
  27 + if (value.getCode().equals(code)) {
  28 + return value;
  29 + }
  30 + }
  31 + return null;
  32 + }
  33 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms;
  2 +
  3 +import cn.iocoder.dashboard.util.json.JsonUtils;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * 消息内容实体类
  10 + */
  11 +@Data
  12 +public class SmsBody {
  13 +
  14 + /**
  15 + * 模板编码
  16 + */
  17 + private String code;
  18 +
  19 + /**
  20 + * 参数列表
  21 + */
  22 + private Map<String, String> params;
  23 +
  24 + public String getParamsStr() {
  25 + return JsonUtils.toJsonString(params);
  26 + }
  27 +
  28 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.io.Serializable;
  6 +
  7 +/**
  8 + * 消息内容实体类
  9 + */
  10 +@Data
  11 +public class SmsResult<T> implements Serializable {
  12 +
  13 + /**
  14 + * 是否成功
  15 + */
  16 + private Boolean success;
  17 +
  18 + /**
  19 + * 提示
  20 + */
  21 + private String message;
  22 +
  23 + /**
  24 + * 返回值
  25 + */
  26 + private T result;
  27 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms;
  2 +
  3 +import org.apache.commons.lang3.StringUtils;
  4 +
  5 +import java.util.Arrays;
  6 +import java.util.Collection;
  7 +import java.util.Collections;
  8 +
  9 +/**
  10 + * 短信父接口
  11 + *
  12 + * @author zzf
  13 + * @date 2021/1/25 14:14
  14 + */
  15 +public interface SmsSender<R> {
  16 +
  17 + /**
  18 + * 发送通知
  19 + *
  20 + * @param msgBody 通知内容
  21 + * @param targets 发送对象列表
  22 + * @return 是否发送成功
  23 + */
  24 + SmsResult<R> send(SmsBody msgBody, Collection<String> targets);
  25 +
  26 + /**
  27 + * 发送通知
  28 + *
  29 + * @param msgBody 通知内容
  30 + * @param target 发送对象列表
  31 + * @return 是否发送成功
  32 + */
  33 + default SmsResult<R> send(SmsBody msgBody, String target) {
  34 + if (StringUtils.isBlank(target)) {
  35 + return failResult();
  36 + }
  37 +
  38 + return send(msgBody, Collections.singletonList(target));
  39 + }
  40 +
  41 + /**
  42 + * 发送通知
  43 + *
  44 + * @param msgBody 通知内容
  45 + * @param targets 发送对象列表
  46 + * @return 是否发送成功
  47 + */
  48 + default SmsResult<R> send(SmsBody msgBody, String... targets) {
  49 + if (targets == null) {
  50 + return failResult();
  51 + }
  52 +
  53 + return send(msgBody, Arrays.asList(targets));
  54 + }
  55 +
  56 + default SmsResult<R> failResult() {
  57 + SmsResult<R> resultBody = new SmsResult<>();
  58 + resultBody.setSuccess(false);
  59 + return resultBody;
  60 + }
  61 +
  62 + default SmsResult<R> failResult(String message) {
  63 + SmsResult<R> resultBody = failResult();
  64 + resultBody.setMessage(message);
  65 + return resultBody;
  66 + }
  67 +}
0 \ No newline at end of file 68 \ No newline at end of file
src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.config;
  2 +
  3 +import cn.iocoder.dashboard.framework.msg.sms.factory.DefaultSmsSenderFactory;
  4 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain;
  5 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.DefaultSmsIntercepterChain;
  6 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsLogIntercepter;
  7 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  8 +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService;
  9 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  10 +import org.springframework.context.annotation.Bean;
  11 +import org.springframework.context.annotation.Configuration;
  12 +
  13 +import javax.annotation.Resource;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * 短信服务配置
  18 + *
  19 + * @author guer
  20 + */
  21 +@Configuration
  22 +@ConditionalOnProperty("sms.enabled")
  23 +public class SmsConfiguration {
  24 +
  25 + @Resource
  26 + private SmsChannelService channelService;
  27 +
  28 +
  29 + @Bean
  30 + public AbstractSmsIntercepterChain smsIntercepterChain() {
  31 + DefaultSmsIntercepterChain intercepterChain = new DefaultSmsIntercepterChain();
  32 + //添加拦截器
  33 + intercepterChain.addSmsIntercepter(new SmsLogIntercepter());
  34 + return intercepterChain;
  35 + }
  36 +
  37 + @Bean
  38 + public DefaultSmsSenderFactory smsSenderFactory(AbstractSmsIntercepterChain intercepterChain) {
  39 + DefaultSmsSenderFactory defaultSmsSenderFactory = new DefaultSmsSenderFactory();
  40 + List<SmsChannelAllVO> smsChannelAllVOList = channelService.listChannelAllEnabledInfo();
  41 + //初始化渠道、模板信息
  42 + defaultSmsSenderFactory.init(smsChannelAllVOList);
  43 + //注入拦截器链
  44 + defaultSmsSenderFactory.setIntercepterChain(intercepterChain);
  45 + return defaultSmsSenderFactory;
  46 + }
  47 +
  48 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.factory;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
  5 +import cn.iocoder.dashboard.common.exception.ServiceException;
  6 +import cn.iocoder.dashboard.framework.msg.sms.SmsSender;
  7 +import cn.iocoder.dashboard.framework.msg.sms.impl.ali.AliSmsSender;
  8 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain;
  9 +import cn.iocoder.dashboard.framework.msg.sms.proxy.DefaultSmsSenderProxy;
  10 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  11 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO;
  12 +import lombok.Setter;
  13 +
  14 +import java.util.List;
  15 +import java.util.concurrent.ConcurrentHashMap;
  16 +import java.util.concurrent.locks.Lock;
  17 +import java.util.concurrent.locks.ReadWriteLock;
  18 +import java.util.concurrent.locks.ReentrantReadWriteLock;
  19 +
  20 +import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
  21 +
  22 +/**
  23 + * 短信发送者工厂
  24 + *
  25 + * @author zzf
  26 + * @date 2021/1/25 16:18
  27 + */
  28 +public class DefaultSmsSenderFactory {
  29 +
  30 + /**
  31 + * sender索引
  32 + * key: {@link SmsTemplateVO#getBizCode()}
  33 + * value: {@link SmsSender}
  34 + */
  35 + private final ConcurrentHashMap<String, SmsSender<?>> bizCode2SenderMap = new ConcurrentHashMap<>(8);
  36 +
  37 + /**
  38 + * sender索引
  39 + * key: {@link SmsTemplateVO#getCode()}
  40 + * value: {@link SmsSender}
  41 + */
  42 + private final ConcurrentHashMap<String, SmsSender<?>> templateCode2SenderMap = new ConcurrentHashMap<>(8);
  43 +
  44 +
  45 + @Setter
  46 + private AbstractSmsIntercepterChain intercepterChain;
  47 +
  48 + /**
  49 + * 读写锁
  50 + */
  51 + private final ReadWriteLock lock = new ReentrantReadWriteLock();
  52 + private final Lock readLock = lock.readLock();
  53 + private final Lock writeLock = lock.writeLock();
  54 +
  55 +
  56 + public void init(List<SmsChannelAllVO> smsChannelAllVOList) {
  57 + if (ObjectUtil.isEmpty(smsChannelAllVOList)) {
  58 + throw new ServiceException(SMS_CHANNEL_NOT_FOUND);
  59 + }
  60 + try {
  61 + writeLock.lock();
  62 + addSender(smsChannelAllVOList);
  63 + } finally {
  64 + writeLock.unlock();
  65 + }
  66 + }
  67 +
  68 + public SmsSender<?> getSenderByBizCode(String bizCode) {
  69 + return getSmsSender(bizCode, bizCode2SenderMap);
  70 + }
  71 +
  72 + public SmsSender<?> getSenderByTemplateCode(String templateCode) {
  73 + return getSmsSender(templateCode, templateCode2SenderMap);
  74 + }
  75 +
  76 + private SmsSender<?> getSmsSender(String templateCode, ConcurrentHashMap<String, SmsSender<?>> cacheMap) {
  77 + try {
  78 + readLock.lock();
  79 + SmsSender<?> smsSender = cacheMap.get(templateCode);
  80 + if (smsSender == null) {
  81 + throw new ServiceException(SMS_SENDER_NOT_FOUND);
  82 + }
  83 + return smsSender;
  84 + } finally {
  85 + readLock.unlock();
  86 + }
  87 + }
  88 +
  89 + public void flush(List<SmsChannelAllVO> smsChannelAllVOList) {
  90 + try {
  91 + writeLock.lock();
  92 + bizCode2SenderMap.clear();
  93 + templateCode2SenderMap.clear();
  94 + addSender(smsChannelAllVOList);
  95 + } finally {
  96 + writeLock.unlock();
  97 + }
  98 + }
  99 +
  100 +
  101 + private void addSender(List<SmsChannelAllVO> smsChannelAllVOList) {
  102 + smsChannelAllVOList.forEach(channelAllVO -> addSender(SmsChannelEnum.getByCode(channelAllVO.getCode()), channelAllVO));
  103 + }
  104 +
  105 + private void addSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) {
  106 + if (channelEnum == null) {
  107 + throw new ServiceException(INVALID_CHANNEL_CODE);
  108 + }
  109 + List<SmsTemplateVO> templateList = channelAllVO.getTemplateList();
  110 + if (ObjectUtil.isEmpty(templateList)) {
  111 + throw new ServiceException(SMS_TEMPLATE_NOT_FOUND);
  112 + }
  113 +
  114 + SmsSender<?> aliSmsSender = getSender(channelEnum, channelAllVO);
  115 +
  116 +
  117 + templateList.forEach(smsTemplateVO -> {
  118 + bizCode2SenderMap.put(smsTemplateVO.getBizCode(), aliSmsSender);
  119 + templateCode2SenderMap.put(smsTemplateVO.getCode(), aliSmsSender);
  120 + });
  121 + }
  122 +
  123 + private SmsSender<?> getSender(SmsChannelEnum channelEnum, SmsChannelAllVO channelAllVO) {
  124 + switch (channelEnum) {
  125 + case ALI:
  126 + return new DefaultSmsSenderProxy<>(new AliSmsSender(channelAllVO), intercepterChain);
  127 + // TODO fill more channel
  128 + default:
  129 + break;
  130 + }
  131 + throw new ServiceException(SMS_SENDER_NOT_FOUND);
  132 + }
  133 +
  134 +
  135 +
  136 +
  137 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.impl.ali;
  2 +
  3 +import cn.iocoder.dashboard.framework.msg.sms.SmsBody;
  4 +import cn.iocoder.dashboard.framework.msg.sms.SmsResult;
  5 +import cn.iocoder.dashboard.framework.msg.sms.SmsSender;
  6 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  7 +import com.aliyuncs.DefaultAcsClient;
  8 +import com.aliyuncs.IAcsClient;
  9 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
  10 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
  11 +import com.aliyuncs.http.MethodType;
  12 +import com.aliyuncs.profile.DefaultProfile;
  13 +import com.aliyuncs.profile.IClientProfile;
  14 +import lombok.extern.slf4j.Slf4j;
  15 +import org.apache.commons.lang3.StringUtils;
  16 +
  17 +import java.util.Collection;
  18 +
  19 +/**
  20 + * 阿里短信实现类
  21 + *
  22 + * @author zzf
  23 + * @date 2021/1/25 14:17
  24 + */
  25 +@Slf4j
  26 +public class AliSmsSender implements SmsSender<SendSmsResponse> {
  27 +
  28 + private static final String OK = "OK";
  29 +
  30 + private static final String PRODUCT = "Dysmsapi";
  31 +
  32 + private static final String DOMAIN = "dysmsapi.aliyuncs.com";
  33 +
  34 + private static final String ENDPOINT = "cn-hangzhou";
  35 +
  36 + private final SmsChannelAllVO channelVO;
  37 +
  38 + private final IAcsClient acsClient;
  39 +
  40 + /**
  41 + * 构造阿里云短信发送处理
  42 + *
  43 + * @param channelVO 阿里云短信配置
  44 + */
  45 + public AliSmsSender(SmsChannelAllVO channelVO) {
  46 +
  47 + this.channelVO = channelVO;
  48 +
  49 + String accessKeyId = channelVO.getApiKey();
  50 + String accessKeySecret = channelVO.getApiSecret();
  51 +
  52 + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret);
  53 + DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN);
  54 +
  55 + acsClient = new DefaultAcsClient(profile);
  56 + }
  57 +
  58 +
  59 + @Override
  60 + public SmsResult<SendSmsResponse> send(SmsBody msgBody, Collection<String> targets) {
  61 + SendSmsRequest request = new SendSmsRequest();
  62 + request.setSysMethod(MethodType.POST);
  63 + request.setPhoneNumbers(StringUtils.join(targets, ","));
  64 + request.setSignName(channelVO.getApiSignatureId());
  65 + request.setTemplateCode(channelVO.getTemplateByTemplateCode(msgBody.getCode()).getApiTemplateId());
  66 + request.setTemplateParam(msgBody.getParamsStr());
  67 +
  68 + try {
  69 + SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
  70 +
  71 + boolean result = OK.equals(sendSmsResponse.getCode());
  72 + if (!result) {
  73 + log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
  74 + }
  75 + SmsResult<SendSmsResponse> resultBody = new SmsResult<>();
  76 + resultBody.setSuccess(result);
  77 + resultBody.setResult(sendSmsResponse);
  78 + return resultBody;
  79 + } catch (Exception e) {
  80 + log.debug(e.getMessage(), e);
  81 + }
  82 +
  83 + return failResult();
  84 + }
  85 +
  86 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.intercepter;
  2 +
  3 +import lombok.Getter;
  4 +
  5 +import java.util.ArrayList;
  6 +import java.util.Collections;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * 消息父接口
  11 + *
  12 + * @author zzf
  13 + * @date 2021/1/22 15:46
  14 + */
  15 +public abstract class AbstractSmsIntercepterChain {
  16 +
  17 + @Getter
  18 + protected final List<SmsIntercepter> intercepterList = new ArrayList<>(8);
  19 +
  20 +
  21 + /**
  22 + * 添加短信拦截器
  23 + *
  24 + * @param smsIntercepter 短信拦截器
  25 + */
  26 + public void addSmsIntercepter(SmsIntercepter smsIntercepter) {
  27 + addSmsIntercepter(Collections.singletonList(smsIntercepter));
  28 + }
  29 +
  30 + /**
  31 + * 添加短信拦截器
  32 + *
  33 + * @param smsIntercepterList 短信拦截器数组
  34 + */
  35 + abstract void addSmsIntercepter(List<SmsIntercepter> smsIntercepterList);
  36 +
  37 +
  38 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.intercepter;
  2 +
  3 +import java.util.Comparator;
  4 +import java.util.List;
  5 +
  6 +/**
  7 + * 消息父接口
  8 + *
  9 + * @author zzf
  10 + * @date 2021/1/22 15:46
  11 + */
  12 +public class DefaultSmsIntercepterChain extends AbstractSmsIntercepterChain {
  13 +
  14 + @Override
  15 + public void addSmsIntercepter(List<SmsIntercepter> smsIntercepterList) {
  16 + intercepterList.addAll(smsIntercepterList);
  17 + //排序
  18 + intercepterList.sort(Comparator.comparingInt(SmsIntercepter::getOrder));
  19 + }
  20 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.intercepter;
  2 +
  3 +import cn.iocoder.dashboard.framework.msg.sms.SmsBody;
  4 +import cn.iocoder.dashboard.framework.msg.sms.SmsResult;
  5 +
  6 +import java.util.Collection;
  7 +
  8 +/**
  9 + * 消息父接口
  10 + *
  11 + * @author zzf
  12 + * @date 2021/1/22 15:46
  13 + */
  14 +public interface SmsIntercepter {
  15 +
  16 + /**
  17 + * 监听发送前
  18 + *
  19 + * @param msgBody 消息体
  20 + * @param targets 发送对象数组
  21 + */
  22 + void beforeSender(SmsBody msgBody, Collection<String> targets);
  23 +
  24 + /**
  25 + * 监听发送后
  26 + *
  27 + * @param msgBody 消息体
  28 + * @param targets 发送对象数组
  29 + * @param resultBody 返回对象
  30 + */
  31 + <T> void afterSender(SmsBody msgBody, Collection<String> targets, SmsResult<T> resultBody);
  32 +
  33 + /**
  34 + * 排序值,拦截器根据order值顺序执行
  35 + * <p>
  36 + * 值越小,越早执行
  37 + *
  38 + * @return 排序值
  39 + */
  40 + int getOrder();
  41 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.intercepter;
  2 +
  3 +import cn.iocoder.dashboard.framework.msg.sms.SmsBody;
  4 +import cn.iocoder.dashboard.framework.msg.sms.SmsResult;
  5 +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsLogMapper;
  6 +import cn.iocoder.dashboard.util.json.JsonUtils;
  7 +import lombok.Setter;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +
  10 +import java.util.Collection;
  11 +
  12 +/**
  13 + * 短信日志拦截器
  14 + *
  15 + * @author zzf
  16 + * @date 2021/1/22 15:46
  17 + */
  18 +@Slf4j
  19 +public class SmsLogIntercepter implements SmsIntercepter {
  20 +
  21 +
  22 + @Override
  23 + public void beforeSender(SmsBody msgBody, Collection<String> targets) {
  24 + log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets);
  25 +
  26 + }
  27 +
  28 + @Override
  29 + public <T> void afterSender(SmsBody msgBody, Collection<String> targets, SmsResult<T> resultBody) {
  30 + if (resultBody.getSuccess()) {
  31 + //
  32 + } else {
  33 + log.warn("send sms fail, body: {}, target: {}, resultBody: {}",
  34 + JsonUtils.toJsonString(msgBody),
  35 + targets,
  36 + JsonUtils.toJsonString(resultBody)
  37 + );
  38 + }
  39 +
  40 + }
  41 +
  42 + @Override
  43 + public int getOrder() {
  44 + return 0;
  45 + }
  46 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.proxy;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.dashboard.framework.msg.sms.SmsBody;
  5 +import cn.iocoder.dashboard.framework.msg.sms.SmsResult;
  6 +import cn.iocoder.dashboard.framework.msg.sms.SmsSender;
  7 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.AbstractSmsIntercepterChain;
  8 +
  9 +import java.util.Collection;
  10 +
  11 +/**
  12 + * 消息父接口
  13 + *
  14 + * @author zzf
  15 + * @date 2021/1/22 15:46
  16 + */
  17 +public class DefaultSmsSenderProxy<R> implements SmsSender<R> {
  18 +
  19 + private final SmsSender<R> smsSender;
  20 + private final AbstractSmsIntercepterChain chain;
  21 +
  22 + @Override
  23 + public SmsResult<R> send(SmsBody msgBody, Collection<String> targets) {
  24 + if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) {
  25 + chain.getIntercepterList().forEach(s -> s.beforeSender(msgBody, targets));
  26 + }
  27 +
  28 + SmsResult<R> resultBody = smsSender.send(msgBody, targets);
  29 +
  30 + if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) {
  31 + chain.getIntercepterList().forEach(s -> s.afterSender(msgBody, targets, resultBody));
  32 + }
  33 + return resultBody;
  34 + }
  35 +
  36 + public DefaultSmsSenderProxy(SmsSender<R> smsSender,
  37 + AbstractSmsIntercepterChain chain) {
  38 + this.smsSender = smsSender;
  39 + this.chain = chain;
  40 + }
  41 +}
src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.msg.sms.proxy;
  2 +
  3 +import cn.iocoder.dashboard.framework.msg.sms.SmsSender;
  4 +import cn.iocoder.dashboard.framework.msg.sms.intercepter.SmsIntercepter;
  5 +
  6 +import java.util.Collections;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * 消息父接口
  11 + *
  12 + * @author zzf
  13 + * @date 2021/1/22 15:46
  14 + */
  15 +public interface SmsSenderProxy<R> extends SmsSender<R> {
  16 +
  17 + /**
  18 + * 添加短信拦截器
  19 + *
  20 + * @param smsIntercepter 短信拦截器
  21 + */
  22 + default void addSmsIntercepter(SmsIntercepter smsIntercepter) {
  23 + addSmsIntercepter(Collections.singletonList(smsIntercepter));
  24 + }
  25 +
  26 + /**
  27 + * 添加短信拦截器
  28 + *
  29 + * @param smsIntercepterList 短信拦截器数组
  30 + */
  31 + void addSmsIntercepter(List<SmsIntercepter> smsIntercepterList);
  32 +
  33 +
  34 +}
src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyDefine.java
1 package cn.iocoder.dashboard.framework.redis.core; 1 package cn.iocoder.dashboard.framework.redis.core;
2 2
3 -import lombok.AllArgsConstructor;  
4 import lombok.Data; 3 import lombok.Data;
5 -import lombok.Getter;  
6 4
7 import java.time.Duration; 5 import java.time.Duration;
8 6
@@ -26,20 +24,15 @@ public class RedisKeyDefine { @@ -26,20 +24,15 @@ public class RedisKeyDefine {
26 24
27 } 25 }
28 26
29 - @Getter  
30 - @AllArgsConstructor  
31 - public enum TimeoutTypeEnum {  
32 -  
33 - FOREVER(1), // 永不超时  
34 - DYNAMIC(2), // 动态超时  
35 - FIXED(3); // 固定超时  
36 -  
37 - /**  
38 - * 类型  
39 - */  
40 - private final Integer type; 27 + /**
  28 + * 过期时间 - 永不过期
  29 + */
  30 + public static final Duration TIMEOUT_FOREVER = null;
41 31
42 - } 32 + /**
  33 + * 过期时间 - 动态,通过参数传入
  34 + */
  35 + public static final Duration TIMEOUT_DYNAMIC = null;
43 36
44 /** 37 /**
45 * Key 模板 38 * Key 模板
@@ -56,11 +49,9 @@ public class RedisKeyDefine { @@ -56,11 +49,9 @@ public class RedisKeyDefine {
56 */ 49 */
57 private final Class<?> valueType; 50 private final Class<?> valueType;
58 /** 51 /**
59 - * 超时类型  
60 - */  
61 - private final TimeoutTypeEnum timeoutType;  
62 - /**  
63 * 过期时间 52 * 过期时间
  53 + *
  54 + * 为空时,表示永不过期 {@link #TIMEOUT_FOREVER}
64 */ 55 */
65 private final Duration timeout; 56 private final Duration timeout;
66 57
@@ -68,20 +59,7 @@ public class RedisKeyDefine { @@ -68,20 +59,7 @@ public class RedisKeyDefine {
68 this.keyTemplate = keyTemplate; 59 this.keyTemplate = keyTemplate;
69 this.keyType = keyType; 60 this.keyType = keyType;
70 this.valueType = valueType; 61 this.valueType = valueType;
71 - this.timeoutType = TimeoutTypeEnum.FIXED;  
72 this.timeout = timeout; 62 this.timeout = timeout;
73 - // 添加注册表  
74 - RedisKeyRegistry.add(this);  
75 - }  
76 -  
77 - public RedisKeyDefine(String keyTemplate, KeyTypeEnum keyType, Class<?> valueType, TimeoutTypeEnum timeoutType) {  
78 - this.keyTemplate = keyTemplate;  
79 - this.keyType = keyType;  
80 - this.valueType = valueType;  
81 - this.timeoutType = timeoutType;  
82 - this.timeout = Duration.ZERO;  
83 - // 添加注册表  
84 - RedisKeyRegistry.add(this);  
85 } 63 }
86 64
87 } 65 }
src/main/java/cn/iocoder/dashboard/framework/redis/core/RedisKeyRegistry.java deleted
1 -package cn.iocoder.dashboard.framework.redis.core;  
2 -  
3 -import java.util.ArrayList;  
4 -import java.util.List;  
5 -  
6 -/**  
7 - * {@link RedisKeyDefine} 注册表  
8 - */  
9 -public class RedisKeyRegistry {  
10 -  
11 - private static final List<RedisKeyDefine> defines = new ArrayList<>();  
12 -  
13 - public static void add(RedisKeyDefine define) {  
14 - defines.add(define);  
15 - }  
16 -  
17 - public static List<RedisKeyDefine> list() {  
18 - return defines;  
19 - }  
20 -  
21 - public static int size() {  
22 - return defines.size();  
23 - }  
24 -  
25 -}  
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
  6 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
  7 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
  8 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  9 +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService;
  10 +import io.swagger.annotations.Api;
  11 +import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.validation.annotation.Validated;
  13 +import org.springframework.web.bind.annotation.*;
  14 +
  15 +import javax.annotation.Resource;
  16 +import java.util.List;
  17 +
  18 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  19 +
  20 +@Api("短信 渠道/签名 API")
  21 +@RestController
  22 +@RequestMapping("/sms/channel")
  23 +public class SmsChannelController {
  24 +
  25 + @Resource
  26 + private SmsChannelService service;
  27 +
  28 + @ApiOperation("获取渠道/签名分页")
  29 + @GetMapping("/page")
  30 + public CommonResult<PageResult<SmsChannelDO>> getPermissionInfo(@Validated SmsChannelPageReqVO reqVO) {
  31 + return success(service.pageChannels(reqVO));
  32 + }
  33 +
  34 + @ApiOperation("获取渠道枚举")
  35 + @GetMapping("/list/channel-enum")
  36 + public CommonResult<List<SmsChannelEnumRespVO>> getChannelEnums() {
  37 + return success(service.getChannelEnums());
  38 + }
  39 +
  40 +
  41 + @ApiOperation("添加消息渠道")
  42 + @PostMapping("/create")
  43 + public CommonResult<Long> add(@Validated @RequestBody SmsChannelCreateReqVO reqVO) {
  44 + return success(service.createChannel(reqVO));
  45 + }
  46 +
  47 + @ApiOperation("刷新消息渠道信息")
  48 + @PutMapping("/flush")
  49 + public CommonResult<Boolean> flushChannel() {
  50 + return success(service.flushChannel());
  51 + }
  52 +
  53 +
  54 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  5 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  6 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginReqVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthLoginRespVO;
  8 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthMenuRespVO;
  9 +import cn.iocoder.dashboard.modules.system.controller.auth.vo.SysAuthPermissionInfoRespVO;
  10 +import cn.iocoder.dashboard.modules.system.convert.auth.SysAuthConvert;
  11 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO;
  12 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO;
  13 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
  14 +import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum;
  15 +import cn.iocoder.dashboard.modules.system.service.auth.SysAuthService;
  16 +import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService;
  17 +import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService;
  18 +import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
  19 +import cn.iocoder.dashboard.util.collection.SetUtils;
  20 +import io.swagger.annotations.Api;
  21 +import io.swagger.annotations.ApiOperation;
  22 +import org.springframework.web.bind.annotation.*;
  23 +
  24 +import javax.annotation.Resource;
  25 +import javax.validation.Valid;
  26 +import java.util.List;
  27 +
  28 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  29 +import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserId;
  30 +import static cn.iocoder.dashboard.framework.security.core.util.SecurityUtils.getLoginUserRoleIds;
  31 +
  32 +@Api("认证 API")
  33 +@RestController
  34 +@RequestMapping("/sms/template")
  35 +public class SmsTemplateController {
  36 +
  37 + @Resource
  38 + private SysAuthService authService;
  39 + @Resource
  40 + private SysUserService userService;
  41 + @Resource
  42 + private SysRoleService roleService;
  43 + @Resource
  44 + private SysPermissionService permissionService;
  45 +
  46 + @ApiOperation("使用账号密码登录")
  47 + @PostMapping("/login")
  48 + @OperateLog(enable = false) // 避免 Post 请求被记录操作日志
  49 + public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {
  50 + String token = authService.login(reqVO.getUsername(), reqVO.getPassword(), reqVO.getUuid(), reqVO.getCode());
  51 + // 返回结果
  52 + return success(SysAuthLoginRespVO.builder().token(token).build());
  53 + }
  54 +
  55 + @ApiOperation("获取登陆用户的权限信息")
  56 + @GetMapping("/get-permission-info")
  57 + public CommonResult<SysAuthPermissionInfoRespVO> getPermissionInfo() {
  58 + // 获得用户信息
  59 + SysUserDO user = userService.getUser(getLoginUserId());
  60 + if (user == null) {
  61 + return null;
  62 + }
  63 + // 获得角色列表
  64 + List<SysRoleDO> roleList = roleService.listRolesFromCache(getLoginUserRoleIds());
  65 + // 获得菜单列表
  66 + List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(),
  67 + SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
  68 + SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
  69 + // 拼接结果返回
  70 + return success(SysAuthConvert.INSTANCE.convert(user, roleList, menuList));
  71 + }
  72 +
  73 + @ApiOperation("获得登陆用户的菜单列表")
  74 + @GetMapping("list-menus")
  75 + public CommonResult<List<SysAuthMenuRespVO>> listMenus() {
  76 + // 获得用户拥有的菜单列表
  77 + List<SysMenuDO> menuList = permissionService.listRoleMenusFromCache(getLoginUserRoleIds(),
  78 + SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
  79 + SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
  80 + // 转换成 Tree 结构返回
  81 + return success(SysAuthConvert.INSTANCE.buildMenuTree(menuList));
  82 + }
  83 +
  84 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +import java.io.Serializable;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * 渠道(包含模板)信息VO类
  11 + *
  12 + * @author zzf
  13 + * @date 2021/1/25 17:01
  14 + */
  15 +@Data
  16 +@EqualsAndHashCode
  17 +public class SmsChannelAllVO implements Serializable {
  18 +
  19 + /**
  20 + * id
  21 + */
  22 + private Long id;
  23 +
  24 + /**
  25 + * 编码(来自枚举类 阿里、华为、七牛等)
  26 + */
  27 + private String code;
  28 +
  29 + /**
  30 + * 渠道账号id
  31 + */
  32 + private String apiKey;
  33 +
  34 + /**
  35 + * 渠道账号秘钥
  36 + */
  37 + private String apiSecret;
  38 +
  39 + /**
  40 + * 实际渠道签名唯一标识
  41 + */
  42 + private String apiSignatureId;
  43 +
  44 + /**
  45 + * 签名值
  46 + */
  47 + private String signature;
  48 +
  49 + /**
  50 + * 该渠道名下的短信模板集合
  51 + */
  52 + private List<SmsTemplateVO> templateList;
  53 +
  54 + public SmsTemplateVO getTemplateByTemplateCode(String tempCode) {
  55 + return templateList.stream().filter(s -> s.getCode().equals(tempCode)).findFirst().get();
  56 + }
  57 +
  58 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo;
  2 +
  3 +import lombok.Data;
  4 +import lombok.EqualsAndHashCode;
  5 +
  6 +/**
  7 + * 渠道模板VO类
  8 + *
  9 + * @author zzf
  10 + * @date 2021/1/25 17:03
  11 + */
  12 +@Data
  13 +@EqualsAndHashCode
  14 +public class SmsTemplateVO {
  15 +
  16 + /**
  17 + * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)
  18 + */
  19 + private String bizCode;
  20 + /**
  21 + * 编码
  22 + */
  23 + private String code;
  24 +
  25 + /**
  26 + * 实际渠道模板唯一标识
  27 + */
  28 + private String apiTemplateId;
  29 +
  30 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.NoArgsConstructor;
  9 +
  10 +import java.io.Serializable;
  11 +
  12 +
  13 +@ApiModel("消息渠道创建 Request VO")
  14 +@Data
  15 +@NoArgsConstructor
  16 +@AllArgsConstructor
  17 +@EqualsAndHashCode
  18 +public class SmsChannelCreateReqVO implements Serializable {
  19 +
  20 + @ApiModelProperty("编码(来自枚举类 阿里、华为、七牛等)")
  21 + private String code;
  22 +
  23 + @ApiModelProperty("渠道账号id")
  24 + private String apiKey;
  25 +
  26 + @ApiModelProperty("渠道账号秘钥")
  27 + private String apiSecret;
  28 +
  29 + @ApiModelProperty("优先级(存在多个签名时,选择值最小的,渠道不可用时,按优先级从小到大切换)")
  30 + private Integer priority;
  31 +
  32 + @ApiModelProperty("名称")
  33 + private String name;
  34 +
  35 + @ApiModelProperty("签名值")
  36 + private String signature;
  37 +
  38 + @ApiModelProperty("备注")
  39 + private String remark;
  40 +
  41 + @ApiModelProperty("启用状态(0正常 1停用)")
  42 + private Integer status;
  43 +
  44 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.req;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.NoArgsConstructor;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.util.Date;
  13 +
  14 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  15 +
  16 +@ApiModel("消息渠道分页 Request VO")
  17 +@Data
  18 +@NoArgsConstructor
  19 +@AllArgsConstructor
  20 +@EqualsAndHashCode(callSuper = true)
  21 +public class SmsChannelPageReqVO extends PageParam {
  22 +
  23 + @ApiModelProperty(value = "渠道名", example = "阿里", notes = "模糊匹配")
  24 + private String name;
  25 +
  26 + @ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配")
  27 + private String signature;
  28 +
  29 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.NoArgsConstructor;
  7 +
  8 +import java.io.Serializable;
  9 +
  10 +
  11 +@ApiModel("用户分页 Request VO")
  12 +@Data
  13 +@NoArgsConstructor
  14 +@EqualsAndHashCode
  15 +public class SmsChannelEnumRespVO implements Serializable {
  16 +
  17 + private String code;
  18 +
  19 + private String name;
  20 +
  21 +}
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Data;
  8 +import lombok.EqualsAndHashCode;
  9 +import lombok.NoArgsConstructor;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import java.util.Date;
  13 +
  14 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  15 +
  16 +@ApiModel("用户分页 Request VO")
  17 +@Data
  18 +@NoArgsConstructor
  19 +@AllArgsConstructor
  20 +@EqualsAndHashCode(callSuper = true)
  21 +public class SmsChannelPageRespVO extends PageParam {
  22 +
  23 + @ApiModelProperty(value = "用户账号", example = "yudao", notes = "模糊匹配")
  24 + private String username;
  25 +
  26 + @ApiModelProperty(value = "手机号码", example = "yudao", notes = "模糊匹配")
  27 + private String mobile;
  28 +
  29 + @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
  30 + private Integer status;
  31 +
  32 + @ApiModelProperty(value = "开始时间", example = "2020-10-24")
  33 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  34 + private Date beginTime;
  35 +
  36 + @ApiModelProperty(value = "结束时间", example = "2020-10-24")
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + private Date endTime;
  39 +
  40 + @ApiModelProperty(value = "部门编号", example = "1024", notes = "同时筛选子部门")
  41 + private Long deptId;
  42 +
  43 +}
src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.convert.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  6 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
  7 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
  8 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  9 +import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
  10 +import com.baomidou.mybatisplus.core.metadata.IPage;
  11 +import org.mapstruct.Mapper;
  12 +import org.mapstruct.Mapping;
  13 +import org.mapstruct.factory.Mappers;
  14 +
  15 +import java.util.List;
  16 +
  17 +@Mapper
  18 +public interface SmsChannelConvert {
  19 +
  20 + SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class);
  21 +
  22 + @Mapping(source = "records", target = "list")
  23 + PageResult<SmsChannelDO> convertPage(IPage<SmsChannelDO> page);
  24 +
  25 + SmsChannelDO convert(SmsChannelCreateReqVO bean);
  26 +
  27 + SmsChannelDO convert(SysUserUpdateReqVO bean);
  28 +
  29 + List<SmsChannelEnumRespVO> convertEnum(List<SmsChannelEnum> bean);
  30 +
  31 + List<SmsChannelAllVO> convert(List<SmsChannelDO> bean);
  32 +
  33 +
  34 +}
src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.convert.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO;
  5 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  6 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO;
  7 +import com.baomidou.mybatisplus.core.metadata.IPage;
  8 +import org.mapstruct.Mapper;
  9 +import org.mapstruct.Mapping;
  10 +import org.mapstruct.factory.Mappers;
  11 +
  12 +import java.util.List;
  13 +
  14 +@Mapper
  15 +public interface SmsTemplateConvert {
  16 +
  17 + SmsTemplateConvert INSTANCE = Mappers.getMapper(SmsTemplateConvert.class);
  18 +
  19 + @Mapping(source = "records", target = "list")
  20 + PageResult<SmsChannelDO> convertPage(IPage<SmsChannelDO> page);
  21 +
  22 + List<SmsTemplateVO> convert(List<SmsTemplateDO> bean);
  23 +
  24 + SmsTemplateVO convert(SmsTemplateDO bean);
  25 +
  26 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
  6 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
  7 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  8 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  9 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  10 +import com.baomidou.mybatisplus.core.metadata.IPage;
  11 +import org.apache.ibatis.annotations.Mapper;
  12 +
  13 +import java.util.List;
  14 +
  15 +@Mapper
  16 +public interface SmsChannelMapper extends BaseMapper<SmsChannelDO> {
  17 +
  18 + default IPage<SmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
  19 + return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SmsChannelDO>()
  20 + .like(StrUtil.isNotBlank(reqVO.getName()), SmsChannelDO::getName, reqVO.getName())
  21 + .like(StrUtil.isNotBlank(reqVO.getSignature()), SmsChannelDO::getName, reqVO.getSignature())
  22 + );
  23 + }
  24 +
  25 + default List<SmsChannelDO> selectEnabledList() {
  26 + return selectList(new LambdaQueryWrapper<SmsChannelDO>()
  27 + .eq(SmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
  28 + .orderByAsc(SmsChannelDO::getId)
  29 + );
  30 + }
  31 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms;
  2 +
  3 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsLog;
  4 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +@Mapper
  8 +public interface SmsLogMapper extends BaseMapper<SmsLog> {
  9 +
  10 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO;
  5 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  7 +import org.apache.ibatis.annotations.Mapper;
  8 +
  9 +import java.util.List;
  10 +
  11 +@Mapper
  12 +public interface SmsTemplateMapper extends BaseMapper<SmsTemplateDO> {
  13 +
  14 + /**
  15 + * 根据短信渠道id查询短信模板集合
  16 + *
  17 + * @param channelId 渠道id
  18 + * @return 模板集合
  19 + */
  20 + default List<SmsTemplateDO> selectListByChannelId(Long channelId) {
  21 + return selectList(new LambdaQueryWrapper<SmsTemplateDO>()
  22 + .eq(SmsTemplateDO::getChannelId, channelId)
  23 + .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
  24 + .orderByAsc(SmsTemplateDO::getId)
  25 + );
  26 + }
  27 +
  28 + /**
  29 + * 查询有效短信模板集合
  30 + *
  31 + * @return 有效短信模板集合
  32 + */
  33 + default List<SmsTemplateDO> selectEnabledList() {
  34 + return selectList(new LambdaQueryWrapper<SmsTemplateDO>()
  35 + .eq(SmsTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus())
  36 + .orderByAsc(SmsTemplateDO::getId)
  37 + );
  38 + }
  39 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms;
  2 +
  3 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +
  8 +
  9 +/**
  10 + * 短信渠道
  11 + *
  12 + * @author zzf
  13 + * @since 2021-01-25
  14 + */
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@TableName(value = "sms_channel", autoResultMap = true)
  18 +public class SmsChannelDO extends BaseDO {
  19 +
  20 + /**
  21 + * 自增编号
  22 + */
  23 + private Long id;
  24 +
  25 + /**
  26 + * 编码(来自枚举类 阿里、华为、七牛等)
  27 + */
  28 + private String code;
  29 +
  30 + /**
  31 + * 渠道账号id
  32 + */
  33 + private String apiKey;
  34 +
  35 + /**
  36 + * 渠道账号秘钥
  37 + */
  38 + private String apiSecret;
  39 +
  40 + /**
  41 + * 实际渠道签名唯一标识
  42 + */
  43 + private String apiSignatureId;
  44 +
  45 + /**
  46 + * 名称
  47 + */
  48 + private String name;
  49 +
  50 + /**
  51 + * 签名值
  52 + */
  53 + private String signature;
  54 +
  55 + /**
  56 + * 备注
  57 + */
  58 + private String remark;
  59 +
  60 + /**
  61 + * 启用状态(0正常 1停用)
  62 + */
  63 + private Integer status;
  64 +
  65 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms;
  2 +
  3 +import com.baomidou.mybatisplus.annotation.TableName;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +
  7 +import java.io.Serializable;
  8 +import java.util.Date;
  9 +
  10 +/**
  11 + * 短信日志
  12 + *
  13 + * @author zzf
  14 + * @since 2021-01-25
  15 + */
  16 +@Data
  17 +@EqualsAndHashCode
  18 +@TableName(value = "sms_log", autoResultMap = true)
  19 +public class SmsLog implements Serializable {
  20 +
  21 + /**
  22 + * 自增编号
  23 + */
  24 + private Long id;
  25 +
  26 + /**
  27 + * 短信渠道编码(来自枚举类)
  28 + */
  29 + private String channelCode;
  30 +
  31 + /**
  32 + * 实际渠道短信唯一标识
  33 + */
  34 + private String apiSmsId;
  35 +
  36 + /**
  37 + * 模板id
  38 + */
  39 + private Long templateId;
  40 +
  41 + /**
  42 + * 手机号
  43 + */
  44 + private String phone;
  45 +
  46 + /**
  47 + * 内容
  48 + */
  49 + private String content;
  50 +
  51 + /**
  52 + * 备注
  53 + */
  54 + private String remark;
  55 +
  56 + /**
  57 + * 发送状态(0发送中 1成功 2失败)
  58 + */
  59 + private Integer sendStatus;
  60 +
  61 + /**
  62 + * 创建者
  63 + */
  64 + private String createBy;
  65 +
  66 + /**
  67 + * 创建时间
  68 + */
  69 + private Date createTime;
  70 +
  71 +}
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms;
  2 +
  3 +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.TableName;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +
  8 +import java.util.Date;
  9 +
  10 +/**
  11 + * 短信模板
  12 + *
  13 + * @author zzf
  14 + * @since 2021-01-25
  15 + */
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@TableName(value = "sms_template", autoResultMap = true)
  19 +public class SmsTemplateDO extends BaseDO {
  20 +
  21 + /**
  22 + * 自增编号
  23 + */
  24 + private Long id;
  25 +
  26 + /**
  27 + * 短信渠道编码(来自枚举类)
  28 + */
  29 + private String channelCode;
  30 +
  31 + /**
  32 + * 短信渠道id (对于前端来说就是绑定一个签名)
  33 + */
  34 + private Long channelId;
  35 +
  36 + /**
  37 + * 消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]
  38 + */
  39 + private Integer type;
  40 +
  41 + /**
  42 + * 业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)
  43 + */
  44 + private String bizCode;
  45 +
  46 + /**
  47 + * 编码
  48 + */
  49 + private String code;
  50 +
  51 + /**
  52 + * 名称
  53 + */
  54 + private String name;
  55 +
  56 + /**
  57 + * 实际渠道模板唯一标识
  58 + */
  59 + private String apiTemplateId;
  60 +
  61 + /**
  62 + * 内容
  63 + */
  64 + private String content;
  65 +
  66 + /**
  67 + * 参数数组(自动根据内容生成)
  68 + */
  69 + private String params;
  70 +
  71 + /**
  72 + * 备注
  73 + */
  74 + private String remark;
  75 +
  76 + /**
  77 + * 启用状态(0正常 1停用)
  78 + */
  79 + private Integer status;
  80 +
  81 +}
src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java 0 → 100644
  1 +/**
  2 + * msg 包,专门专门用于发送消息的功能,支撑上层的通用与核心业务。
  3 + * 例如说:短信、邮件、app通知等等
  4 + *
  5 + */
  6 +package cn.iocoder.dashboard.modules.msg;
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  5 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
  6 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
  7 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
  8 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 短信渠道Service接口
  14 + *
  15 + * @author zzf
  16 + * @date 2021/1/25 9:24
  17 + */
  18 +public interface SmsChannelService {
  19 +
  20 + PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO);
  21 +
  22 + Long createChannel(SmsChannelCreateReqVO reqVO);
  23 +
  24 + List<SmsChannelEnumRespVO> getChannelEnums();
  25 +
  26 + /**
  27 + * 查询渠道(包含名下模块)信息集合
  28 + *
  29 + * @return 渠道(包含名下模块)信息集合
  30 + */
  31 + List<SmsChannelAllVO> listChannelAllEnabledInfo();
  32 +
  33 + boolean flushChannel();
  34 +}
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms;
  2 +
  3 +/**
  4 + * 短信渠道Service接口
  5 + *
  6 + * @author zzf
  7 + * @date 2021/1/25 9:24
  8 + */
  9 +public interface SmsLogService {
  10 +}
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms;
  2 +
  3 +/**
  4 + * 短信渠道Service接口
  5 + *
  6 + * @author zzf
  7 + * @date 2021/1/25 9:24
  8 + */
  9 +public interface SmsTemplateService {
  10 +}
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms.impl;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.hutool.extra.spring.SpringUtil;
  5 +import cn.iocoder.dashboard.common.enums.SmsChannelEnum;
  6 +import cn.iocoder.dashboard.common.pojo.PageResult;
  7 +import cn.iocoder.dashboard.framework.msg.sms.factory.AbstractSmsSenderFactory;
  8 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
  9 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
  10 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
  11 +import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
  12 +import cn.iocoder.dashboard.modules.msg.convert.sms.SmsChannelConvert;
  13 +import cn.iocoder.dashboard.modules.msg.convert.sms.SmsTemplateConvert;
  14 +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsChannelMapper;
  15 +import cn.iocoder.dashboard.modules.msg.dal.mysql.dao.sms.SmsTemplateMapper;
  16 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
  17 +import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsTemplateDO;
  18 +import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService;
  19 +import org.springframework.stereotype.Service;
  20 +
  21 +import javax.annotation.Resource;
  22 +import java.util.ArrayList;
  23 +import java.util.Arrays;
  24 +import java.util.List;
  25 +
  26 +/**
  27 + * 短信渠道Service实现类
  28 + *
  29 + * @author zzf
  30 + * @date 2021/1/25 9:25
  31 + */
  32 +@Service
  33 +public class SmsChannelServiceImpl implements SmsChannelService {
  34 +
  35 + @Resource
  36 + private SmsChannelMapper mapper;
  37 +
  38 + @Resource
  39 + private SmsTemplateMapper templateMapper;
  40 +
  41 + @Override
  42 + public PageResult<SmsChannelDO> pageChannels(SmsChannelPageReqVO reqVO) {
  43 + return SmsChannelConvert.INSTANCE.convertPage(mapper.selectChannelPage(reqVO));
  44 + }
  45 +
  46 + @Override
  47 + public Long createChannel(SmsChannelCreateReqVO reqVO) {
  48 + SmsChannelDO channelDO = SmsChannelConvert.INSTANCE.convert(reqVO);
  49 + mapper.insert(channelDO);
  50 + return channelDO.getId();
  51 + }
  52 +
  53 + @Override
  54 + public List<SmsChannelEnumRespVO> getChannelEnums() {
  55 + return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
  56 + }
  57 +
  58 + @Override
  59 + public List<SmsChannelAllVO> listChannelAllEnabledInfo() {
  60 + List<SmsChannelDO> channelDOList = mapper.selectEnabledList();
  61 + if (ObjectUtil.isNull(channelDOList)) {
  62 + return null;
  63 + }
  64 + List<SmsChannelAllVO> channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList);
  65 +
  66 + channelAllVOList.forEach(smsChannelDO -> {
  67 +
  68 + List<SmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
  69 + if (ObjectUtil.isNull(templateDOList)) {
  70 + templateDOList = new ArrayList<>();
  71 + }
  72 + smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList));
  73 + });
  74 + return channelAllVOList;
  75 + }
  76 +
  77 + @Override
  78 + public boolean flushChannel() {
  79 + AbstractSmsSenderFactory smsSenderFactory = SpringUtil.getBean(AbstractSmsSenderFactory.class);
  80 + if (smsSenderFactory == null) {
  81 + return false;
  82 + }
  83 +
  84 + smsSenderFactory.flush(listChannelAllEnabledInfo());
  85 +
  86 + return true;
  87 + }
  88 +}
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms.impl;
  2 +
  3 +import cn.iocoder.dashboard.modules.msg.service.sms.SmsLogService;
  4 +import org.springframework.stereotype.Service;
  5 +
  6 +/**
  7 + * 短信日志Service实现类
  8 + *
  9 + * @author zzf
  10 + * @date 2021/1/25 9:25
  11 + */
  12 +@Service
  13 +public class SmsLogServiceImpl implements SmsLogService {
  14 +
  15 +}
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.msg.service.sms.impl;
  2 +
  3 +import cn.iocoder.dashboard.modules.msg.service.sms.SmsTemplateService;
  4 +import org.springframework.stereotype.Service;
  5 +
  6 +/**
  7 + * 短信模板Service实现类
  8 + *
  9 + * @author zzf
  10 + * @date 2021/1/25 9:25
  11 + */
  12 +@Service
  13 +public class SmsTemplateServiceImpl implements SmsTemplateService {
  14 +}
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
@@ -75,4 +75,11 @@ public interface SysErrorCodeConstants { @@ -75,4 +75,11 @@ public interface SysErrorCodeConstants {
75 // ========== 文件 1002009000 ========== 75 // ========== 文件 1002009000 ==========
76 ErrorCode FILE_PATH_EXISTS = new ErrorCode(1002009001, "文件路径已经存在"); 76 ErrorCode FILE_PATH_EXISTS = new ErrorCode(1002009001, "文件路径已经存在");
77 77
  78 +
  79 + // ========== 消息 1003001000 ==========
  80 + ErrorCode SMS_CHANNEL_NOT_FOUND = new ErrorCode(1003001001, "没有短信渠道信息, 请初始化sms_channel表数据。");
  81 + ErrorCode SMS_TEMPLATE_NOT_FOUND = new ErrorCode(1003001002, "没有短信模板信息, 请初始化sms_template表数据。");
  82 + ErrorCode SMS_SENDER_NOT_FOUND = new ErrorCode(1003001003, "没有找到对应的短信发送对象,请检查sms_channel表和sms_template表数据");
  83 + ErrorCode INVALID_CHANNEL_CODE = new ErrorCode(1003001004, "非法的短信渠道code,请检查sms_channel表的code值是否与SmsChannelEnum中的code值一致。");
  84 +
78 } 85 }