短信提交 2021-03-28,增加发送日志

pull/2/head
YunaiV 2021-03-28 22:49:14 +08:00
parent 46ed64ba40
commit 515fca5c41
34 changed files with 579 additions and 965 deletions

View File

@ -46,6 +46,7 @@
<easyexcel.verion>2.2.7</easyexcel.verion> <easyexcel.verion>2.2.7</easyexcel.verion>
<velocity.version>2.2</velocity.version> <velocity.version>2.2</velocity.version>
<screw.version>1.0.5</screw.version> <screw.version>1.0.5</screw.version>
<!-- 三方云服务相关 -->
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
@ -271,6 +272,8 @@
<version>${screw.version}</version> <version>${screw.version}</version>
</dependency> </dependency>
<!-- 三方云服务相关 -->
<!-- SMS SDK begin --> <!-- SMS SDK begin -->
<dependency> <dependency>
<groupId>com.yunpian.sdk</groupId> <groupId>com.yunpian.sdk</groupId>

View File

@ -1,67 +0,0 @@
package cn.iocoder.dashboard.framework.sms.client;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import lombok.extern.slf4j.Slf4j;
/**
*
*
* @author zzf
* @date 2021/2/1 9:28
*/
@Slf4j
public abstract class AbstractSmsClient implements SmsClient {
/**
*
*/
protected final SmsChannelProperty channelVO;
/**
*
*
* @param property
*/
public AbstractSmsClient(SmsChannelProperty property) {
this.channelVO = property;
}
public SmsChannelProperty getProperty() {
return channelVO;
}
@Override
public final SmsResult send(String templateApiId, SmsBody smsBody, String target) {
SmsResult result;
try {
beforeSend(templateApiId, smsBody, target);
result = doSend(templateApiId, smsBody, target);
afterSend(templateApiId, smsBody, target, result);
} catch (Exception e) {
// exception handle
log.debug(e.getMessage(), e);
return SmsResult.failResult("发送异常: " + e.getMessage());
}
return result;
}
/**
*
*
* @param templateApiId
* @param smsBody
* @param targetPhone
* @return
* @throws Exception
*/
protected abstract SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception;
protected void beforeSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception {
}
protected void afterSend(String templateApiId, SmsBody smsBody, String targetPhone, SmsResult result) throws Exception {
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.dashboard.framework.sms.config;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.client.impl.SmsClientFactoryImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*
* @author
*/
@Configuration
public class SmsConfiguration {
@Bean
public SmsClientFactory smsClientFactory() {
return new SmsClientFactoryImpl();
}
}

View File

@ -1,38 +0,0 @@
package cn.iocoder.dashboard.framework.sms.core;
import cn.iocoder.dashboard.util.json.JsonUtils;
import lombok.Data;
import java.util.Map;
/**
*
*/
@Data
public class SmsBody {
/**
* id
*/
private Long smsLogId;
/**
*
*/
private String templateCode;
/**
*
*/
private String templateContent;
/**
*
*/
private Map<String, String> params;
public String getParamsStr() {
return JsonUtils.toJsonString(params);
}
}

View File

@ -1,133 +0,0 @@
package cn.iocoder.dashboard.framework.sms.core;
import cn.iocoder.dashboard.common.exception.ServiceException;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.client.impl.ali.AliyunSmsClient;
import cn.iocoder.dashboard.framework.sms.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty;
import cn.iocoder.dashboard.util.json.JsonUtils;
import org.springframework.stereotype.Component;
import javax.servlet.ServletRequest;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
/**
*
*
* @author zzf
* @date 2021/1/28 14:01
*/
@Component
public class SmsClientFactory {
/**
* channelId: client map
* id: map
*/
private final Map<Long, AbstractSmsClient> smsSenderMap = new ConcurrentHashMap<>(8);
/**
* templateCode: TemplateProperty map
* map
*/
private final Map<String, SmsTemplateProperty> templatePropertyMap = new ConcurrentHashMap<>(16);
/**
*
*
* @param propertyVO
* @return id(channelId)
*/
public Long createClient(SmsChannelProperty propertyVO) {
AbstractSmsClient sender = createClient(SmsChannelEnum.getByCode(propertyVO.getCode()), propertyVO);
smsSenderMap.put(propertyVO.getId(), sender);
return propertyVO.getId();
}
private AbstractSmsClient createClient(SmsChannelEnum channelEnum, SmsChannelProperty channelVO) {
if (channelEnum == null) {
throw new ServiceException(INVALID_CHANNEL_CODE);
}
switch (channelEnum) {
case ALIYUN:
return new AliyunSmsClient(channelVO);
case YUN_PIAN:
return new YunpianSmsClient(channelVO);
// TODO fill more channel
default:
break;
}
throw new ServiceException(SMS_SENDER_NOT_FOUND);
}
/**
*
*
* @param channelId id
* @return id
*/
public AbstractSmsClient getClient(Long channelId) {
return smsSenderMap.get(channelId);
}
/**
*
*/
public void addOrUpdateTemplateCache(Collection<SmsTemplateProperty> templateProperties) {
templateProperties.forEach(this::addOrUpdateTemplateCache);
}
/**
*
*/
public void addOrUpdateTemplateCache(SmsTemplateProperty templateProperty) {
templatePropertyMap.put(templateProperty.getCode(), templateProperty);
}
/**
*
*
* @param templateCode
* @return id
*/
public String getTemplateApiIdByCode(String templateCode) {
SmsTemplateProperty smsTemplateProperty = templatePropertyMap.get(templateCode);
if (smsTemplateProperty == null) {
throw new ServiceException(SMS_TEMPLATE_NOT_EXISTS);
}
return smsTemplateProperty.getApiTemplateId();
}
/**
* send_lodapiId
*
* @param callbackRequest
* @return
*/
public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) {
for (Long channelId : smsSenderMap.keySet()) {
AbstractSmsClient smsClient = smsSenderMap.get(channelId);
try {
SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest);
if (smsSendResult != null) {
return smsSendResult;
}
} catch (Exception ignored) {
}
}
throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: "
+ JsonUtils.toJsonString(callbackRequest.getParameterMap()));
}
}

View File

@ -15,4 +15,5 @@ public interface SmsConstants {
String COMMA = ","; String COMMA = ",";
String SUCCESS = "SUCCESS"; String SUCCESS = "SUCCESS";
} }

View File

