重构短信功能
parent
df8bda53e8
commit
37c39365ec
@ -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,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 cn.iocoder.dashboard.util.json.JsonUtils;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -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;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -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.CommonResult;
|
||||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||||
import cn.iocoder.dashboard.modules.msg.service.sms.SmsChannelService;
|
import cn.iocoder.dashboard.modules.system.service.sms.SmsChannelService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.validation.annotation.Validated;
|
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.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
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.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
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.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
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.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
@ -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 io.swagger.annotations.ApiModel;
|
||||||
import lombok.Data;
|
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 cn.iocoder.dashboard.common.pojo.PageParam;
|
||||||
import io.swagger.annotations.ApiModel;
|
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.enums.SmsChannelEnum;
|
||||||
import cn.iocoder.dashboard.common.pojo.PageResult;
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||||
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import org.mapstruct.Mapper;
|
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.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsTemplateVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||||
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.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
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.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
|
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.system.controller.sms.vo.req.SmsChannelPageReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
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 com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
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.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.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
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 cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
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 com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
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 cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
@ -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.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.SmsChannelAllVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelCreateReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.req.SmsChannelPageReqVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
|
||||||
import cn.iocoder.dashboard.modules.msg.dal.mysql.daoobject.sms.SmsChannelDO;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.sms.SmsChannelDO;
|
||||||
|
|
||||||
import java.util.List;
|
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接口
|
* 短信渠道Service接口
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.dashboard.modules.msg.service.sms;
|
package cn.iocoder.dashboard.modules.system.service.sms;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信渠道Service接口
|
* 短信渠道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.SmsLogService;
|
import cn.iocoder.dashboard.modules.system.service.sms.SmsLogService;
|
||||||
import org.springframework.stereotype.Service;
|
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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue