mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 10:18:42 +08:00 
			
		
		
		
	重构短信功能
This commit is contained in:
		| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -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)); | ||||
|     } | ||||
| } | ||||
| @@ -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(); | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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,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
									
								
								src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/main/java/cn/iocoder/dashboard/framework/sms/SmsClient.java
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
|     } | ||||
| } | ||||
| @@ -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,4 +1,4 @@ | ||||
| package cn.iocoder.dashboard.framework.msg.sms; | ||||
| package cn.iocoder.dashboard.framework.sms; | ||||
| 
 | ||||
| import lombok.Data; | ||||
| 
 | ||||
| @@ -1,6 +0,0 @@ | ||||
| /** | ||||
|  * msg 包,专门专门用于发送消息的功能,支撑上层的通用与核心业务。 | ||||
|  * 例如说:短信、邮件、app通知等等 | ||||
|  * | ||||
|  */ | ||||
| package cn.iocoder.dashboard.modules.msg; | ||||
| @@ -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,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,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,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,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,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,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,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; | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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,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,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,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; | ||||
| @@ -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值一致。"); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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,4 +1,4 @@ | ||||
| package cn.iocoder.dashboard.modules.msg.service.sms; | ||||
| package cn.iocoder.dashboard.modules.system.service.sms; | ||||
| 
 | ||||
| /** | ||||
|  * 短信渠道Service接口 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cn.iocoder.dashboard.modules.msg.service.sms; | ||||
| package cn.iocoder.dashboard.modules.system.service.sms; | ||||
| 
 | ||||
| /** | ||||
|  * 短信渠道Service接口 | ||||
| @@ -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; | ||||
|     } | ||||
| @@ -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; | ||||
| 
 | ||||
| /** | ||||
| @@ -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; | ||||
| 
 | ||||
| /** | ||||
| @@ -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); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 zengzefeng
					zengzefeng