@ -1,7 +1,8 @@
package cn.iocoder.dashboard.framework.sms.core; package cn.iocoder.dashboard.framework.sms.core;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable; import java.io.Serializable;
@ -9,33 +10,64 @@ import java.io.Serializable;
* *
*/ */
@Data @Data
@Accessors(chain = true)
public class SmsResult implements Serializable { public class SmsResult implements Serializable {
/** /**
* () *
*
* API
*/ */
private Boolean success; private Boolean success;
/**
*
*
* {@link SmsSendFailureTypeEnum#getType()}
*/
private Integer sendFailureType;
/**
*
*
* 使 {@link SmsSendFailureTypeEnum#getMsg()}
* Exception
*/
private String sendFailureMsg;
/** /**
* * API
*
* 使 String
*/ */
private String apiId; private String apiSendCode;
/** /**
* * API
*/ */
private String code; private String apiSendMsg;
/** /**
* * API ID
*
* API
*/ */
private String message; private String apiRequestId;
/**
* API
*
* API
*/
private String apiSerialNo;
public static SmsResult failResult(String message) { private SmsResult() {
SmsResult resultBody = new SmsResult();
resultBody.setSuccess(false);
resultBody.setMessage(message);
return resultBody;
} }
public static SmsResult success(SmsSendFailureTypeEnum sendFailureType,
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
return new SmsResult().setSuccess(true).setSendFailureType(sendFailureType.getType()).setSendFailureMsg(sendFailureType.getMsg())
.setApiSendCode(apiSendCode).setApiSendMsg(apiSendMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo);
}
public static SmsResult error(Throwable ex) {
return new SmsResult().setSuccess(false)
.setSendFailureType(SmsSendFailureTypeEnum.SMS_SEND_EXCEPTION.getType())
.setSendFailureMsg(ExceptionUtil.getRootCauseMessage(ex));
}
} }

View File

@ -1,28 +1,36 @@
package cn.iocoder.dashboard.framework.sms.client; package cn.iocoder.dashboard.framework.sms.core.client;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import java.util.Map;
/** /**
* *
* *
* @author zzf * @author zzf
* @date 2021/1/25 14:14 * @date 2021/1/25 14:14
*/ */
public interface SmsClient { public interface SmsClient {
/**
*
*
* @return
*/
Long getId();
/** /**
* *
* *
* @param templateApiId * @param sendLogId
* @param smsBody * @param mobile
* @param targets * @param apiTemplateId API
* @param templateParams
* @return * @return
*/ */
SmsResult send(String templateApiId, SmsBody smsBody, String targets); SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams);
// TODO FROM 芋艿 to ZZF是不是可以改成意图更明确的解析返回结果例如说 parseXXXX // TODO FROM 芋艿 to ZZF是不是可以改成意图更明确的解析返回结果例如说 parseXXXX
/** /**

View File

@ -0,0 +1,28 @@
package cn.iocoder.dashboard.framework.sms.core.client;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
/**
*
*
* @author zzf
* @date 2021/1/28 14:01
*/
public interface SmsClientFactory {
/**
* Client
*
* @param channelId
* @return Client
*/
SmsClient getSmsClient(Long channelId);
/**
* Client
*
* @param properties
*/
void createOrUpdateSmsClient(SmsChannelProperties properties);
}

View File

@ -0,0 +1,89 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl;
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
*
*
* @author zzf
* @date 2021/2/1 9:28
*/
@Slf4j
public abstract class AbstractSmsClient implements SmsClient {
/**
*
*/
protected volatile SmsChannelProperties properties;
/**
*
*
* @param properties
*/
public AbstractSmsClient(SmsChannelProperties properties) {
this.properties = properties;
}
/**
*
*/
public final void init() {
doInit();
log.info("[init][配置({}) 初始化完成]", properties);
}
public final void refresh(SmsChannelProperties properties) {
// 判断是否更新
if (!properties.equals(this.properties)) {
return;
}
log.info("[refresh][配置({})发生变化,重新初始化]", properties);
this.properties = properties;
// 初始化
this.init();
}
/**
*
*/
protected abstract void doInit();
@Override
public Long getId() {
return properties.getId();
}
@Override
public final SmsResult send(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams) {
SmsResult result;
try {
result = doSend(sendLogId, mobile, apiTemplateId, templateParams);
} catch (Throwable ex) {
// 打印异常日志
log.error("[send][发送短信异常sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
sendLogId, mobile, apiTemplateId, templateParams, ex);
// 封装返回
return SmsResult.error(ex);
}
return result;
}
/**
*
*
* @param sendLogId
* @param mobile
* @param apiTemplateId API
* @param templateParams
* @return
*/
protected abstract SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams)
throws Throwable;
}

View File

@ -0,0 +1,83 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
*
*
* @author zzf
*/
@Validated
@Slf4j
public class SmsClientFactoryImpl implements SmsClientFactory {
/**
* Map
* key使 {@link SmsChannelProperties#getId()}
*/
private final Map<Long, AbstractSmsClient> clients = new ConcurrentHashMap<>();
@Override
public SmsClient getSmsClient(Long channelId) {
return clients.get(channelId);
}
@Override
public void createOrUpdateSmsClient(SmsChannelProperties properties) {
AbstractSmsClient client = clients.get(properties.getId());
if (client == null) {
client = this.createSmsClient(properties);
clients.put(client.getId(), client);
} else {
client.refresh(properties);
}
}
private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
// 创建客户端
switch (channelEnum) {
case ALIYUN:
return new AliyunSmsClient(properties);
case YUN_PIAN:
return new YunpianSmsClient(properties);
}
// 创建失败,错误日志 + 抛出异常
log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
}
// /**
// * 从短信发送回调函数请求中获取用于唯一确定一条send_lod的apiId
// *
// * @param callbackRequest 短信发送回调函数请求
// * @return 第三方平台短信唯一标识
// */
// public SmsResultDetail getSmsResultDetailFromCallbackQuery(ServletRequest callbackRequest) {
// for (Long channelId : clients.keySet()) {
// AbstractSmsClient smsClient = clients.get(channelId);
// try {
// SmsResultDetail smsSendResult = smsClient.smsSendCallbackHandle(callbackRequest);
// if (smsSendResult != null) {
// return smsSendResult;
// }
// } catch (Exception ignored) {
// }
// }
// throw new IllegalArgumentException("getSmsResultDetailFromCallbackQuery fail! don't match SmsClient by RequestParam: "
// + JsonUtils.toJsonString(callbackRequest.getParameterMap()));
// }
}

View File

