Jelajahi Sumber

重构短信功能

zengzefeng 4 tahun lalu
induk
melakukan
37c39365ec
42 mengubah file dengan 455 tambahan dan 567 penghapusan
  1. 5 7
      sql/ruoyi-vue-pro.sql
  2. 0 67
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java
  3. 0 48
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java
  4. 0 137
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java
  5. 0 38
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java
  6. 0 20
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java
  7. 0 41
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java
  8. 0 46
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java
  9. 0 41
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java
  10. 0 34
      src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java
  11. 1 1
      src/main/java/cn/iocoder/dashboard/framework/sms/SmsBody.java
  12. 107 0
      src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java
  13. 42 0
      src/main/java/cn/iocoder/dashboard/framework/sms/SmsClientAdapter.java
  14. 1 1
      src/main/java/cn/iocoder/dashboard/framework/sms/SmsResult.java
  15. 0 6
      src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java
  16. 6 6
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsChannelController.java
  17. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/SmsTemplateController.java
  18. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsChannelAllVO.java
  19. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/SmsTemplateVO.java
  20. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelCreateReqVO.java
  21. 1 6
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/req/SmsChannelPageReqVO.java
  22. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelEnumRespVO.java
  23. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/controller/sms/vo/resp/SmsChannelPageRespVO.java
  24. 5 5
      src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsChannelConvert.java
  25. 4 4
      src/main/java/cn/iocoder/dashboard/modules/system/convert/sms/SmsTemplateConvert.java
  26. 3 3
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsChannelMapper.java
  27. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsLogMapper.java
  28. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/sms/SmsTemplateMapper.java
  29. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsChannelDO.java
  30. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsLog.java
  31. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/sms/SmsTemplateDO.java
  32. 6 4
      src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java
  33. 6 6
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsChannelService.java
  34. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsLogService.java
  35. 1 1
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/SmsTemplateService.java
  36. 12 20
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsChannelServiceImpl.java
  37. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsLogServiceImpl.java
  38. 2 2
      src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SmsTemplateServiceImpl.java
  39. 34 0
      src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsConfiguration.java
  40. 143 0
      src/main/java/cn/iocoder/dashboard/modules/system/sms/SmsSenderUtils.java
  41. 12 7
      src/main/java/cn/iocoder/dashboard/modules/system/sms/client/AliSmsClient.java
  42. 48 0
      src/main/java/cn/iocoder/dashboard/modules/system/sms/proxy/SmsClientLogProxy.java

+ 5 - 7
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停用)',

+ 0 - 67
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsSender.java

@@ -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<R> {
-
-    /**
-     * 发送通知
-     *
-     * @param msgBody 通知内容
-     * @param targets 发送对象列表
-     * @return 是否发送成功
-     */
-    SmsResult<R> send(SmsBody msgBody, Collection<String> targets);
-
-    /**
-     * 发送通知
-     *
-     * @param msgBody 通知内容
-     * @param target  发送对象列表
-     * @return 是否发送成功
-     */
-    default SmsResult<R> send(SmsBody msgBody, String target) {
-        if (StringUtils.isBlank(target)) {
-            return failResult();
-        }
-
-        return send(msgBody, Collections.singletonList(target));
-    }
-
-    /**
-     * 发送通知
-     *
-     * @param msgBody 通知内容
-     * @param targets 发送对象列表
-     * @return 是否发送成功
-     */
-    default SmsResult<R> send(SmsBody msgBody, String... targets) {
-        if (targets == null) {
-            return failResult();
-        }
-
-        return send(msgBody, Arrays.asList(targets));
-    }
-
-    default SmsResult<R> failResult() {
-        SmsResult<R> resultBody = new SmsResult<>();
-        resultBody.setSuccess(false);
-        return resultBody;
-    }
-
-    default SmsResult<R> failResult(String message) {
-        SmsResult<R> resultBody = failResult();
-        resultBody.setMessage(message);
-        return resultBody;
-    }
-}

+ 0 - 48
src/main/java/cn/iocoder/dashboard/framework/msg/sms/config/SmsConfiguration.java