@ -1,19 +1,15 @@
package cn.iocoder.dashboard.framework.sms.client.impl.ali; package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.util.json.JsonUtils; import cn.iocoder.dashboard.util.json.JsonUtils;
import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient; import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile; import com.aliyuncs.profile.IClientProfile;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
@ -28,7 +24,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* *
* *
* @author zzf * @author zzf
* @date 2021/1/25 14:17 * @date 2021/1/25 14:17
@ -36,54 +32,54 @@ import java.util.Map;
@Slf4j @Slf4j
public class AliyunSmsClient extends AbstractSmsClient { public class AliyunSmsClient extends AbstractSmsClient {
private static final String OK = "OK";
private static final String PRODUCT = "Dystopi"; private static final String PRODUCT = "Dystopi";
private static final String DOMAIN = "dysmsapi.aliyuncs.com"; private static final String DOMAIN = "dysmsapi.aliyuncs.com";
private static final String ENDPOINT = "cn-hangzhou"; private static final String ENDPOINT = "cn-hangzhou";
private final IAcsClient acsClient; private static final String OK = "OK";
/** /**
* *
*
* @param channelVO
*/ */
public AliyunSmsClient(SmsChannelProperty channelVO) { private volatile IAcsClient acsClient;
super(channelVO);
String accessKeyId = channelVO.getApiKey(); public AliyunSmsClient(SmsChannelProperties properties) {
String accessKeySecret = channelVO.getApiSecret(); super(properties);
}
IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, accessKeyId, accessKeySecret); @Override
protected void doInit() {
IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN); DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN);
acsClient = new DefaultAcsClient(profile); acsClient = new DefaultAcsClient(profile);
} }
@Override @Override
public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception { protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams) throws Exception {
SendSmsRequest request = new SendSmsRequest(); return null;
request.setSysMethod(MethodType.POST);
request.setPhoneNumbers(targetPhone);
request.setSignName(channelVO.getApiSignatureId());
request.setTemplateCode(templateApiId);
request.setTemplateParam(smsBody.getParamsStr());
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
boolean success = OK.equals(sendSmsResponse.getCode());
if (!success) {
log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
}
return new SmsResult()
.setSuccess(success)
.setMessage(sendSmsResponse.getMessage())
.setCode(sendSmsResponse.getCode())
.setApiId(sendSmsResponse.getBizId());
} }
// @Override
// public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) throws Exception {
// SendSmsRequest request = new SendSmsRequest();
// request.setSysMethod(MethodType.POST);
// request.setPhoneNumbers(targetPhone);
// request.setSignName(properties.getSignature());
// request.setTemplateCode(templateApiId);
// request.setTemplateParam(smsBody.getParamsStr());
// SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
//
// boolean success = OK.equals(sendSmsResponse.getCode());
// if (!success) {
// log.debug("send fail[code={}, message={}]", sendSmsResponse.getCode(), sendSmsResponse.getMessage());
// }
// return new SmsResult()
// .setSuccess(success)
// .setMessage(sendSmsResponse.getMessage())
// .setCode(sendSmsResponse.getCode())
// .setApiId(sendSmsResponse.getBizId());
// }
/** /**
* [{ * [{
* "send_time" : "2017-08-30 00:00:00", * "send_time" : "2017-08-30 00:00:00",
@ -131,8 +127,8 @@ public class AliyunSmsClient extends AbstractSmsClient {
public Integer getSendStatus() { public Integer getSendStatus() {
return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS)) return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS))
? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() ? SysSmsSendStatusEnum.SUCCESS.getStatus()
: SysSmsSendStatusEnum.SEND_FAIL.getStatus(); : SysSmsSendStatusEnum.FAILURE.getStatus();
} }
public String getBizId() { public String getBizId() {

View File

@ -1,19 +1,20 @@
package cn.iocoder.dashboard.framework.sms.client.impl.yunpian; package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.CharsetUtil;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.hutool.core.util.URLUtil;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsConstants; import cn.iocoder.dashboard.framework.sms.core.SmsConstants;
import cn.iocoder.dashboard.framework.sms.core.SmsResult; import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.util.json.JsonUtils; import cn.iocoder.dashboard.util.json.JsonUtils;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.yunpian.sdk.YunpianClient; import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.constant.Code;
import com.yunpian.sdk.constant.YunpianConstant; import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result; import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend; import com.yunpian.sdk.model.SmsSingleSend;
@ -25,9 +26,10 @@ import java.net.URLEncoder;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringJoiner;
/** /**
* *
* *
* @author zzf * @author zzf
* @date 9:48 2021/3/5 * @date 9:48 2021/3/5
@ -35,71 +37,59 @@ import java.util.Map;
@Slf4j @Slf4j
public class YunpianSmsClient extends AbstractSmsClient { public class YunpianSmsClient extends AbstractSmsClient {
private final YunpianClient client; /**
*
*/
private volatile YunpianClient client;
private final TypeReference<List<Map<String, String>>> callbackType = new TypeReference<List<Map<String, String>>>() { private final TypeReference<List<Map<String, String>>> callbackType = new TypeReference<List<Map<String, String>>>() {
}; };
/** public YunpianSmsClient(SmsChannelProperties properties) {
* super(properties);
*
* @param channelVO
*/
public YunpianSmsClient(SmsChannelProperty channelVO) {
super(channelVO);
client = new YunpianClient(channelVO.getApiKey());
} }
@Override @Override
public SmsResult doSend(String templateApiId, SmsBody smsBody, String targetPhone) { public void doInit() {
Map<String, String> paramMap = new HashMap<>(); client = new YunpianClient(properties.getApiKey());
paramMap.put(YunpianConstant.APIKEY, getProperty().getApiKey()); }
paramMap.put(YunpianConstant.MOBILE, String.join(SmsConstants.COMMA, targetPhone));
paramMap.put(YunpianConstant.TEXT, formatContent(smsBody));
paramMap.put(Helper.CALLBACK, getProperty().getCallbackUrl());
Result<SmsSingleSend> sendResult = client.sms().single_send(paramMap); @Override
boolean success = sendResult.getCode().equals(Code.OK); protected SmsResult doSend(Long sendLogId, String mobile, String apiTemplateId, Map<String, Object> templateParams) throws Throwable {
// 构建参数
Map<String, String> request = new HashMap<>();
request.put(YunpianConstant.APIKEY, properties.getApiKey());
request.put(YunpianConstant.MOBILE, mobile);
request.put(YunpianConstant.TPL_ID, apiTemplateId);
request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams));
request.put(YunpianConstant.UID, String.valueOf(sendLogId));
request.put(Helper.CALLBACK, properties.getCallbackUrl());
if (!success) { // 执行发送
log.debug("send fail[code={}, message={}]", sendResult.getCode(), sendResult.getDetail()); Result<SmsSingleSend> sendResult = client.sms().tpl_single_send(request);
if (sendResult.getThrowable() != null) {
throw sendResult.getThrowable();
} }
return new SmsResult() // 解析结果
.setSuccess(success) SmsSingleSend data = sendResult.getData();
.setMessage(sendResult.getDetail()) return SmsResult.success(parseSendFailureType(sendResult), // 将 API 短信平台,解析成统一的错误码
.setCode(sendResult.getCode().toString()) String.valueOf(data.getCode()), data.getMsg(), null, String.valueOf(data.getSid()));
.setApiId(sendResult.getData().getSid().toString());
} }
private static String formatTplValue(Map<String, Object> templateParams) {
/** if (CollUtil.isEmpty(templateParams)) {
* return "";
* }
* @param smsBody // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化
* @return StringJoiner joiner = new StringJoiner("&");
*/ templateParams.forEach((key, value) -> joiner.add(String.format("#%s#=%s", key, URLUtil.encode(String.valueOf(value)))));
private String formatContent(SmsBody smsBody) { return joiner.toString();
StringBuilder result = new StringBuilder(smsBody.getTemplateContent());
smsBody.getParams().forEach((key, val) -> {
String param = parseParamToPlaceholder(key);
result.replace(result.indexOf(param), result.indexOf(param + param.length()), val);
});
return result.toString();
} }
/** private static SmsSendFailureTypeEnum parseSendFailureType(Result<SmsSingleSend> sendResult) {
* return SmsSendFailureTypeEnum.SMS_UNKNOWN;
* <p>
* #param#
*
* @param key
* @return
*/
private String parseParamToPlaceholder(String key) {
return SmsConstants.JING_HAO + key + SmsConstants.JING_HAO;
} }
/** /**
* *
*/ */
@ -109,7 +99,6 @@ public class YunpianSmsClient extends AbstractSmsClient {
return Helper.getSmsResultDetailByParam(map); return Helper.getSmsResultDetailByParam(map);
} }
/** /**
* request * request
* *
@ -155,8 +144,8 @@ public class YunpianSmsClient extends AbstractSmsClient {
private static int getSendStatus(Map<String, String> map) { private static int getSendStatus(Map<String, String> map) {
String reportStatus = map.get(REPORT_STATUS); String reportStatus = map.get(REPORT_STATUS);
return SmsConstants.SUCCESS.equals(reportStatus) return SmsConstants.SUCCESS.equals(reportStatus)
? SysSmsSendStatusEnum.SEND_SUCCESS.getStatus() ? SysSmsSendStatusEnum.SUCCESS.getStatus()
: SysSmsSendStatusEnum.SEND_FAIL.getStatus(); : SysSmsSendStatusEnum.FAILURE.getStatus();
} }
public static SmsResultDetail getSmsResultDetailByParam(Map<String, String> map) { public static SmsResultDetail getSmsResultDetailByParam(Map<String, String> map) {

View File

@ -13,14 +13,23 @@ import lombok.Getter;
public enum SmsSendFailureTypeEnum { public enum SmsSendFailureTypeEnum {
// ========== 模板相关(100 开头) ========== // ========== 模板相关(100 开头) ==========
SMS_TEMPLATE_DISABLE(100), // 短信模板被禁用 SMS_CHANNEL_CLIENT_NOT_EXISTS(100, "短信渠道的客户端不存在"),
// ========== 其它相关 ========== // ========== 模板相关(200 开头) ==========
SMS_TEMPLATE_DISABLE(200, "短信模板被禁用"),
// ========== 其它相关(900 开头) ==========
SMS_SEND_EXCEPTION(900, "发送异常"),
SMS_UNKNOWN(999, "未知错误,需要解析")
; ;
/** /**
* *
*/ */
private final int type; private final int type;
/**
*
*/
private final String msg;
} }

View File

@ -0,0 +1,52 @@
package cn.iocoder.dashboard.framework.sms.core.property;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import lombok.Data;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
*
*
* @author zzf
* @date 2021/1/25 17:01
*/
@Data
@Validated
public class SmsChannelProperties {
/**
*
*/
@NotNull(message = "短信渠道 ID 不能为空")
private Long id;
/**
*
*/
@NotEmpty(message = "短信签名不能为空")
private String signature;
/**
*
*
* {@link SmsChannelEnum}
*/
@NotEmpty(message = "渠道编码不能为空")
private String code;
/**
* API
*/
@NotEmpty(message = "短信 API 的账号不能为空")
private String apiKey;
/**
* API
*/
@NotEmpty(message = "短信 API 的秘钥不能为空")
private String apiSecret;
/**
* URL
*/
private String callbackUrl;
}

View File

@ -1,68 +0,0 @@
package cn.iocoder.dashboard.framework.sms.core.property;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;
/**
* ()VO
*
* @author zzf
* @date 2021/1/25 17:01
*/
@Data
@EqualsAndHashCode
public class SmsChannelProperty implements Serializable {
/**
* id
*/
@NotNull(message = "短信渠道ID不能为空")
private Long id;
/**
* ( )
*/
@NotEmpty(message = "短信渠道编码不能为空")
private String code;
/**
* id
*/
@NotEmpty(message = "渠道账号id不能为空")
private String apiKey;
/**
*
*/
@NotEmpty(message = "渠道账号秘钥不能为空")
private String apiSecret;
/**
*
*/
@NotEmpty(message = "实际渠道签名唯一标识不能为空")
private String apiSignatureId;
/**
*
*/
@NotEmpty(message = "签名值不能为空")
private String signature;
/**
* 0 1
*/
@NotNull(message = "是否拥有回调函数不能为空")
private Integer hadCallback;
/**
* url
*/
private String callbackUrl;
}

View File

@ -1,47 +0,0 @@
package cn.iocoder.dashboard.framework.sms.core.property;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotEmpty;
/**
* VO
*
* @author zzf
* @date 2021/1/25 17:03
*/
@Data
@EqualsAndHashCode
public class SmsTemplateProperty {
/**
* id
*/
@NotEmpty(message = "短信渠道编码不能为空")
private Long channelId;
/**
* (, )
*/
private String bizCode;
/**
*
*/
@NotEmpty(message = "短信模板编码不能为空")
private String code;
/**
*
*/
@NotEmpty(message = "短信模板唯一标识不能为空")
private String apiTemplateId;
/**
*
*/
@NotEmpty(message = "短信模板内容不能为空")
private String content;
}

View File