@@ -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<SmsChannelAllVO> smsChannelAllVOList = channelService.listChannelAllEnabledInfo();
-        //初始化渠道、模板信息
-        defaultSmsSenderFactory.init(smsChannelAllVOList);
-        //注入拦截器链
-        defaultSmsSenderFactory.setIntercepterChain(intercepterChain);
-        return defaultSmsSenderFactory;
-    }
-
-}

+ 0 - 137
src/main/java/cn/iocoder/dashboard/framework/msg/sms/factory/DefaultSmsSenderFactory.java

@@ -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<String, SmsSender<?>> bizCode2SenderMap = new ConcurrentHashMap<>(8);
-
-    /**
-     * sender索引
-     * key: {@link SmsTemplateVO#getCode()}
-     * value: {@link SmsSender}
-     */
-    private final ConcurrentHashMap<String, SmsSender<?>> 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<SmsChannelAllVO> 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<String, SmsSender<?>> 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<SmsChannelAllVO> smsChannelAllVOList) {
-        try {
-            writeLock.lock();
-            bizCode2SenderMap.clear();
-            templateCode2SenderMap.clear();
-            addSender(smsChannelAllVOList);
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
-
-    private void addSender(List<SmsChannelAllVO> 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<SmsTemplateVO> 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);
-    }
-
-
-
-
-}

+ 0 - 38
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/AbstractSmsIntercepterChain.java

@@ -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<SmsIntercepter> intercepterList = new ArrayList<>(8);
-
-
-    /**
-     * 添加短信拦截器
-     *
-     * @param smsIntercepter 短信拦截器
-     */
-    public void addSmsIntercepter(SmsIntercepter smsIntercepter) {
-        addSmsIntercepter(Collections.singletonList(smsIntercepter));
-    }
-
-    /**
-     * 添加短信拦截器
-     *
-     * @param smsIntercepterList 短信拦截器数组
-     */
-    abstract void addSmsIntercepter(List<SmsIntercepter> smsIntercepterList);
-
-
-}

+ 0 - 20
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/DefaultSmsIntercepterChain.java

@@ -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<SmsIntercepter> smsIntercepterList) {
-        intercepterList.addAll(smsIntercepterList);
-        //排序
-        intercepterList.sort(Comparator.comparingInt(SmsIntercepter::getOrder));
-    }
-}

+ 0 - 41
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsIntercepter.java

@@ -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<String> targets);
-
-    /**
-     * 监听发送后
-     *
-     * @param msgBody    消息体
-     * @param targets    发送对象数组
-     * @param resultBody 返回对象
-     */
-    <T> void afterSender(SmsBody msgBody, Collection<String> targets, SmsResult<T> resultBody);
-
-    /**
-     * 排序值,拦截器根据order值顺序执行
-     * <p>
-     * 值越小,越早执行
-     *
-     * @return 排序值
-     */
-    int getOrder();
-}

+ 0 - 46
src/main/java/cn/iocoder/dashboard/framework/msg/sms/intercepter/SmsLogIntercepter.java

@@ -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<String> targets) {
-        log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets);
-
-    }
-
-    @Override
-    public <T> void afterSender(SmsBody msgBody, Collection<String> targets, SmsResult<T> 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;
-    }
-}

+ 0 - 41
src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/DefaultSmsSenderProxy.java

@@ -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<R> implements SmsSender<R> {
-
-    private final SmsSender<R> smsSender;
-    private final AbstractSmsIntercepterChain chain;
-
-    @Override
-    public SmsResult<R> send(SmsBody msgBody, Collection<String> targets) {
-        if (ObjectUtil.isNotNull(chain) && ObjectUtil.isNotEmpty(chain.getIntercepterList())) {
-            chain.getIntercepterList().forEach(s -> s.beforeSender(msgBody, targets));
-        }
-
-        SmsResult<R> 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<R> smsSender,
-                                 AbstractSmsIntercepterChain chain) {
-        this.smsSender = smsSender;
-        this.chain = chain;
-    }
-}

+ 0 - 34
src/main/java/cn/iocoder/dashboard/framework/msg/sms/proxy/SmsSenderProxy.java