@ -15,9 +15,6 @@ import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class SmsChannelPageReqVO extends PageParam { public class SmsChannelPageReqVO extends PageParam {
@ApiModelProperty(value = "渠道名", example = "阿里", notes = "模糊匹配")
private String name;
@ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配") @ApiModelProperty(value = "签名值", example = "源码", notes = "模糊匹配")
private String signature; private String signature;

View File

@ -1,16 +1,13 @@
package cn.iocoder.dashboard.modules.system.convert.sms; package cn.iocoder.dashboard.modules.system.convert.sms;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO; import cn.iocoder.dashboard.modules.system.controller.user.vo.user.SysUserUpdateReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
@ -20,9 +17,6 @@ public interface SmsChannelConvert {
SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class); SmsChannelConvert INSTANCE = Mappers.getMapper(SmsChannelConvert.class);
@Mapping(source = "records", target = "list")
PageResult<SysSmsChannelDO> convertPage(IPage<SysSmsChannelDO> page);
SysSmsChannelDO convert(SmsChannelCreateReqVO bean); SysSmsChannelDO convert(SmsChannelCreateReqVO bean);
SysSmsChannelDO convert(SysUserUpdateReqVO bean); SysSmsChannelDO convert(SysUserUpdateReqVO bean);
@ -31,9 +25,8 @@ public interface SmsChannelConvert {
List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean); List<SmsChannelAllVO> convert(List<SysSmsChannelDO> bean);
List<SmsChannelProperty> convertProperty(List<SmsChannelAllVO> list); List<SmsChannelProperties> convertProperty(List<SmsChannelAllVO> list);
List<SmsChannelProperty> convertProperties(List<SysSmsChannelDO> list);
List<SmsChannelProperties> convertList(List<SysSmsChannelDO> list);
} }

View File

@ -1,7 +1,6 @@
package cn.iocoder.dashboard.modules.system.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.framework.sms.core.property.SmsTemplateProperty;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsTemplateVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
@ -24,6 +23,4 @@ public interface SmsTemplateConvert {
SmsTemplateVO convert(SysSmsTemplateDO bean); SmsTemplateVO convert(SysSmsTemplateDO bean);
List<SmsTemplateProperty> convertProperty(List<SysSmsTemplateDO> bean);
} }

View File

@ -1,70 +1,58 @@
package cn.iocoder.dashboard.modules.system.dal.dataobject.sms; package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* *
* *
* @author zzf * @author zzf
* @since 2021-01-25 * @since 2021-01-25
*/ */
@TableName(value = "sms_channel", autoResultMap = true)
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName(value = "sms_channel", autoResultMap = true)
public class SysSmsChannelDO extends BaseDO { public class SysSmsChannelDO extends BaseDO {
/** /**
* *
*/ */
private Long id; private Long id;
/** /**
* ( ) *
*/
private String code;
/**
* url
*/
private String callback_url;
/**
* id
*/
private String apiKey;
/**
*
*/
private String apiSecret;
/**
*
*/
private String apiSignatureId;
/**
*
*/
private String name;
/**
*
*/ */
private String signature; private String signature;
/**
*
*
* {@link SmsChannelEnum}
*/
private String code;
/**
*
*
* {@link CommonStatusEnum}
*/
private Integer status;
/** /**
* *
*/ */
private String remark; private String remark;
/** /**
* 0 1 * API
*/ */
private Integer status; private String apiKey;
/**
* API
*/
private String apiSecret;
/**
* URL
*/
private String callbackUrl;
} }

View File

@ -105,16 +105,23 @@ public class SysSmsSendLogDO extends BaseDO {
* {@link SysSmsSendStatusEnum} * {@link SysSmsSendStatusEnum}
*/ */
private Integer sendStatus; private Integer sendStatus;
/**
*
*/
private Date sendTime;
/** /**
* *
* *
* {@link SmsSendFailureTypeEnum} * {@link SmsSendFailureTypeEnum#getType()}
*/ */
private Integer sendFailureType; private Integer sendFailureType;
/** /**
* *
*
* 使 {@link SmsSendFailureTypeEnum#getMsg()}
* Exception
*/ */
private Date sendTime; private String sendFailureMsg;
/** /**
* API * API
* *

View File

@ -1,66 +0,0 @@
package cn.iocoder.dashboard.modules.system.dal.dataobject.sms;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
*
*
* @author zzf
* @since 2021-01-25
*/
@Data
@EqualsAndHashCode
@Accessors(chain = true)
@TableName(value = "sms_send_log", autoResultMap = true)
public class SysSmsSendLogDOX implements Serializable {
/**
*
*/
private Long id;
/**
* ()
*/
private String channelCode;
/**
* id
*/
private Long channelId;
/**
* id
*/
private String templateCode;
/**
*
*/
private String phone;
/**
*
*/
private String remark;
/**
*
*
* @see SysSmsSendStatusEnum
*/
private Integer sendStatus;
/**
*
*/
private Date sendTime;
}

View File

@ -1,31 +1,27 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.sms; package cn.iocoder.dashboard.modules.system.dal.mysql.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.pojo.PageResult;
import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@Mapper @Mapper
public interface SysSmsChannelMapper extends BaseMapper<SysSmsChannelDO> { public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> {
default IPage<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) { default PageResult<SysSmsChannelDO> selectChannelPage(SmsChannelPageReqVO reqVO) {
return selectPage(MyBatisUtils.buildPage(reqVO), new LambdaQueryWrapper<SysSmsChannelDO>() return selectPage(reqVO, new LambdaQueryWrapper<SysSmsChannelDO>()
.like(StrUtil.isNotBlank(reqVO.getName()), SysSmsChannelDO::getName, reqVO.getName()) .like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getSignature, reqVO.getSignature()));
.like(StrUtil.isNotBlank(reqVO.getSignature()), SysSmsChannelDO::getName, reqVO.getSignature())
);
} }
default List<SysSmsChannelDO> selectEnabledList() { default List<SysSmsChannelDO> selectListByStatus(Integer status) {
return selectList(new LambdaQueryWrapper<SysSmsChannelDO>() return selectList(new LambdaQueryWrapper<SysSmsChannelDO>()
.eq(SysSmsChannelDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) .eq(SysSmsChannelDO::getStatus, status)
.orderByAsc(SysSmsChannelDO::getId) .orderByAsc(SysSmsChannelDO::getId));
);
} }
} }

View File

@ -1,34 +0,0 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
import cn.iocoder.dashboard.common.enums.DefaultBitFieldEnum;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface SysSmsQueryLogMapper extends BaseMapper<SysSmsSendLogDO> {
/**
*
*/
default List<SysSmsSendLogDO> selectNoResultQueryLogList() {
return this.selectList(new LambdaQueryWrapper<SysSmsSendLogDO>()
.eq(SysSmsSendLogDO::getSendStatus, SysSmsSendStatusEnum.QUERY_SUCCESS)
.eq(SysSmsSendLogDO::getGotResult, DefaultBitFieldEnum.NO)
);
}
/**
* APIId
*/
default boolean updateByApiId(SysSmsSendLogDO queryLogDO, String apiId) {
return update(queryLogDO, new LambdaQueryWrapper<SysSmsSendLogDO>()
.eq(SysSmsSendLogDO::getApiId, apiId)
) > 0;
}
}

View File

@ -1,10 +1,9 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.sms; package cn.iocoder.dashboard.modules.system.dal.mysql.sms;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface SysSmsSendLogMapper extends BaseMapper<SysSmsSendLogDO> { public interface SysSmsSendLogMapper extends BaseMapperX<SysSmsSendLogDO> {
} }

View File

@ -1,17 +1,9 @@
package cn.iocoder.dashboard.modules.system.mq.consumer.sms; package cn.iocoder.dashboard.modules.system.mq.consumer.sms;
import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener; import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
import cn.iocoder.dashboard.util.json.JsonUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -26,24 +18,9 @@ import javax.annotation.Resource;
@Slf4j @Slf4j
public class SmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> { public class SmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> {
@Resource
private SysSmsChannelService smsChannelService;
@Resource
private SysSmsQueryLogService smsQueryLogService;
@Resource @Resource
private SysSmsService smsService; private SysSmsService smsService;
@Override
public void onMessage(ObjectRecord<String, SmsSendMessage> record) {
AbstractSmsClient smsClient = smsChannelService.getSmsClient(body.getTemplateCode());
String templateApiId = smsChannelService.getSmsTemplateApiIdByCode(body.getTemplateCode());
SmsResult result = smsClient.send(templateApiId, body, message.getTargetPhone());
smsQueryLogService.afterSendLog(body.getSmsLogId(), result);
}
@Override @Override
public void onMessage(SysSmsSendMessage message) { public void onMessage(SysSmsSendMessage message) {
log.info("[onMessage][消息内容({})]", message); log.info("[onMessage][消息内容({})]", message);

View File

@ -1,8 +1,6 @@
package cn.iocoder.dashboard.modules.system.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.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelPageReqVO; 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.controller.sms.vo.resp.SmsChannelEnumRespVO;
@ -46,26 +44,4 @@ public interface SysSmsChannelService {
*/ */
List<SmsChannelEnumRespVO> getSmsChannelEnums(); List<SmsChannelEnumRespVO> getSmsChannelEnums();
/**
*
*
* @param templateCode
* @return
*/
AbstractSmsClient getSmsClient(String templateCode);
/**
*
*
* @param templateCode
* @return
*/
String getSmsTemplateApiIdByCode(String templateCode);
/**
* ()
*
* @return ()
*/
List<SmsChannelAllVO> listSmsChannelAllEnabledInfo();
} }

View File

@ -1,35 +0,0 @@
package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
/**
*
*
* @author zzf
* @date 2021/1/25 9:24
*/
public interface SysSmsQueryLogService {
/**
*
*
* @param smsBody
* @param targetPhone
* @param client
* @return id
*/
void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client);
/**
*
*
* @param logId id
* @param result
*/
void afterSendLog(Long logId, SmsResult result);
void updateSendLogByResultDetail(SmsResultDetail smsResultDetail);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.dashboard.modules.system.service.sms; package cn.iocoder.dashboard.modules.system.service.sms;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import java.util.Map; import java.util.Map;
@ -12,17 +13,38 @@ import java.util.Map;
*/ */
public interface SysSmsSendLogService { public interface SysSmsSendLogService {
/**
*
*
* @param mobile
* @param userId
* @param userType
* @param template
* @param templateContent
* @param templateParams
* @return
*/
Long createSmsSendLog(String mobile, Long userId, Integer userType, Long createSmsSendLog(String mobile, Long userId, Integer userType,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams); SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams);
/** /**
* *
* *
* @param id * @param id
* @param sendFailureType * @param success
* @param sendFailureType
* @param sendFailureMsg
* @param apiSendFailureType API
* @param apiSendFailureMsg API
* @param apiRequestId API ID
* @param apiSerialNo API
*/ */
void updateSmsSendLogFailure(Long id, Integer sendFailureType); void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo);
void getAndSaveSmsSendLog(); default void updateSmsSendLogFailure(Long id, SmsSendFailureTypeEnum sendFailureType) {
updateSmsSendLogResult(id, false, sendFailureType.getType(), sendFailureType.getMsg(),
null, null, null, null);
}
} }

View File

@ -1,32 +1,24 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl; package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.hutool.core.util.ObjectUtil; import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
import cn.iocoder.dashboard.common.pojo.PageResult; import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient; import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty; import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.framework.sms.core.property.SmsTemplateProperty;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.SmsChannelAllVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.req.SmsChannelCreateReqVO; 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.req.SmsChannelPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.sms.vo.resp.SmsChannelEnumRespVO; 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.SmsChannelConvert;
import cn.iocoder.dashboard.modules.system.convert.sms.SmsTemplateConvert;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsTemplateMapper;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsChannelMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Service * Service
@ -37,10 +29,8 @@ import java.util.concurrent.ConcurrentHashMap;
@Service @Service
public class SysSmsChannelServiceImpl implements SysSmsChannelService { public class SysSmsChannelServiceImpl implements SysSmsChannelService {
private final Map<String, Long> templateCode2ChannelIdMap = new ConcurrentHashMap<>(32);
@Resource @Resource
private SmsClientFactory clientFactory; private SmsClientFactory smsClientFactory;
@Resource @Resource
private SysSmsChannelMapper channelMapper; private SysSmsChannelMapper channelMapper;
@ -48,30 +38,19 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
@Resource @Resource
private SysSmsTemplateMapper templateMapper; private SysSmsTemplateMapper templateMapper;
@PostConstruct
@Override @Override
@PostConstruct
public void initSmsClientAndCacheSmsTemplate() { public void initSmsClientAndCacheSmsTemplate() {
// 查询有效渠道信息 // 查询有效渠道信息
List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList(); List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
List<SmsChannelProperty> propertyList = SmsChannelConvert.INSTANCE.convertProperties(channelDOList); // 创建渠道 Client
List<SmsChannelProperties> propertiesList = SmsChannelConvert.INSTANCE.convertList(channelDOList);
// 遍历渠道生成client、获取模板并缓存 propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));
propertyList.forEach(channelProperty -> {
List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(channelProperty.getId());
if (ObjectUtil.isNotEmpty(templateDOList)) {
Long clientId = clientFactory.createClient(channelProperty);
templateDOList.forEach(template -> templateCode2ChannelIdMap.put(template.getCode(), clientId));
List<SmsTemplateProperty> templatePropertyList = SmsTemplateConvert.INSTANCE.convertProperty(templateDOList);
clientFactory.addOrUpdateTemplateCache(templatePropertyList);
}
});
} }
@Override @Override
public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) { public PageResult<SysSmsChannelDO> pageSmsChannels(SmsChannelPageReqVO reqVO) {
return SmsChannelConvert.INSTANCE.convertPage(channelMapper.selectChannelPage(reqVO)); return channelMapper.selectChannelPage(reqVO);
} }
@Override @Override
@ -86,30 +65,20 @@ public class SysSmsChannelServiceImpl implements SysSmsChannelService {
return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values())); return SmsChannelConvert.INSTANCE.convertEnum(Arrays.asList(SmsChannelEnum.values()));
} }
@Override // @Override
public AbstractSmsClient getSmsClient(String templateCode) { // public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() {
return clientFactory.getClient(templateCode2ChannelIdMap.get(templateCode)); // List<SysSmsChannelDO> channelDOList = channelMapper.selectListByStatus();
} // if (ObjectUtil.isNull(channelDOList)) {
// return null;
@Override // }
public String getSmsTemplateApiIdByCode(String templateCode) { // List<SmsChannelAllVO> channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList);
return clientFactory.getTemplateApiIdByCode(templateCode); // channelAllVOList.forEach(smsChannelDO -> {
} // List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
// if (ObjectUtil.isNull(templateDOList)) {
@Override // templateDOList = new ArrayList<>();
public List<SmsChannelAllVO> listSmsChannelAllEnabledInfo() { // }
List<SysSmsChannelDO> channelDOList = channelMapper.selectEnabledList(); // smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList));
if (ObjectUtil.isNull(channelDOList)) { // });
return null; // return channelAllVOList;
} // }
List<SmsChannelAllVO> channelAllVOList = SmsChannelConvert.INSTANCE.convert(channelDOList);
channelAllVOList.forEach(smsChannelDO -> {
List<SysSmsTemplateDO> templateDOList = templateMapper.selectListByChannelId(smsChannelDO.getId());
if (ObjectUtil.isNull(templateDOList)) {
templateDOList = new ArrayList<>();
}
smsChannelDO.setTemplateList(SmsTemplateConvert.INSTANCE.convert(templateDOList));
});
return channelAllVOList;
}
} }