@@ -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<R> extends SmsSender<R> {
-
-    /**
-     * 添加短信拦截器
-     *
-     * @param smsIntercepter 短信拦截器
-     */
-    default void addSmsIntercepter(SmsIntercepter smsIntercepter) {
-        addSmsIntercepter(Collections.singletonList(smsIntercepter));
-    }
-
-    /**
-     * 添加短信拦截器
-     *
-     * @param smsIntercepterList 短信拦截器数组
-     */
-    void addSmsIntercepter(List<SmsIntercepter> smsIntercepterList);
-
-
-}

+ 1 - 1
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsBody.java → 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;

+ 107 - 0
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<R> {
+
+    /**
+     * 发送消息
+     *
+     * @param msgBody 消息内容
+     * @param targets 发送对象列表
+     * @return 是否发送成功
+     */
+    SmsResult<R> send(SmsBody msgBody, Collection<String> targets);
+
+    /**
+     * 发送消息
+     *
+     * @param msgBody 消息内容
+     * @param target  发送对象
+     * @return 是否发送成功
+     */
+    default SmsResult<R> send(SmsBody msgBody, String target) {
+        if (StringUtils.isBlank(target)) {
+            return failResult();
+        }
+
+        return send(msgBody, Collections.singletonList(target));
+    }
+
+    /**
+     * 发送消息
+     *
+     * @param msgBody 消息内容
+     * @param targets 发送对象列表
+     * @return 是否发送成功
+     */
+    default SmsResult<R> send(SmsBody msgBody, String... targets) {
+        if (targets == null) {
+            return failResult();
+        }
+
+        return send(msgBody, Arrays.asList(targets));
+    }
+
+
+    /**
+     * 异步发送消息
+     *
+     * @param msgBody 消息内容
+     * @param targets 发送对象列表
+     * @return 是否发送成功
+     */
+    SmsResult<R> sendAsync(SmsBody msgBody, Collection<String> targets);
+
+    /**
+     * 异步发送消息
+     *
+     * @param msgBody 消息内容
+     * @param target  发送对象
+     * @return 是否发送成功
+     */
+    default SmsResult<R> 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<R> sendAsync(SmsBody msgBody, String... targets) {
+        if (targets == null) {
+            return failResult("targets must not null.");
+        }
+
+        return sendAsync(msgBody, Arrays.asList(targets));
+    }
+
+    default SmsResult<R> failResult() {
+        SmsResult<R> resultBody = new SmsResult<>();
+        resultBody.setSuccess(false);
+        return resultBody;
+    }
+
+    default SmsResult<R> failResult(String message) {
+        SmsResult<R> resultBody = failResult();
+        resultBody.setMessage(message);
+        return resultBody;
+    }
+}

+ 42 - 0
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<Long, SmsClient<?>> smsSenderMap;
+
+    public SmsClientAdapter(Map<Long, SmsClient<?>> smsSenderMap) {
+        if (ObjectUtil.isEmpty(smsSenderMap)) {
+            throw new ServiceException(SMS_CHANNEL_NOT_INIT);
+        }
+        this.smsSenderMap = smsSenderMap;
+    }
+
+    public void flushClient(Map<Long, SmsClient<?>> smsSenderMap) {
+        this.smsSenderMap.clear();
+        smsSenderMap.putAll(Collections.unmodifiableMap(smsSenderMap));
+    }
+
+    public SmsResult<?> send(Long channelId, SmsBody smsBody, Collection<String> targetPhone) {
+        SmsClient<?> smsClient = getSmsSender(channelId);
+        return smsClient.send(smsBody, targetPhone);
+    }
+
+    private SmsClient<?> getSmsSender(Long channelId) {
+        return smsSenderMap.get(channelId);
+    }
+}

+ 1 - 1
src/main/java/cn/iocoder/dashboard/framework/msg/sms/SmsResult.java → 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;
 

+ 0 - 6
src/main/java/cn/iocoder/dashboard/modules/msg/package-info.java

@@ -1,6 +0,0 @@
-/**
- * msg 包,专门专门用于发送消息的功能,支撑上层的通用与核心业务。
- * 例如说:短信、邮件、app通知等等
- *
- */
-package cn.iocoder.dashboard.modules.msg;

+ 6 - 6
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsChannelController.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/SmsTemplateController.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsChannelAllVO.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/SmsTemplateVO.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelCreateReqVO.java → 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;

+ 1 - 6
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/req/SmsChannelPageReqVO.java → 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

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelEnumRespVO.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/controller/sms/vo/resp/SmsChannelPageRespVO.java → 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;

+ 5 - 5
src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsChannelConvert.java → 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;

+ 4 - 4
src/main/java/cn/iocoder/dashboard/modules/msg/convert/sms/SmsTemplateConvert.java → 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;

+ 3 - 3
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsChannelMapper.java → 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;

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsLogMapper.java → 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;
 

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/dao/sms/SmsTemplateMapper.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsChannelDO.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsLog.java → 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;

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/dal/mysql/daoobject/sms/SmsTemplateDO.java → 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;

+ 6 - 4
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值一致。");
 
 }

+ 6 - 6
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsChannelService.java → 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;
 

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsLogService.java → 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接口

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/SmsTemplateService.java → 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接口

+ 12 - 20
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsChannelServiceImpl.java → 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;
     }

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsLogServiceImpl.java → 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;
 
 /**

+ 2 - 2
src/main/java/cn/iocoder/dashboard/modules/msg/service/sms/impl/SmsTemplateServiceImpl.java → 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;
 
 /**

+ 34 - 0
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<SmsChannelAllVO> smsChannelAllVOList = channelService.listChannelAllEnabledInfo();
+        Map<Long, SmsClient<?>> channelId2SmsClientMap = SmsSenderUtils.init(smsChannelAllVOList);
+        return new SmsClientAdapter(channelId2SmsClientMap);
+    }
+
+}

+ 143 - 0
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<Long, SmsClient<?>> smsSenderMap = new ConcurrentHashMap<>(8);
+
+    /**
+     * 短信模板code: 短信渠道id map
+     * key: templateCode
+     * val: channelId
+     */
+    private static final Map<String, Long> templateCode2ChannelIdMap = new HashMap<>();
+
+    /**
+     * 将短信渠道信息初始化成短信客户端
+     *
+     * @param smsChannelAllVOList 短信渠道信息
+     * @return 短信渠道id:短信客户端map
+     */
+    public synchronized static Map<Long, SmsClient<?>> init(List<SmsChannelAllVO> 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<SmsChannelAllVO> smsChannelAllVOList) {
+        smsSenderMap.clear();
+        smsClientAdapter.flushClient(init(smsChannelAllVOList));
+    }
+
+    /**
+     * 发送短信
+     *
+     * @param smsClientAdapter 短信客户端适配器
+     * @param smsBody          短信内容
+     * @param targetPhones     对象手机集合
+     * @return 短信发送结果
+     */
+    public static SmsResult<?> send(SmsClientAdapter smsClientAdapter, SmsBody smsBody, Collection<String> 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<SmsChannelAllVO> 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<SmsTemplateVO> 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);
+    }
+}

+ 12 - 7
src/main/java/cn/iocoder/dashboard/framework/msg/sms/impl/ali/AliSmsSender.java → 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<SendSmsResponse> {
+public class AliSmsClient implements SmsClient<SendSmsResponse> {
 
     private static final String OK = "OK";
 
@@ -42,7 +42,7 @@ public class AliSmsSender implements SmsSender<SendSmsResponse> {
      *
      * @param channelVO 阿里云短信配置
      */
-    public AliSmsSender(SmsChannelAllVO channelVO) {
+    public AliSmsClient(SmsChannelAllVO channelVO) {
 
         this.channelVO = channelVO;
 
@@ -83,4 +83,9 @@ public class AliSmsSender implements SmsSender<SendSmsResponse> {
         return failResult();
     }
 
+    @Override
+    public SmsResult<SendSmsResponse> sendAsync(SmsBody msgBody, Collection<String> targets) {
+        return null;
+    }
+
 }

+ 48 - 0
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<R> implements SmsClient<R> {
+
+    private final SmsClient<R> smsClient;
+
+    @Override
+    public SmsResult<R> send(SmsBody msgBody, Collection<String> targets) {
+        log.debug("ready send sms, body: {}, target: {}", JsonUtils.toJsonString(msgBody), targets);
+
+        SmsResult<R> 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<R> sendAsync(SmsBody msgBody, Collection<String> targets) {
+        return send(msgBody, targets);
+    }
+
+    public SmsClientLogProxy(SmsClient<R> smsClient) {
+        this.smsClient = smsClient;
+    }
+}