View File

@ -1,63 +0,0 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.SmsBody;
import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperty;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.sms.SysSmsQueryLogMapper;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsQueryLogService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
*
*
* @author zzf
* @date 13:50 2021/3/2
*/
@Service
public class SysSmsQueryLogServiceImpl implements SysSmsQueryLogService {
@Resource
private SysSmsQueryLogMapper logMapper;
@Override
public void beforeSendLog(SmsBody smsBody, String targetPhone, AbstractSmsClient client) {
SysSmsSendLogDO smsLog = new SysSmsSendLogDO();
SmsChannelProperty property = client.getProperty();
smsLog.setChannelCode(property.getCode())
.setChannelId(property.getId())
.setTemplateCode(smsBody.getTemplateCode())
.setPhone(targetPhone)
.setContent(smsBody.getParams().toString());
smsLog.setSendStatus(SysSmsSendStatusEnum.ASYNC.getStatus());
logMapper.insert(smsLog);
smsBody.setSmsLogId(smsLog.getId());
}
@Override
public void afterSendLog(Long logId, SmsResult result) {
SysSmsSendLogDO smsLog = new SysSmsSendLogDO();
smsLog.setId(logId);
smsLog.setApiId(result.getApiId());
smsLog.setSendStatus(SysSmsSendStatusEnum.QUERY_FAIL.getStatus());
smsLog.setRemark(result.getCode() + ": " + result.getMessage());
logMapper.updateById(smsLog);
}
@Override
public void updateSendLogByResultDetail(SmsResultDetail smsResultDetail) {
SysSmsSendLogDO queryLogDO = new SysSmsSendLogDO();
queryLogDO.setSendStatus(smsResultDetail.getSendStatus());
queryLogDO.setSendTime(smsResultDetail.getSendTime());
queryLogDO.setRemark(smsResultDetail.getMessage());
logMapper.updateByApiId(queryLogDO, smsResultDetail.getApiId());
}
}

View File

@ -1,22 +1,17 @@
package cn.iocoder.dashboard.modules.system.service.sms.impl; package cn.iocoder.dashboard.modules.system.service.sms.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.dashboard.framework.sms.client.AbstractSmsClient;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsSendLogDOX;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsQueryLogMapper;
import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper; import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsSendLogMapper;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum; import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Objects;
/** /**
* *
@ -28,20 +23,9 @@ import java.util.Map;
@Service @Service
public class SysSmsSendLogServiceImpl implements SysSmsSendLogService { public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
@Resource
private SysSmsQueryLogMapper smsQueryLogMapper;
@Resource @Resource
private SysSmsSendLogMapper smsSendLogMapper; private SysSmsSendLogMapper smsSendLogMapper;
@Resource
private SysSmsChannelService smsChannelService;
/**
* {@link #getSmsSendResultJob()}
*/
private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;
@Override @Override
public Long createSmsSendLog(String mobile, Long userId, Integer userType, public Long createSmsSendLog(String mobile, Long userId, Integer userType,
SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) { SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
@ -61,71 +45,12 @@ public class SysSmsSendLogServiceImpl implements SysSmsSendLogService {
} }
@Override @Override
public void updateSmsSendLogFailure(Long id, Integer sendFailureType) { public void updateSmsSendLogResult(Long id, Boolean success, Integer sendFailureType, String sendFailureMsg,
smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendFailureType(sendFailureType)); String apiSendFailureType, String apiSendFailureMsg, String apiRequestId, String apiSerialNo) {
SysSmsSendStatusEnum sendStatus = Objects.equals(success, true) ? SysSmsSendStatusEnum.SUCCESS : SysSmsSendStatusEnum.FAILURE;
smsSendLogMapper.updateById(new SysSmsSendLogDO().setId(id).setSendStatus(sendStatus.getStatus()).setSendTime(new Date())
.setSendFailureType(sendFailureType).setSendFailureMsg(sendFailureMsg)
.setApiSendFailureType(apiSendFailureType).setApiSendFailureMsg(apiSendFailureMsg).setApiRequestId(apiRequestId).setApiSerialNo(apiSerialNo));
} }
@Override
public void getAndSaveSmsSendLog() {
List<SysSmsSendLogDO> noResultQueryLogList = smsQueryLogMapper.selectNoResultQueryLogList();
if (CollectionUtil.isEmpty(noResultQueryLogList)) {
return;
}
//用于添加的发送日志对象
SysSmsSendLogDOX insertSendLog = new SysSmsSendLogDOX();
//用于修改状态的请求日志对象
SysSmsSendLogDO updateQueryLog = new SysSmsSendLogDO();
noResultQueryLogList.forEach(queryLog -> {
AbstractSmsClient smsClient = smsChannelService.getSmsClient(queryLog.getTemplateCode());
updateQueryLog.setId(queryLog.getId());
// 只处理实现了获取发送结果方法的短信客户端,理论上这里都是满足条件的,以防万一加个判断。
/*if (smsClient instanceof NeedQuerySendResultSmsClient) {
//初始化点字段值
queryLog2SendLong(insertSendLog, queryLog);
NeedQuerySendResultSmsClient querySendResultSmsClient = (NeedQuerySendResultSmsClient) smsClient;
try {
List<SmsResultDetail> smsSendResult = querySendResultSmsClient.getSmsSendResult(queryLog.getRemark());
smsSendResult.forEach(resultDetail -> {
insertSendLog.setPhone(resultDetail.getPhone());
insertSendLog.setSendStatus(resultDetail.getSendStatus());
insertSendLog.setSendTime(resultDetail.getSendTime());
insertSendLog.setRemark(resultDetail.getMessage());
smsSendLogMapper.insert(insertSendLog);
});
} catch (Exception e) {
//exception handle
log.error("query send result fail, exception: " + e.getMessage());
updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus());
updateQueryLog.setRemark(e.getMessage());
smsQueryLogMapper.updateById(updateQueryLog);
return;
}
} else {
//理论上这里都是满足条件的,以防万一加个判断。
updateQueryLog.setSendStatus(SmsSendStatusEnum.QUERY_SEND_FAIL.getStatus());
smsQueryLogMapper.updateById(updateQueryLog);
}*/
updateQueryLog.setSendStatus(SysSmsSendStatusEnum.SEND_SUCCESS.getStatus());
updateQueryLog.setRemark(String.format("日志(id = %s)对应的客户端没有继承NeedQuerySendResultSmsClient, 不能获取短信结果。", queryLog.getId()));
smsQueryLogMapper.updateById(updateQueryLog);
});
}
private void queryLog2SendLong(SysSmsSendLogDOX insertSendLog, SysSmsSendLogDO queryLog) {
insertSendLog.setChannelCode(queryLog.getChannelCode());
insertSendLog.setChannelId(queryLog.getChannelId());
insertSendLog.setTemplateCode(queryLog.getTemplateCode());
}
@Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
public void getSmsSendResultJob() {
getAndSaveSmsSendLog();
}
} }

View File

@ -4,15 +4,19 @@ import cn.hutool.core.collection.CollUtil;
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.common.enums.UserTypeEnum; import cn.iocoder.dashboard.common.enums.UserTypeEnum;
import cn.iocoder.dashboard.framework.sms.core.SmsClientFactory; import cn.iocoder.dashboard.framework.sms.core.SmsResult;
import cn.iocoder.dashboard.framework.sms.core.SmsResultDetail; import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum; import cn.iocoder.dashboard.framework.sms.core.enums.SmsSendFailureTypeEnum;
import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO; import cn.iocoder.dashboard.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage; import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer; import cn.iocoder.dashboard.modules.system.mq.producer.sms.SysSmsProducer;
import cn.iocoder.dashboard.modules.system.service.sms.*; import cn.iocoder.dashboard.modules.system.service.sms.SysSmsSendLogService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsService;
import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
import cn.iocoder.dashboard.modules.system.service.user.SysUserService; import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -31,29 +35,21 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
* @date 2021/1/25 9:25 * @date 2021/1/25 9:25
*/ */
@Service @Service
@Slf4j
public class SysSmsServiceImpl implements SysSmsService { public class SysSmsServiceImpl implements SysSmsService {
@Resource @Resource
private SysSmsTemplateService smsTemplateService; private SysSmsTemplateService smsTemplateService;
@Resource @Resource
private SysSmsSendLogService smsSendLogService; private SysSmsSendLogService smsSendLogService;
@Resource
private SysSmsProducer smsProducer;
@Resource
private SmsClientFactory smsClientFactory;
@Resource @Resource
private SysUserService userService; private SysUserService userService;
@Resource
private SysSmsChannelService channelService;
@Resource
private SysSmsQueryLogService logService;
@Resource
private SysSmsProducer smsProducer;
@Resource
private SmsClientFactory smsClientFactory;
@Override @Override
public void sendSingleSms(String mobile, Long userId, Integer userType, public void sendSingleSms(String mobile, Long userId, Integer userType,
String templateCode, Map<String, Object> templateParams) { String templateCode, Map<String, Object> templateParams) {
@ -68,7 +64,7 @@ public class SysSmsServiceImpl implements SysSmsService {
// 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。 // 如果模板被禁用,则直接标记发送失败。也就说,不发短信,嘿嘿。
if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) { if (CommonStatusEnum.DISABLE.getStatus().equals(template.getStatus())) {
smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE.getType()); smsSendLogService.updateSmsSendLogFailure(sendLogId, SmsSendFailureTypeEnum.SMS_TEMPLATE_DISABLE);
return; return;
} }
// 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台 // 如果模板未禁用,发送 MQ 消息。目的是,异步化调用短信平台
@ -126,19 +122,31 @@ public class SysSmsServiceImpl implements SysSmsService {
SysUserDO user = userService.getUser(userId); SysUserDO user = userService.getUser(userId);
return user != null ? user.getMobile() : null; return user != null ? user.getMobile() : null;
} }
// TODO 芋艿:支持 C 端用户
return null; return null;
} }
@Override @Override
public void doSendSms(SysSmsSendMessage message) { public void doSendSms(SysSmsSendMessage message) {
// 获得渠道对应的 SmsClient 客户端
SmsClient smsClient = smsClientFactory.getSmsClient(message.getChannelId());
if (smsClient == null) {
log.error("[doSendSms][短信 message({}) 找不到对应的客户端]", message);
smsSendLogService.updateSmsSendLogFailure(message.getSendLogId(), SmsSendFailureTypeEnum.SMS_CHANNEL_CLIENT_NOT_EXISTS);
return;
}
// 发送短信
SmsResult sendResult = smsClient.send(message.getSendLogId(), message.getMobile(),
message.getApiTemplateId(), message.getTemplateParams());
} }
@Override @Override
public Object smsSendCallbackHandle(ServletRequest request) { public Object smsSendCallbackHandle(ServletRequest request) {
SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request); // SmsResultDetail smsResultDetail = smsClientFactory.getSmsResultDetailFromCallbackQuery(request);
logService.updateSendLogByResultDetail(smsResultDetail); // logService.updateSendLogByResultDetail(smsResultDetail);
return smsResultDetail.getCallbackResponseBody(); // return smsResultDetail.getCallbackResponseBody();
return null;
} }
} }