sms:移除 SmsCodeMapping + SmsCommonResult,简化短信的封装
parent
4118f25d75
commit
562f82580e
|
@ -31,8 +31,8 @@ public interface SmsClient {
|
||||||
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
|
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
|
||||||
* @return 短信发送结果
|
* @return 短信发送结果
|
||||||
*/
|
*/
|
||||||
SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId,
|
SmsSendRespDTO sendSms(Long logId, String mobile, String apiTemplateId,
|
||||||
List<KeyValue<String, Object>> templateParams);
|
List<KeyValue<String, Object>> templateParams) throws Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析接收短信的接收结果
|
* 解析接收短信的接收结果
|
||||||
|
@ -49,6 +49,6 @@ public interface SmsClient {
|
||||||
* @param apiTemplateId 短信 API 的模板编号
|
* @param apiTemplateId 短信 API 的模板编号
|
||||||
* @return 短信模板
|
* @return 短信模板
|
||||||
*/
|
*/
|
||||||
SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId);
|
SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将 API 的错误码,转换为通用的错误码
|
|
||||||
*
|
|
||||||
* @see SmsCommonResult
|
|
||||||
* @see SmsFrameworkErrorCodeConstants
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface SmsCodeMapping extends Function<String, ErrorCode> {
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client;
|
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 短信的 CommonResult 拓展类
|
|
||||||
*
|
|
||||||
* 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
|
|
||||||
*
|
|
||||||
* 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class SmsCommonResult<T> extends CommonResult<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API 返回错误码
|
|
||||||
*
|
|
||||||
* 由于第三方的错误码可能是字符串,所以使用 String 类型
|
|
||||||
*/
|
|
||||||
private String apiCode;
|
|
||||||
/**
|
|
||||||
* API 返回提示
|
|
||||||
*/
|
|
||||||
private String apiMsg;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API 请求编号
|
|
||||||
*/
|
|
||||||
private String apiRequestId;
|
|
||||||
|
|
||||||
private SmsCommonResult() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> SmsCommonResult<T> build(String apiCode, String apiMsg, String apiRequestId,
|
|
||||||
T data, SmsCodeMapping codeMapping) {
|
|
||||||
Assert.notNull(codeMapping, "参数 codeMapping 不能为空");
|
|
||||||
SmsCommonResult<T> result = new SmsCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId);
|
|
||||||
result.setData(data);
|
|
||||||
// 翻译错误码
|
|
||||||
if (codeMapping != null) {
|
|
||||||
ErrorCode errorCode = codeMapping.apply(apiCode);
|
|
||||||
if (errorCode == null) {
|
|
||||||
errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
|
|
||||||
}
|
|
||||||
result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> SmsCommonResult<T> error(Throwable ex) {
|
|
||||||
SmsCommonResult<T> result = new SmsCommonResult<>();
|
|
||||||
result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode());
|
|
||||||
result.setMsg(ExceptionUtil.getRootCauseMessage(ex));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -10,9 +10,34 @@ import lombok.Data;
|
||||||
@Data
|
@Data
|
||||||
public class SmsSendRespDTO {
|
public class SmsSendRespDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否成功
|
||||||
|
*/
|
||||||
|
private Boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 请求编号
|
||||||
|
*/
|
||||||
|
private String apiRequestId;
|
||||||
|
|
||||||
|
// ==================== 成功时字段 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信 API 发送返回的序号
|
* 短信 API 发送返回的序号
|
||||||
*/
|
*/
|
||||||
private String serialNo;
|
private String serialNo;
|
||||||
|
|
||||||
|
// ==================== 失败时字段 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API 返回错误码
|
||||||
|
*
|
||||||
|
* 由于第三方的错误码可能是字符串,所以使用 String 类型
|
||||||
|
*/
|
||||||
|
private String apiCode;
|
||||||
|
/**
|
||||||
|
* API 返回提示
|
||||||
|
*/
|
||||||
|
private String apiMsg;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,9 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl;
|
package cn.iocoder.yudao.framework.sms.core.client.impl;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信客户端的抽象类,提供模板方法,减少子类的冗余代码
|
* 短信客户端的抽象类,提供模板方法,减少子类的冗余代码
|
||||||
*
|
*
|
||||||
|
@ -25,14 +17,9 @@ public abstract class AbstractSmsClient implements SmsClient {
|
||||||
* 短信渠道配置
|
* 短信渠道配置
|
||||||
*/
|
*/
|
||||||
protected volatile SmsChannelProperties properties;
|
protected volatile SmsChannelProperties properties;
|
||||||
/**
|
|
||||||
* 错误码枚举类
|
|
||||||
*/
|
|
||||||
protected final SmsCodeMapping codeMapping;
|
|
||||||
|
|
||||||
public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) {
|
public AbstractSmsClient(SmsChannelProperties properties) {
|
||||||
this.properties = prepareProperties(properties);
|
this.properties = properties;
|
||||||
this.codeMapping = codeMapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,74 +41,13 @@ public abstract class AbstractSmsClient implements SmsClient {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("[refresh][配置({})发生变化,重新初始化]", properties);
|
log.info("[refresh][配置({})发生变化,重新初始化]", properties);
|
||||||
this.properties = prepareProperties(properties);
|
|
||||||
// 初始化
|
// 初始化
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 在赋值给{@link this#properties}前,子类可根据需要预处理短信渠道配置
|
|
||||||
*
|
|
||||||
* @param properties 数据库中存储的短信渠道配置
|
|
||||||
* @return 满足子类实现的短信渠道配置
|
|
||||||
*/
|
|
||||||
protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return properties.getId();
|
return properties.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile,
|
|
||||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
|
||||||
// 执行短信发送
|
|
||||||
SmsCommonResult<SmsSendRespDTO> result;
|
|
||||||
try {
|
|
||||||
result = doSendSms(logId, mobile, apiTemplateId, templateParams);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
// 打印异常日志
|
|
||||||
log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
|
|
||||||
logId, mobile, apiTemplateId, templateParams, ex);
|
|
||||||
// 封装返回
|
|
||||||
return SmsCommonResult.error(ex);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
|
|
||||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams)
|
|
||||||
throws Throwable;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
|
|
||||||
try {
|
|
||||||
return doParseSmsReceiveStatus(text);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId) {
|
|
||||||
// 执行短信发送
|
|
||||||
SmsCommonResult<SmsTemplateRespDTO> result;
|
|
||||||
try {
|
|
||||||
result = doGetSmsTemplate(apiTemplateId);
|
|
||||||
} catch (Throwable ex) {
|
|
||||||
// 打印异常日志
|
|
||||||
log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex);
|
|
||||||
// 封装返回
|
|
||||||
return SmsCommonResult.error(ex);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import com.aliyuncs.AcsRequest;
|
|
||||||
import com.aliyuncs.AcsResponse;
|
|
||||||
import com.aliyuncs.DefaultAcsClient;
|
import com.aliyuncs.DefaultAcsClient;
|
||||||
import com.aliyuncs.IAcsClient;
|
import com.aliyuncs.IAcsClient;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
|
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
|
||||||
|
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
||||||
import com.aliyuncs.exceptions.ClientException;
|
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
||||||
import com.aliyuncs.profile.DefaultProfile;
|
import com.aliyuncs.profile.DefaultProfile;
|
||||||
import com.aliyuncs.profile.IClientProfile;
|
import com.aliyuncs.profile.IClientProfile;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
@ -31,9 +27,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
||||||
|
|
||||||
|
@ -46,6 +41,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AliyunSmsClient extends AbstractSmsClient {
|
public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用成功 code
|
||||||
|
*/
|
||||||
|
public static final String API_CODE_SUCCESS = "OK";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* REGION, 使用杭州
|
* REGION, 使用杭州
|
||||||
*/
|
*/
|
||||||
|
@ -57,7 +57,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
private volatile IAcsClient client;
|
private volatile IAcsClient client;
|
||||||
|
|
||||||
public AliyunSmsClient(SmsChannelProperties properties) {
|
public AliyunSmsClient(SmsChannelProperties properties) {
|
||||||
super(properties, new AliyunSmsCodeMapping());
|
super(properties);
|
||||||
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
||||||
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,9 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
|
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
|
||||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
|
List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||||
// 构建参数
|
// 构建请求
|
||||||
SendSmsRequest request = new SendSmsRequest();
|
SendSmsRequest request = new SendSmsRequest();
|
||||||
request.setPhoneNumbers(mobile);
|
request.setPhoneNumbers(mobile);
|
||||||
request.setSignName(properties.getSignature());
|
request.setSignName(properties.getSignature());
|
||||||
|
@ -79,34 +79,32 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
|
request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
|
||||||
request.setOutId(String.valueOf(sendLogId));
|
request.setOutId(String.valueOf(sendLogId));
|
||||||
// 执行请求
|
// 执行请求
|
||||||
return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId()));
|
SendSmsResponse response = client.getAcsResponse(request);
|
||||||
|
return new SmsSendRespDTO().setSuccess(Objects.equals(response.getCode(), API_CODE_SUCCESS)).setSerialNo(response.getBizId())
|
||||||
|
.setApiRequestId(response.getRequestId()).setApiCode(response.getCode()).setApiMsg(response.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
|
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||||
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
|
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
|
||||||
return statuses.stream().map(status -> {
|
return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(status.getSuccess())
|
||||||
SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
|
.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg())
|
||||||
resp.setSuccess(status.getSuccess());
|
.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime())
|
||||||
resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg());
|
.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())));
|
||||||
resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime());
|
|
||||||
resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()));
|
|
||||||
return resp;
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
|
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
|
||||||
// 构建参数
|
// 构建请求
|
||||||
QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
|
QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
|
||||||
request.setTemplateCode(apiTemplateId);
|
request.setTemplateCode(apiTemplateId);
|
||||||
// 执行请求
|
// 执行请求
|
||||||
return invoke(request, response -> {
|
QuerySmsTemplateResponse response = client.getAcsResponse(request);
|
||||||
SmsTemplateRespDTO data = new SmsTemplateRespDTO();
|
if (response.getTemplateStatus() == null) {
|
||||||
data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
|
return null;
|
||||||
data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
|
}
|
||||||
return data;
|
return new SmsTemplateRespDTO().setId(response.getTemplateCode()).setContent(response.getTemplateContent())
|
||||||
});
|
.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -119,37 +117,10 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
<T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) {
|
|
||||||
try {
|
|
||||||
// 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射
|
|
||||||
T sendResult = client.getAcsResponse(request);
|
|
||||||
String code = (String) ReflectUtil.getFieldValue(sendResult, "code");
|
|
||||||
String message = (String) ReflectUtil.getFieldValue(sendResult, "message");
|
|
||||||
String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId");
|
|
||||||
// 解析结果
|
|
||||||
R data = null;
|
|
||||||
if (Objects.equals(code, "OK")) { // 请求成功的情况下
|
|
||||||
data = responseConsumer.apply(sendResult);
|
|
||||||
}
|
|
||||||
// 拼接结果
|
|
||||||
return SmsCommonResult.build(code, message, requestId, data, codeMapping);
|
|
||||||
} catch (ClientException ex) {
|
|
||||||
return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatResultMsg(ClientException ex) {
|
|
||||||
if (StrUtil.isEmpty(ex.getErrorDescription())) {
|
|
||||||
return ex.getErrMsg();
|
|
||||||
}
|
|
||||||
return ex.getErrMsg() + " => " + ex.getErrorDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 短信接收状态
|
* 短信接收状态
|
||||||
*
|
*
|
||||||
* 参见 https://help.aliyun.com/document_detail/101867.html 文档
|
* 参见 <a href="https://help.aliyun.com/document_detail/101867.html">文档</a>
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 阿里云的 SmsCodeMapping 实现类
|
|
||||||
*
|
|
||||||
* 参见 https://help.aliyun.com/document_detail/101346.htm 文档
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public class AliyunSmsCodeMapping implements SmsCodeMapping {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ErrorCode apply(String apiCode) {
|
|
||||||
switch (apiCode) {
|
|
||||||
case "OK": return GlobalErrorCodeConstants.SUCCESS;
|
|
||||||
case "isv.ACCOUNT_NOT_EXISTS":
|
|
||||||
case "isv.ACCOUNT_ABNORMAL":
|
|
||||||
case "MissingAccessKeyId": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;
|
|
||||||
case "isp.RAM_PERMISSION_DENY": return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;
|
|
||||||
case "isv.INVALID_JSON_PARAM":
|
|
||||||
case "isv.INVALID_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
|
|
||||||
case "isv.BUSINESS_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;
|
|
||||||
case "isv.DAY_LIMIT_CONTROL": return SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL;
|
|
||||||
case "isv.SMS_CONTENT_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;
|
|
||||||
case "isv.SMS_TEMPLATE_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;
|
|
||||||
case "isv.SMS_SIGNATURE_ILLEGAL":
|
|
||||||
case "isv.SIGN_NAME_ILLEGAL":
|
|
||||||
case "isv.SMS_SIGN_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;
|
|
||||||
case "isv.AMOUNT_NOT_ENOUGH":
|
|
||||||
case "isv.OUT_OF_SERVICE": return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;
|
|
||||||
case "isv.MOBILE_NUMBER_ILLEGAL": return SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID;
|
|
||||||
case "isv.TEMPLATE_MISSING_PARAMETERS": return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;
|
|
||||||
default: return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.debug;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 钉钉的 SmsCodeMapping 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public class DebugDingTalkCodeMapping implements SmsCodeMapping {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ErrorCode apply(String apiCode) {
|
|
||||||
return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -8,19 +8,19 @@ import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
|
||||||
|
|
||||||
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.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于钉钉 WebHook 实现的调试的短信客户端实现类
|
* 基于钉钉 WebHook 实现的调试的短信客户端实现类
|
||||||
|
@ -32,7 +32,7 @@ import java.util.Map;
|
||||||
public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||||
|
|
||||||
public DebugDingTalkSmsClient(SmsChannelProperties properties) {
|
public DebugDingTalkSmsClient(SmsChannelProperties properties) {
|
||||||
super(properties, new DebugDingTalkCodeMapping());
|
super(properties);
|
||||||
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
||||||
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
|
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
|
||||||
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||||
// 构建请求
|
// 构建请求
|
||||||
String url = buildUrl("robot/send");
|
String url = buildUrl("robot/send");
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
@ -55,14 +55,15 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||||
String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
|
String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
|
||||||
// 解析结果
|
// 解析结果
|
||||||
Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
|
Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
|
||||||
return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"),
|
String errorCode = MapUtil.getStr(responseObj, "errcode");
|
||||||
null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping);
|
return new SmsSendRespDTO().setSuccess(Objects.equals(errorCode, "0")).setSerialNo(StrUtil.uuid())
|
||||||
|
.setApiCode(errorCode).setApiMsg(MapUtil.getStr(responseObj, "errorMsg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建请求地址
|
* 构建请求地址
|
||||||
*
|
*
|
||||||
* 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档
|
* 参见 <a href="https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71">文档</a>
|
||||||
*
|
*
|
||||||
* @param path 请求路径
|
* @param path 请求路径
|
||||||
* @return 请求地址
|
* @return 请求地址
|
||||||
|
@ -82,15 +83,14 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
|
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||||
throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
|
throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
|
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
|
||||||
SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
|
return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
|
||||||
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
|
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
|
||||||
return SmsCommonResult.build("0", "success", null, data, codeMapping);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
|
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯云短信配置实现类
|
|
||||||
* 腾讯云发送短信时,需要额外的参数 sdkAppId,
|
|
||||||
*
|
|
||||||
* @author shiwp
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class TencentSmsChannelProperties extends SmsChannelProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 应用 id
|
|
||||||
*/
|
|
||||||
private String sdkAppId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 考虑到不破坏原有的 apiKey + apiSecret 的结构,
|
|
||||||
* 所以腾讯云短信存储时,将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
|
|
||||||
* 因此在使用时,需要将 secretId 和 sdkAppId 解析出来,分别存储到对应字段中。
|
|
||||||
*/
|
|
||||||
public static TencentSmsChannelProperties build(SmsChannelProperties properties) {
|
|
||||||
if (properties instanceof TencentSmsChannelProperties) {
|
|
||||||
return (TencentSmsChannelProperties) properties;
|
|
||||||
}
|
|
||||||
TencentSmsChannelProperties result = BeanUtil.toBean(properties, TencentSmsChannelProperties.class);
|
|
||||||
String combineKey = properties.getApiKey();
|
|
||||||
Assert.notEmpty(combineKey, "apiKey 不能为空");
|
|
||||||
String[] keys = combineKey.trim().split(" ");
|
|
||||||
Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]");
|
|
||||||
Assert.notBlank(keys[0], "腾讯云短信 secretId 不能为空");
|
|
||||||
Assert.notBlank(keys[1], "腾讯云短信 sdkAppId 不能为空");
|
|
||||||
result.setSdkAppId(keys[1]).setApiKey(keys[0]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,9 +4,7 @@ import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
|
@ -17,23 +15,22 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.tencentcloudapi.common.Credential;
|
import com.tencentcloudapi.common.Credential;
|
||||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
|
||||||
import com.tencentcloudapi.sms.v20210111.SmsClient;
|
import com.tencentcloudapi.sms.v20210111.SmsClient;
|
||||||
import com.tencentcloudapi.sms.v20210111.models.*;
|
import com.tencentcloudapi.sms.v20210111.models.*;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.Objects;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 腾讯云短信功能实现
|
* 腾讯云短信功能实现
|
||||||
* <p>
|
*
|
||||||
* 参见 https://cloud.tencent.com/document/product/382/52077
|
* 参见 <a href="https://cloud.tencent.com/document/product/382/52077">文档</a>
|
||||||
*
|
*
|
||||||
* @author shiwp
|
* @author shiwp
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +39,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||||
/**
|
/**
|
||||||
* 调用成功 code
|
* 调用成功 code
|
||||||
*/
|
*/
|
||||||
public static final String API_SUCCESS_CODE = "Ok";
|
public static final String API_CODE_SUCCESS = "Ok";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* REGION,使用南京
|
* REGION,使用南京
|
||||||
|
@ -51,180 +48,103 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否国际/港澳台短信:
|
* 是否国际/港澳台短信:
|
||||||
|
*
|
||||||
* 0:表示国内短信。
|
* 0:表示国内短信。
|
||||||
* 1:表示国际/港澳台短信。
|
* 1:表示国际/港澳台短信。
|
||||||
*/
|
*/
|
||||||
private static final long INTERNATIONAL = 0L;
|
private static final long INTERNATIONAL_CHINA = 0L;
|
||||||
|
|
||||||
private SmsClient client;
|
private SmsClient client;
|
||||||
|
|
||||||
public TencentSmsClient(SmsChannelProperties properties) {
|
public TencentSmsClient(SmsChannelProperties properties) {
|
||||||
super(properties, new TencentSmsCodeMapping());
|
super(properties);
|
||||||
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
|
||||||
|
validateSdkAppId(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doInit() {
|
protected void doInit() {
|
||||||
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey
|
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey
|
||||||
Credential credential = new Credential(properties.getApiKey(), properties.getApiSecret());
|
Credential credential = new Credential(getApiKey(), properties.getApiSecret());
|
||||||
client = new SmsClient(credential, ENDPOINT);
|
client = new SmsClient(credential, ENDPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数校验腾讯云的 SDK AppId
|
||||||
|
*
|
||||||
|
* 原因是:腾讯云发放短信的时候,需要额外的参数 sdkAppId
|
||||||
|
*
|
||||||
|
* 解决方案:考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
|
||||||
|
*
|
||||||
|
* @param properties 配置
|
||||||
|
*/
|
||||||
|
private static void validateSdkAppId(SmsChannelProperties properties) {
|
||||||
|
String combineKey = properties.getApiKey();
|
||||||
|
Assert.notEmpty(combineKey, "apiKey 不能为空");
|
||||||
|
String[] keys = combineKey.trim().split(" ");
|
||||||
|
Assert.isTrue(keys.length == 2, "腾讯云短信 apiKey 配置格式错误,请配置 为[secretId sdkAppId]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSdkAppId() {
|
||||||
|
return StrUtil.subAfter(properties.getApiKey(), " ", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getApiKey() {
|
||||||
|
return StrUtil.subBefore(properties.getApiKey(), " ", true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId,
|
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
|
||||||
String mobile,
|
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
|
||||||
String apiTemplateId,
|
// 构建请求
|
||||||
List<KeyValue<String, Object>> templateParams) throws Throwable {
|
|
||||||
return invoke(() -> buildSendSmsRequest(sendLogId, mobile, apiTemplateId, templateParams),
|
|
||||||
this::doSendSms0,
|
|
||||||
response -> {
|
|
||||||
SendStatus sendStatus = response.getSendStatusSet()[0];
|
|
||||||
return SmsCommonResult.build(sendStatus.getCode(), sendStatus.getMessage(), response.getRequestId(),
|
|
||||||
new SmsSendRespDTO().setSerialNo(sendStatus.getSerialNo()), codeMapping);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯云发放短信的时候,需要额外的参数 sdkAppId。
|
|
||||||
* 考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
|
|
||||||
* 因此,这边需要使用 TencentSmsChannelProperties 做拆分,重新封装到 properties 内。
|
|
||||||
*
|
|
||||||
* @param properties 数据库中存储的短信渠道配置
|
|
||||||
* @return TencentSmsChannelProperties
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {
|
|
||||||
return TencentSmsChannelProperties.build(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用腾讯云 SDK 发送短信
|
|
||||||
*
|
|
||||||
* @param request 发送短信请求
|
|
||||||
* @return 发送短信响应
|
|
||||||
* @throws TencentCloudSDKException SDK 用来封装发送短信失败
|
|
||||||
*/
|
|
||||||
private SendSmsResponse doSendSms0(SendSmsRequest request) throws TencentCloudSDKException {
|
|
||||||
return client.SendSms(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 封装腾讯云发送短信请求
|
|
||||||
*
|
|
||||||
* @param sendLogId 日志编号
|
|
||||||
* @param mobile 手机号
|
|
||||||
* @param apiTemplateId 短信 API 的模板编号
|
|
||||||
* @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
|
|
||||||
* @return 腾讯云发送短信请求
|
|
||||||
*/
|
|
||||||
private SendSmsRequest buildSendSmsRequest(Long sendLogId,
|
|
||||||
String mobile,
|
|
||||||
String apiTemplateId,
|
|
||||||
List<KeyValue<String, Object>> templateParams) {
|
|
||||||
SendSmsRequest request = new SendSmsRequest();
|
SendSmsRequest request = new SendSmsRequest();
|
||||||
request.setSmsSdkAppId(((TencentSmsChannelProperties) properties).getSdkAppId());
|
request.setSmsSdkAppId(getSdkAppId());
|
||||||
request.setPhoneNumberSet(new String[]{mobile});
|
request.setPhoneNumberSet(new String[]{mobile});
|
||||||
request.setSignName(properties.getSignature());
|
request.setSignName(properties.getSignature());
|
||||||
request.setTemplateId(apiTemplateId);
|
request.setTemplateId(apiTemplateId);
|
||||||
request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
|
request.setTemplateParamSet(ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
|
||||||
request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId)));
|
request.setSessionContext(JsonUtils.toJsonString(new SessionContext().setLogId(sendLogId)));
|
||||||
return request;
|
// 执行请求
|
||||||
|
SendSmsResponse response = client.SendSms(request);
|
||||||
|
SendStatus status = response.getSendStatusSet()[0];
|
||||||
|
return new SmsSendRespDTO().setSuccess(Objects.equals(status.getCode(), API_CODE_SUCCESS)).setSerialNo(status.getSerialNo())
|
||||||
|
.setApiRequestId(response.getRequestId()).setApiCode(status.getCode()).setApiMsg(status.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
|
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||||
List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
|
List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
|
||||||
return CollectionUtils.convertList(callback, status -> {
|
return convertList(callback, status -> new SmsReceiveRespDTO()
|
||||||
SmsReceiveRespDTO data = new SmsReceiveRespDTO();
|
.setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()))
|
||||||
data.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription());
|
.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription())
|
||||||
data.setReceiveTime(status.getReceiveTime()).setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()));
|
.setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime())
|
||||||
data.setMobile(status.getMobile()).setSerialNo(status.getSerialNo());
|
.setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId()));
|
||||||
SessionContext context;
|
|
||||||
Long logId;
|
|
||||||
Assert.notNull(context = status.getSessionContext(), "回执信息中未解析出 context,请联系腾讯云小助手");
|
|
||||||
Assert.notNull(logId = context.getLogId(), "回执信息中未解析出 logId,请联系腾讯云小助手");
|
|
||||||
data.setLogId(logId);
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {
|
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
|
||||||
return invoke(() -> this.buildSmsTemplateStatusRequest(apiTemplateId),
|
// 构建请求
|
||||||
this::doGetSmsTemplate0,
|
DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
|
||||||
response -> {
|
request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
|
||||||
SmsTemplateRespDTO data = convertTemplateStatusDTO(response.getDescribeTemplateStatusSet()[0]);
|
request.setInternational(INTERNATIONAL_CHINA);
|
||||||
return SmsCommonResult.build(API_SUCCESS_CODE, null, response.getRequestId(), data, codeMapping);
|
// 执行请求
|
||||||
});
|
DescribeSmsTemplateListResponse response = client.DescribeSmsTemplateList(request);
|
||||||
|
DescribeTemplateListStatus status = response.getDescribeTemplateStatusSet()[0];
|
||||||
|
if (status == null || status.getStatusCode() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new SmsTemplateRespDTO().setId(status.getTemplateId().toString()).setContent(status.getTemplateContent())
|
||||||
|
.setAuditStatus(convertSmsTemplateAuditStatus(status.getStatusCode().intValue())).setAuditReason(status.getReviewReply());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SmsTemplateRespDTO convertTemplateStatusDTO(DescribeTemplateListStatus templateStatus) {
|
Integer convertSmsTemplateAuditStatus(int templateStatus) {
|
||||||
if (templateStatus == null) {
|
switch (templateStatus) {
|
||||||
return null;
|
case 1: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
|
||||||
|
case 0: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
|
||||||
|
case -1: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
|
||||||
|
default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
|
||||||
}
|
}
|
||||||
SmsTemplateAuditStatusEnum auditStatus;
|
|
||||||
Assert.notNull(templateStatus.getStatusCode(),
|
|
||||||
StrUtil.format("短信模版审核状态为 null,模版 id{}", templateStatus.getTemplateId()));
|
|
||||||
switch (templateStatus.getStatusCode().intValue()) {
|
|
||||||
case -1:
|
|
||||||
auditStatus = SmsTemplateAuditStatusEnum.FAIL;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
auditStatus = SmsTemplateAuditStatusEnum.SUCCESS;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
auditStatus = SmsTemplateAuditStatusEnum.CHECKING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException(StrUtil.format("不能解析短信模版审核状态{},模版 id{}",
|
|
||||||
templateStatus.getStatusCode(), templateStatus.getTemplateId()));
|
|
||||||
}
|
|
||||||
SmsTemplateRespDTO data = new SmsTemplateRespDTO();
|
|
||||||
data.setId(String.valueOf(templateStatus.getTemplateId())).setContent(templateStatus.getTemplateContent());
|
|
||||||
data.setAuditStatus(auditStatus.getStatus()).setAuditReason(templateStatus.getReviewReply());
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 封装查询模版审核状态请求
|
|
||||||
* @param apiTemplateId api 的模版 id
|
|
||||||
* @return 查询模版审核状态请求
|
|
||||||
*/
|
|
||||||
private DescribeSmsTemplateListRequest buildSmsTemplateStatusRequest(String apiTemplateId) {
|
|
||||||
DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
|
|
||||||
request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
|
|
||||||
// 地区 0:表示国内短信。1:表示国际/港澳台短信。
|
|
||||||
request.setInternational(INTERNATIONAL);
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用腾讯云 SDK 查询短信模版状态
|
|
||||||
*
|
|
||||||
* @param request 查询短信模版状态请求
|
|
||||||
* @return 查询短信模版状态响应
|
|
||||||
* @throws TencentCloudSDKException SDK 用来封装查询短信模版状态失败
|
|
||||||
*/
|
|
||||||
private DescribeSmsTemplateListResponse doGetSmsTemplate0(DescribeSmsTemplateListRequest request) throws TencentCloudSDKException {
|
|
||||||
return client.DescribeSmsTemplateList(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
<Q, P, R> SmsCommonResult<R> invoke(Supplier<Q> requestSupplier,
|
|
||||||
SdkFunction<Q, P> responseSupplier,
|
|
||||||
Function<P, SmsCommonResult<R>> resultGen) {
|
|
||||||
// 构建请求body
|
|
||||||
Q request = requestSupplier.get();
|
|
||||||
P response;
|
|
||||||
// 调用腾讯云发送短信
|
|
||||||
try {
|
|
||||||
response = responseSupplier.apply(request);
|
|
||||||
} catch (TencentCloudSDKException e) {
|
|
||||||
// 调用异常,封装结果
|
|
||||||
return SmsCommonResult.build(e.getErrorCode(), e.getMessage(), e.getRequestId(), null, codeMapping);
|
|
||||||
}
|
|
||||||
return resultGen.apply(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -278,7 +198,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||||
private String serialNo;
|
private String serialNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户的 session 内容(与发送接口的请求参数SessionContext一致)
|
* 用户的 session 内容(与发送接口的请求参数 SessionContext 一致)
|
||||||
*/
|
*/
|
||||||
@JsonProperty("ext")
|
@JsonProperty("ext")
|
||||||
private SessionContext sessionContext;
|
private SessionContext sessionContext;
|
||||||
|
@ -293,10 +213,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||||
* 发送短信记录id
|
* 发送短信记录id
|
||||||
*/
|
*/
|
||||||
private Long logId;
|
private Long logId;
|
||||||
}
|
|
||||||
|
|
||||||
private interface SdkFunction<T, R> {
|
|
||||||
R apply(T t) throws TencentCloudSDKException;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯云的 SmsCodeMapping 实现类
|
|
||||||
*
|
|
||||||
* 参见 https://cloud.tencent.com/document/api/382/52075#.E5.85.AC.E5.85.B1.E9.94.99.E8.AF.AF.E7.A0.81
|
|
||||||
*
|
|
||||||
* @author : shiwp
|
|
||||||
*/
|
|
||||||
public class TencentSmsCodeMapping implements SmsCodeMapping {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ErrorCode apply(String apiCode) {
|
|
||||||
switch (apiCode) {
|
|
||||||
case TencentSmsClient.API_SUCCESS_CODE: return GlobalErrorCodeConstants.SUCCESS;
|
|
||||||
case "FailedOperation.ContainSensitiveWord": return SMS_SEND_CONTENT_INVALID;
|
|
||||||
case "FailedOperation.JsonParseFail":
|
|
||||||
case "MissingParameter.EmptyPhoneNumberSet":
|
|
||||||
case "LimitExceeded.PhoneNumberCountLimit":
|
|
||||||
case "FailedOperation.FailResolvePacket": return GlobalErrorCodeConstants.BAD_REQUEST;
|
|
||||||
case "FailedOperation.InsufficientBalanceInSmsPackage": return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
|
|
||||||
case "FailedOperation.MarketingSendTimeConstraint": return SMS_SEND_MARKET_LIMIT_CONTROL;
|
|
||||||
case "FailedOperation.PhoneNumberInBlacklist": return SMS_MOBILE_BLACK;
|
|
||||||
case "FailedOperation.SignatureIncorrectOrUnapproved": return SMS_SIGN_INVALID;
|
|
||||||
case "FailedOperation.MissingTemplateToModify":
|
|
||||||
case "FailedOperation.TemplateIncorrectOrUnapproved": return SMS_TEMPLATE_INVALID;
|
|
||||||
case "InvalidParameterValue.IncorrectPhoneNumber": return SMS_MOBILE_INVALID;
|
|
||||||
case "InvalidParameterValue.SdkAppIdNotExist": return SMS_APP_ID_INVALID;
|
|
||||||
case "InvalidParameterValue.TemplateParameterLengthLimit":
|
|
||||||
case "InvalidParameterValue.TemplateParameterFormatError": return SMS_TEMPLATE_PARAM_ERROR;
|
|
||||||
case "LimitExceeded.PhoneNumberDailyLimit": return SMS_SEND_DAY_LIMIT_CONTROL;
|
|
||||||
case "LimitExceeded.PhoneNumberThirtySecondLimit":
|
|
||||||
case "LimitExceeded.PhoneNumberOneHourLimit": return SMS_SEND_BUSINESS_LIMIT_CONTROL;
|
|
||||||
case "UnauthorizedOperation.RequestPermissionDeny":
|
|
||||||
case "FailedOperation.ForbidAddMarketingTemplates":
|
|
||||||
case "FailedOperation.NotEnterpriseCertification":
|
|
||||||
case "UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny": return SMS_PERMISSION_DENY;
|
|
||||||
case "UnauthorizedOperation.RequestIpNotInWhitelist": return SMS_IP_DENY;
|
|
||||||
case "AuthFailure.SecretIdNotFound": return SMS_ACCOUNT_INVALID;
|
|
||||||
}
|
|
||||||
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +1,20 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
||||||
|
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
import com.aliyuncs.AcsRequest;
|
|
||||||
import com.aliyuncs.IAcsClient;
|
import com.aliyuncs.IAcsClient;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
|
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
|
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
|
||||||
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
|
||||||
import com.aliyuncs.exceptions.ClientException;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatcher;
|
import org.mockito.ArgumentMatcher;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
@ -28,12 +22,10 @@ import org.mockito.Mock;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ -67,8 +59,7 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
public void tesSendSms_success() throws Throwable {
|
||||||
public void testDoSendSms() throws ClientException {
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long sendLogId = randomLongId();
|
Long sendLogId = randomLongId();
|
||||||
String mobile = randomString();
|
String mobile = randomString();
|
||||||
|
@ -87,20 +78,47 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}))).thenReturn(response);
|
}))).thenReturn(response);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||||
apiTemplateId, templateParams);
|
apiTemplateId, templateParams);
|
||||||
// 断言
|
// 断言
|
||||||
|
assertTrue(result.getSuccess());
|
||||||
|
assertEquals(response.getRequestId(), result.getApiRequestId());
|
||||||
assertEquals(response.getCode(), result.getApiCode());
|
assertEquals(response.getCode(), result.getApiCode());
|
||||||
assertEquals(response.getMessage(), result.getApiMsg());
|
assertEquals(response.getMessage(), result.getApiMsg());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
|
assertEquals(response.getBizId(), result.getSerialNo());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
|
|
||||||
assertEquals(response.getRequestId(), result.getApiRequestId());
|
|
||||||
// 断言结果
|
|
||||||
assertEquals(response.getBizId(), result.getData().getSerialNo());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoTParseSmsReceiveStatus() throws Throwable {
|
public void tesSendSms_fail() throws Throwable {
|
||||||
|
// 准备参数
|
||||||
|
Long sendLogId = randomLongId();
|
||||||
|
String mobile = randomString();
|
||||||
|
String apiTemplateId = randomString();
|
||||||
|
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||||
|
new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
|
||||||
|
// mock 方法
|
||||||
|
SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("ERROR"));
|
||||||
|
when(client.getAcsResponse(argThat((ArgumentMatcher<SendSmsRequest>) acsRequest -> {
|
||||||
|
assertEquals(mobile, acsRequest.getPhoneNumbers());
|
||||||
|
assertEquals(properties.getSignature(), acsRequest.getSignName());
|
||||||
|
assertEquals(apiTemplateId, acsRequest.getTemplateCode());
|
||||||
|
assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam());
|
||||||
|
assertEquals(sendLogId.toString(), acsRequest.getOutId());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(response);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||||
|
// 断言
|
||||||
|
assertFalse(result.getSuccess());
|
||||||
|
assertEquals(response.getRequestId(), result.getApiRequestId());
|
||||||
|
assertEquals(response.getCode(), result.getApiCode());
|
||||||
|
assertEquals(response.getMessage(), result.getApiMsg());
|
||||||
|
assertEquals(response.getBizId(), result.getSerialNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseSmsReceiveStatus() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
String text = "[\n" +
|
String text = "[\n" +
|
||||||
" {\n" +
|
" {\n" +
|
||||||
|
@ -118,20 +136,21 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
// mock 方法
|
// mock 方法
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
|
List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(1, statuses.size());
|
assertEquals(1, statuses.size());
|
||||||
assertTrue(statuses.get(0).getSuccess());
|
assertTrue(statuses.get(0).getSuccess());
|
||||||
assertEquals("DELIVERED", statuses.get(0).getErrorCode());
|
assertEquals("DELIVERED", statuses.get(0).getErrorCode());
|
||||||
assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
|
assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
|
||||||
assertEquals("13900000001", statuses.get(0).getMobile());
|
assertEquals("13900000001", statuses.get(0).getMobile());
|
||||||
assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime());
|
assertEquals(LocalDateTime.of(2017, 2, 2, 22, 23, 24),
|
||||||
|
statuses.get(0).getReceiveTime());
|
||||||
assertEquals("12345", statuses.get(0).getSerialNo());
|
assertEquals("12345", statuses.get(0).getSerialNo());
|
||||||
assertEquals(67890L, statuses.get(0).getLogId());
|
assertEquals(67890L, statuses.get(0).getLogId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoGetSmsTemplate() throws ClientException {
|
public void testGetSmsTemplate() throws Throwable {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
String apiTemplateId = randomString();
|
String apiTemplateId = randomString();
|
||||||
// mock 方法
|
// mock 方法
|
||||||
|
@ -145,18 +164,12 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}))).thenReturn(response);
|
}))).thenReturn(response);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
|
SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(response.getCode(), result.getApiCode());
|
assertEquals(response.getTemplateCode(), result.getId());
|
||||||
assertEquals(response.getMessage(), result.getApiMsg());
|
assertEquals(response.getTemplateContent(), result.getContent());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
|
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
|
assertEquals(response.getReason(), result.getAuditReason());
|
||||||
assertEquals(response.getRequestId(), result.getApiRequestId());
|
|
||||||
// 断言结果
|
|
||||||
assertEquals(response.getTemplateCode(), result.getData().getId());
|
|
||||||
assertEquals(response.getTemplateContent(), result.getData().getContent());
|
|
||||||
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
|
|
||||||
assertEquals(response.getReason(), result.getData().getAuditReason());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -171,55 +184,4 @@ public class AliyunSmsClientTest extends BaseMockitoUnitTest {
|
||||||
"未知审核状态(3)");
|
"未知审核状态(3)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInvoke_throwable() throws ClientException {
|
|
||||||
// 准备参数
|
|
||||||
QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
|
|
||||||
// mock 方法
|
|
||||||
ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString());
|
|
||||||
when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);
|
|
||||||
|
|
||||||
// 调用,并断言异常
|
|
||||||
SmsCommonResult<?> result = smsClient.invoke(request, null);
|
|
||||||
// 断言
|
|
||||||
assertEquals(ex.getErrCode(), result.getApiCode());
|
|
||||||
assertEquals(ex.getErrMsg(), result.getApiMsg());
|
|
||||||
Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getCode(), result.getCode());
|
|
||||||
Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getMsg(), result.getMsg());
|
|
||||||
assertEquals(ex.getRequestId(), result.getApiRequestId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInvoke_success() throws ClientException {
|
|
||||||
// 准备参数
|
|
||||||
QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
|
|
||||||
Function<QuerySmsTemplateResponse, SmsTemplateRespDTO> responseConsumer = response -> {
|
|
||||||
SmsTemplateRespDTO data = new SmsTemplateRespDTO();
|
|
||||||
data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
|
|
||||||
data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason());
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
// mock 方法
|
|
||||||
QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {
|
|
||||||
o.setCode("OK");
|
|
||||||
o.setTemplateStatus(1); // 设置模板通过
|
|
||||||
});
|
|
||||||
when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response);
|
|
||||||
|
|
||||||
// 调用
|
|
||||||
SmsCommonResult<SmsTemplateRespDTO> result = smsClient.invoke(request, responseConsumer);
|
|
||||||
// 断言
|
|
||||||
assertEquals(response.getCode(), result.getApiCode());
|
|
||||||
assertEquals(response.getMessage(), result.getApiMsg());
|
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
|
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
|
|
||||||
assertEquals(response.getRequestId(), result.getApiRequestId());
|
|
||||||
// 断言结果
|
|
||||||
assertEquals(response.getTemplateCode(), result.getData().getId());
|
|
||||||
assertEquals(response.getTemplateContent(), result.getData().getContent());
|
|
||||||
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
|
|
||||||
assertEquals(response.getReason(), result.getData().getAuditReason());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link AliyunSmsCodeMapping} 的单元测试
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public class AliyunSmsCodeMappingTest extends BaseMockitoUnitTest {
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private AliyunSmsCodeMapping codeMapping;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testApply() {
|
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply("OK"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("MissingAccessKeyId"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_NOT_EXISTS"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("isv.ACCOUNT_ABNORMAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("isv.DAY_LIMIT_CONTROL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("isv.SMS_CONTENT_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGN_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SIGN_NAME_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("isp.RAM_PERMISSION_DENY"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.OUT_OF_SERVICE"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("isv.AMOUNT_NOT_ENOUGH"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("isv.SMS_TEMPLATE_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("isv.SMS_SIGNATURE_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_PARAMETERS"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR, codeMapping.apply("isv.INVALID_JSON_PARAM"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("isv.MOBILE_NUMBER_ILLEGAL"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("isv.TEMPLATE_MISSING_PARAMETERS"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("isv.BUSINESS_LIMIT_CONTROL"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +1,10 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
|
package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
|
||||||
|
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
|
@ -31,7 +28,6 @@ import java.util.List;
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ -78,7 +74,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoSendSms() throws Throwable {
|
public void testDoSendSms_success() throws Throwable {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long sendLogId = randomLongId();
|
Long sendLogId = randomLongId();
|
||||||
String mobile = randomString();
|
String mobile = randomString();
|
||||||
|
@ -94,7 +90,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
o.setSendStatusSet(sendStatuses);
|
o.setSendStatusSet(sendStatuses);
|
||||||
SendStatus sendStatus = new SendStatus();
|
SendStatus sendStatus = new SendStatus();
|
||||||
sendStatuses[0] = sendStatus;
|
sendStatuses[0] = sendStatus;
|
||||||
sendStatus.setCode(TencentSmsClient.API_SUCCESS_CODE);
|
sendStatus.setCode(TencentSmsClient.API_CODE_SUCCESS);
|
||||||
sendStatus.setMessage("send success");
|
sendStatus.setMessage("send success");
|
||||||
sendStatus.setSerialNo(serialNo);
|
sendStatus.setSerialNo(serialNo);
|
||||||
});
|
});
|
||||||
|
@ -109,20 +105,58 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}))).thenReturn(response);
|
}))).thenReturn(response);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||||
apiTemplateId, templateParams);
|
|
||||||
// 断言
|
// 断言
|
||||||
|
assertTrue(result.getSuccess());
|
||||||
|
assertEquals(response.getRequestId(), result.getApiRequestId());
|
||||||
assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
|
assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
|
||||||
assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
|
assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
|
assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
|
|
||||||
assertEquals(response.getRequestId(), result.getApiRequestId());
|
|
||||||
// 断言结果
|
|
||||||
assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getData().getSerialNo());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoTParseSmsReceiveStatus() throws Throwable {
|
public void testDoSendSms_fail() throws Throwable {
|
||||||
|
// 准备参数
|
||||||
|
Long sendLogId = randomLongId();
|
||||||
|
String mobile = randomString();
|
||||||
|
String apiTemplateId = randomString();
|
||||||
|
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
|
||||||
|
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
|
||||||
|
String requestId = randomString();
|
||||||
|
String serialNo = randomString();
|
||||||
|
// mock 方法
|
||||||
|
SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> {
|
||||||
|
o.setRequestId(requestId);
|
||||||
|
SendStatus[] sendStatuses = new SendStatus[1];
|
||||||
|
o.setSendStatusSet(sendStatuses);
|
||||||
|
SendStatus sendStatus = new SendStatus();
|
||||||
|
sendStatuses[0] = sendStatus;
|
||||||
|
sendStatus.setCode("ERROR");
|
||||||
|
sendStatus.setMessage("send success");
|
||||||
|
sendStatus.setSerialNo(serialNo);
|
||||||
|
});
|
||||||
|
when(client.SendSms(argThat(request -> {
|
||||||
|
assertEquals(mobile, request.getPhoneNumberSet()[0]);
|
||||||
|
assertEquals(properties.getSignature(), request.getSignName());
|
||||||
|
assertEquals(apiTemplateId, request.getTemplateId());
|
||||||
|
assertEquals(toJsonString(ArrayUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)),
|
||||||
|
toJsonString(request.getTemplateParamSet()));
|
||||||
|
assertEquals(sendLogId, ReflectUtil.getFieldValue(JsonUtils.parseObject(request.getSessionContext(), TencentSmsClient.SessionContext.class), "logId"));
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(response);
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||||
|
// 断言
|
||||||
|
assertFalse(result.getSuccess());
|
||||||
|
assertEquals(response.getRequestId(), result.getApiRequestId());
|
||||||
|
assertEquals(response.getSendStatusSet()[0].getCode(), result.getApiCode());
|
||||||
|
assertEquals(response.getSendStatusSet()[0].getMessage(), result.getApiMsg());
|
||||||
|
assertEquals(response.getSendStatusSet()[0].getSerialNo(), result.getSerialNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseSmsReceiveStatus() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
String text = "[\n" +
|
String text = "[\n" +
|
||||||
" {\n" +
|
" {\n" +
|
||||||
|
@ -139,7 +173,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
// mock 方法
|
// mock 方法
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
|
List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(1, statuses.size());
|
assertEquals(1, statuses.size());
|
||||||
assertTrue(statuses.get(0).getSuccess());
|
assertTrue(statuses.get(0).getSuccess());
|
||||||
|
@ -152,7 +186,7 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDoGetSmsTemplate() throws Throwable {
|
public void testGetSmsTemplate() throws Throwable {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long apiTemplateId = randomLongId();
|
Long apiTemplateId = randomLongId();
|
||||||
String requestId = randomString();
|
String requestId = randomString();
|
||||||
|
@ -173,50 +207,24 @@ public class TencentSmsClientTest extends BaseMockitoUnitTest {
|
||||||
}))).thenReturn(response);
|
}))).thenReturn(response);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId.toString());
|
SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId.toString());
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(TencentSmsClient.API_SUCCESS_CODE, result.getApiCode());
|
assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getId());
|
||||||
assertNull(result.getApiMsg());
|
assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getContent());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
|
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
|
assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getAuditReason());
|
||||||
assertEquals(response.getRequestId(), result.getApiRequestId());
|
|
||||||
// 断言结果
|
|
||||||
assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateId().toString(), result.getData().getId());
|
|
||||||
assertEquals(response.getDescribeTemplateStatusSet()[0].getTemplateContent(), result.getData().getContent());
|
|
||||||
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
|
|
||||||
assertEquals(response.getDescribeTemplateStatusSet()[0].getReviewReply(), result.getData().getAuditReason());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvertSuccessTemplateStatus() {
|
public void testConvertSmsTemplateAuditStatus() {
|
||||||
testTemplateStatus(SmsTemplateAuditStatusEnum.SUCCESS, 0L);
|
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
|
||||||
}
|
smsClient.convertSmsTemplateAuditStatus(0));
|
||||||
|
assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
|
||||||
@Test
|
smsClient.convertSmsTemplateAuditStatus(1));
|
||||||
public void testConvertCheckingTemplateStatus() {
|
assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
|
||||||
testTemplateStatus(SmsTemplateAuditStatusEnum.CHECKING, 1L);
|
smsClient.convertSmsTemplateAuditStatus(-1));
|
||||||
}
|
assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3),
|
||||||
|
"未知审核状态(3)");
|
||||||
@Test
|
|
||||||
public void testConvertFailTemplateStatus() {
|
|
||||||
testTemplateStatus(SmsTemplateAuditStatusEnum.FAIL, -1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConvertUnknownTemplateStatus() {
|
|
||||||
DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus();
|
|
||||||
templateStatus.setStatusCode(3L);
|
|
||||||
Long templateId = randomLongId();
|
|
||||||
// 调用,并断言结果
|
|
||||||
assertThrows(IllegalStateException.class, () -> smsClient.convertTemplateStatusDTO(templateStatus),
|
|
||||||
StrUtil.format("不能解析短信模版审核状态[3],模版id[{}]", templateId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testTemplateStatus(SmsTemplateAuditStatusEnum expected, Long value) {
|
|
||||||
DescribeTemplateListStatus templateStatus = new DescribeTemplateListStatus();
|
|
||||||
templateStatus.setStatusCode(value);
|
|
||||||
SmsTemplateRespDTO result = smsClient.convertTemplateStatusDTO(templateStatus);
|
|
||||||
assertEquals(expected.getStatus(), result.getAuditStatus());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.sms.core.client.impl.tencent;
|
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link TencentSmsCodeMapping} 的单元测试
|
|
||||||
*
|
|
||||||
* @author : shiwp
|
|
||||||
*/
|
|
||||||
public class TencentSmsCodeMappingTest extends BaseMockitoUnitTest {
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private TencentSmsCodeMapping codeMapping;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testApply() {
|
|
||||||
assertEquals(GlobalErrorCodeConstants.SUCCESS, codeMapping.apply(TencentSmsClient.API_SUCCESS_CODE));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID, codeMapping.apply("FailedOperation.ContainSensitiveWord"));
|
|
||||||
assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("FailedOperation.JsonParseFail"));
|
|
||||||
assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("MissingParameter.EmptyPhoneNumberSet"));
|
|
||||||
assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("LimitExceeded.PhoneNumberCountLimit"));
|
|
||||||
assertEquals(GlobalErrorCodeConstants.BAD_REQUEST, codeMapping.apply("FailedOperation.FailResolvePacket"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH, codeMapping.apply("FailedOperation.InsufficientBalanceInSmsPackage"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_MARKET_LIMIT_CONTROL, codeMapping.apply("FailedOperation.MarketingSendTimeConstraint"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK, codeMapping.apply("FailedOperation.PhoneNumberInBlacklist"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID, codeMapping.apply("FailedOperation.SignatureIncorrectOrUnapproved"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("FailedOperation.MissingTemplateToModify"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID, codeMapping.apply("FailedOperation.TemplateIncorrectOrUnapproved"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_MOBILE_INVALID, codeMapping.apply("InvalidParameterValue.IncorrectPhoneNumber"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_APP_ID_INVALID, codeMapping.apply("InvalidParameterValue.SdkAppIdNotExist"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("InvalidParameterValue.TemplateParameterLengthLimit"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR, codeMapping.apply("InvalidParameterValue.TemplateParameterFormatError"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_DAY_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberDailyLimit"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberThirtySecondLimit"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL, codeMapping.apply("LimitExceeded.PhoneNumberOneHourLimit"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("UnauthorizedOperation.RequestPermissionDeny"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("FailedOperation.ForbidAddMarketingTemplates"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("FailedOperation.NotEnterpriseCertification"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY, codeMapping.apply("UnauthorizedOperation.IndividualUserMarketingSmsPermissionDeny"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_IP_DENY, codeMapping.apply("UnauthorizedOperation.RequestIpNotInWhitelist"));
|
|
||||||
assertEquals(SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID, codeMapping.apply("AuthFailure.SecretIdNotFound"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -82,6 +82,10 @@ public interface ErrorCodeConstants {
|
||||||
// ========== 短信模板 1-002-012-000 ==========
|
// ========== 短信模板 1-002-012-000 ==========
|
||||||
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
|
ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_012_000, "短信模板不存在");
|
||||||
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板");
|
ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1_002_012_001, "已经存在编码为【{}】的短信模板");
|
||||||
|
ErrorCode SMS_TEMPLATE_API_ERROR = new ErrorCode(1_002_012_002, "短信 API 模板调用失败,原因是:{}");
|
||||||
|
ErrorCode SMS_TEMPLATE_API_AUDIT_CHECKING = new ErrorCode(1_002_012_003, "短信 API 模版无法使用,原因:审批中");
|
||||||
|
ErrorCode SMS_TEMPLATE_API_AUDIT_FAIL = new ErrorCode(1_002_012_004, "短信 API 模版无法使用,原因:审批不通过,{}");
|
||||||
|
ErrorCode SMS_TEMPLATE_API_NOT_FOUND = new ErrorCode(1_002_012_005, "短信 API 模版无法使用,原因:模版不存在");
|
||||||
|
|
||||||
// ========== 短信发送 1-002-013-000 ==========
|
// ========== 短信发送 1-002-013-000 ==========
|
||||||
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在");
|
ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1_002_013_000, "手机号不存在");
|
||||||
|
|
|
@ -63,12 +63,6 @@ public class SmsLogExcelVO {
|
||||||
@ExcelProperty("发送时间")
|
@ExcelProperty("发送时间")
|
||||||
private LocalDateTime sendTime;
|
private LocalDateTime sendTime;
|
||||||
|
|
||||||
@ExcelProperty("发送结果的编码")
|
|
||||||
private Integer sendCode;
|
|
||||||
|
|
||||||
@ExcelProperty("发送结果的提示")
|
|
||||||
private String sendMsg;
|
|
||||||
|
|
||||||
@ExcelProperty("短信 API 发送结果的编码")
|
@ExcelProperty("短信 API 发送结果的编码")
|
||||||
private String apiSendCode;
|
private String apiSendCode;
|
||||||
|
|
||||||
|
|
|
@ -52,12 +52,6 @@ public class SmsLogRespVO {
|
||||||
@Schema(description = "发送时间")
|
@Schema(description = "发送时间")
|
||||||
private LocalDateTime sendTime;
|
private LocalDateTime sendTime;
|
||||||
|
|
||||||
@Schema(description = "发送结果的编码", example = "0")
|
|
||||||
private Integer sendCode;
|
|
||||||
|
|
||||||
@Schema(description = "发送结果的提示", example = "成功")
|
|
||||||
private String sendMsg;
|
|
||||||
|
|
||||||
@Schema(description = "短信 API 发送结果的编码", example = "SUCCESS")
|
@Schema(description = "短信 API 发送结果的编码", example = "SUCCESS")
|
||||||
private String apiSendCode;
|
private String apiSendCode;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package cn.iocoder.yudao.module.system.dal.dataobject.sms;
|
package cn.iocoder.yudao.module.system.dal.dataobject.sms;
|
||||||
|
|
||||||
import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
|
|
||||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
|
import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
@ -115,19 +114,6 @@ public class SmsLogDO extends BaseDO {
|
||||||
* 发送时间
|
* 发送时间
|
||||||
*/
|
*/
|
||||||
private LocalDateTime sendTime;
|
private LocalDateTime sendTime;
|
||||||
/**
|
|
||||||
* 发送结果的编码
|
|
||||||
*
|
|
||||||
* 枚举 {@link SmsFrameworkErrorCodeConstants}
|
|
||||||
*/
|
|
||||||
private Integer sendCode;
|
|
||||||
/**
|
|
||||||
* 发送结果的提示
|
|
||||||
*
|
|
||||||
* 一般情况下,使用 {@link SmsFrameworkErrorCodeConstants}
|
|
||||||
* 异常情况下,通过格式化 Exception 的提示存储
|
|
||||||
*/
|
|
||||||
private String sendMsg;
|
|
||||||
/**
|
/**
|
||||||
* 短信 API 发送结果的编码
|
* 短信 API 发送结果的编码
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -37,15 +37,15 @@ public interface SmsLogService {
|
||||||
* 更新日志的发送结果
|
* 更新日志的发送结果
|
||||||
*
|
*
|
||||||
* @param id 日志编号
|
* @param id 日志编号
|
||||||
* @param sendCode 发送结果的编码
|
* @param success 发送是否成功
|
||||||
* @param sendMsg 发送结果的提示
|
|
||||||
* @param apiSendCode 短信 API 发送结果的编码
|
* @param apiSendCode 短信 API 发送结果的编码
|
||||||
* @param apiSendMsg 短信 API 发送失败的提示
|
* @param apiSendMsg 短信 API 发送失败的提示
|
||||||
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
|
* @param apiRequestId 短信 API 发送返回的唯一请求 ID
|
||||||
* @param apiSerialNo 短信 API 发送返回的序号
|
* @param apiSerialNo 短信 API 发送返回的序号
|
||||||
*/
|
*/
|
||||||
void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
|
void updateSmsSendResult(Long id, Boolean success,
|
||||||
String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo);
|
String apiSendCode, String apiSendMsg,
|
||||||
|
String apiRequestId, String apiSerialNo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新日志的接收结果
|
* 更新日志的接收结果
|
||||||
|
@ -56,7 +56,8 @@ public interface SmsLogService {
|
||||||
* @param apiReceiveCode API 接收结果的编码
|
* @param apiReceiveCode API 接收结果的编码
|
||||||
* @param apiReceiveMsg API 接收结果的说明
|
* @param apiReceiveMsg API 接收结果的说明
|
||||||
*/
|
*/
|
||||||
void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
void updateSmsReceiveResult(Long id, Boolean success,
|
||||||
|
LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得短信日志分页
|
* 获得短信日志分页
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsLogMapper;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
|
import cn.iocoder.yudao.module.system.enums.sms.SmsReceiveStatusEnum;
|
||||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
|
import cn.iocoder.yudao.module.system.enums.sms.SmsSendStatusEnum;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
@ -55,13 +54,12 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
|
public void updateSmsSendResult(Long id, Boolean success,
|
||||||
String apiSendCode, String apiSendMsg,
|
String apiSendCode, String apiSendMsg,
|
||||||
String apiRequestId, String apiSerialNo) {
|
String apiRequestId, String apiSerialNo) {
|
||||||
SmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ?
|
SmsSendStatusEnum sendStatus = success ? SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;
|
||||||
SmsSendStatusEnum.SUCCESS : SmsSendStatusEnum.FAILURE;
|
smsLogMapper.updateById(SmsLogDO.builder().id(id)
|
||||||
smsLogMapper.updateById(SmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus())
|
.sendStatus(sendStatus.getStatus()).sendTime(LocalDateTime.now())
|
||||||
.sendTime(LocalDateTime.now()).sendCode(sendCode).sendMsg(sendMsg)
|
|
||||||
.apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
|
.apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
|
||||||
.apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
|
.apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
|
@ -8,7 +9,6 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||||
|
@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
|
||||||
import cn.iocoder.yudao.module.system.service.member.MemberService;
|
import cn.iocoder.yudao.module.system.service.member.MemberService;
|
||||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -35,6 +36,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class SmsSendServiceImpl implements SmsSendService {
|
public class SmsSendServiceImpl implements SmsSendService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@ -158,11 +160,17 @@ public class SmsSendServiceImpl implements SmsSendService {
|
||||||
SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId());
|
SmsClient smsClient = smsChannelService.getSmsClient(message.getChannelId());
|
||||||
Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId());
|
Assert.notNull(smsClient, "短信客户端({}) 不存在", message.getChannelId());
|
||||||
// 发送短信
|
// 发送短信
|
||||||
SmsCommonResult<SmsSendRespDTO> sendResult = smsClient.sendSms(message.getLogId(), message.getMobile(),
|
try {
|
||||||
message.getApiTemplateId(), message.getTemplateParams());
|
SmsSendRespDTO sendResponse = smsClient.sendSms(message.getLogId(), message.getMobile(),
|
||||||
smsLogService.updateSmsSendResult(message.getLogId(), sendResult.getCode(), sendResult.getMsg(),
|
message.getApiTemplateId(), message.getTemplateParams());
|
||||||
sendResult.getApiCode(), sendResult.getApiMsg(), sendResult.getApiRequestId(),
|
smsLogService.updateSmsSendResult(message.getLogId(), sendResponse.getSuccess(),
|
||||||
sendResult.getData() != null ? sendResult.getData().getSerialNo() : null);
|
sendResponse.getApiCode(), sendResponse.getApiMsg(),
|
||||||
|
sendResponse.getApiRequestId(), sendResponse.getSerialNo());
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
log.error("[doSendSms][发送短信异常,日志编号({})]", message.getLogId(), ex);
|
||||||
|
smsLogService.updateSmsSendResult(message.getLogId(), false,
|
||||||
|
"EXCEPTION", ExceptionUtil.getRootCauseMessage(ex), null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ReUtil;
|
import cn.hutool.core.util.ReUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
||||||
|
@ -21,11 +23,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.cache.annotation.CacheEvict;
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
@ -171,9 +173,24 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
|
||||||
// 获得短信模板
|
// 获得短信模板
|
||||||
SmsClient smsClient = smsChannelService.getSmsClient(channelId);
|
SmsClient smsClient = smsChannelService.getSmsClient(channelId);
|
||||||
Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
|
Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
|
||||||
SmsCommonResult<SmsTemplateRespDTO> templateResult = smsClient.getSmsTemplate(apiTemplateId);
|
SmsTemplateRespDTO template;
|
||||||
// 校验短信模板是否正确
|
try {
|
||||||
templateResult.checkError();
|
template = smsClient.getSmsTemplate(apiTemplateId);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
throw exception(SMS_TEMPLATE_API_ERROR, ExceptionUtil.getRootCauseMessage(ex));
|
||||||
|
}
|
||||||
|
// 校验短信模版
|
||||||
|
if (template == null) {
|
||||||
|
throw exception(SMS_TEMPLATE_API_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) {
|
||||||
|
throw exception(SMS_TEMPLATE_API_AUDIT_CHECKING);
|
||||||
|
}
|
||||||
|
if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) {
|
||||||
|
throw exception(SMS_TEMPLATE_API_AUDIT_FAIL, template.getAuditReason());
|
||||||
|
}
|
||||||
|
Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
|
||||||
|
String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -164,31 +164,31 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetSmsChannelPage() {
|
public void testGetSmsChannelPage() {
|
||||||
// mock 数据
|
// mock 数据
|
||||||
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
|
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
|
||||||
o.setSignature("芋道源码");
|
o.setSignature("芋道源码");
|
||||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
o.setCreateTime(buildTime(2020, 12, 12));
|
o.setCreateTime(buildTime(2020, 12, 12));
|
||||||
});
|
});
|
||||||
smsChannelMapper.insert(dbSmsChannel);
|
smsChannelMapper.insert(dbSmsChannel);
|
||||||
// 测试 signature 不匹配
|
// 测试 signature 不匹配
|
||||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
|
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
|
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
|
||||||
// 准备参数
|
// 准备参数
|
||||||
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
|
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
|
||||||
reqVO.setSignature("芋道");
|
reqVO.setSignature("芋道");
|
||||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||||
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
|
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
|
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
|
||||||
// 断言
|
// 断言
|
||||||
assertEquals(1, pageResult.getTotal());
|
assertEquals(1, pageResult.getTotal());
|
||||||
assertEquals(1, pageResult.getList().size());
|
assertEquals(1, pageResult.getList().size());
|
||||||
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
|
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||||
|
@ -172,22 +171,20 @@ public class SmsLogServiceImplTest extends BaseDbUnitTest {
|
||||||
smsLogMapper.insert(dbSmsLog);
|
smsLogMapper.insert(dbSmsLog);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long id = dbSmsLog.getId();
|
Long id = dbSmsLog.getId();
|
||||||
Integer sendCode = randomInteger();
|
Boolean success = randomBoolean();
|
||||||
String sendMsg = randomString();
|
|
||||||
String apiSendCode = randomString();
|
String apiSendCode = randomString();
|
||||||
String apiSendMsg = randomString();
|
String apiSendMsg = randomString();
|
||||||
String apiRequestId = randomString();
|
String apiRequestId = randomString();
|
||||||
String apiSerialNo = randomString();
|
String apiSerialNo = randomString();
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
smsLogService.updateSmsSendResult(id, sendCode, sendMsg,
|
smsLogService.updateSmsSendResult(id, success,
|
||||||
apiSendCode, apiSendMsg, apiRequestId, apiSerialNo);
|
apiSendCode, apiSendMsg, apiRequestId, apiSerialNo);
|
||||||
// 断言
|
// 断言
|
||||||
dbSmsLog = smsLogMapper.selectById(id);
|
dbSmsLog = smsLogMapper.selectById(id);
|
||||||
assertEquals(CommonResult.isSuccess(sendCode) ? SmsSendStatusEnum.SUCCESS.getStatus()
|
assertEquals(success ? SmsSendStatusEnum.SUCCESS.getStatus() : SmsSendStatusEnum.FAILURE.getStatus(),
|
||||||
: SmsSendStatusEnum.FAILURE.getStatus(), dbSmsLog.getSendStatus());
|
dbSmsLog.getSendStatus());
|
||||||
assertNotNull(dbSmsLog.getSendTime());
|
assertNotNull(dbSmsLog.getSendTime());
|
||||||
assertEquals(sendMsg, dbSmsLog.getSendMsg());
|
|
||||||
assertEquals(apiSendCode, dbSmsLog.getApiSendCode());
|
assertEquals(apiSendCode, dbSmsLog.getApiSendCode());
|
||||||
assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg());
|
assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg());
|
||||||
assertEquals(apiRequestId, dbSmsLog.getApiRequestId());
|
assertEquals(apiRequestId, dbSmsLog.getApiRequestId());
|
||||||
|
|
|
@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
|
@ -244,15 +243,14 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testDoSendSms() {
|
public void testDoSendSms() throws Throwable {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
SmsSendMessage message = randomPojo(SmsSendMessage.class);
|
SmsSendMessage message = randomPojo(SmsSendMessage.class);
|
||||||
// mock SmsClientFactory 的方法
|
// mock SmsClientFactory 的方法
|
||||||
SmsClient smsClient = spy(SmsClient.class);
|
SmsClient smsClient = spy(SmsClient.class);
|
||||||
when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
|
when(smsChannelService.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
|
||||||
// mock SmsClient 的方法
|
// mock SmsClient 的方法
|
||||||
SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class);
|
SmsSendRespDTO sendResult = randomPojo(SmsSendRespDTO.class);
|
||||||
sendResult.setData(randomPojo(SmsSendRespDTO.class));
|
|
||||||
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
|
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
|
||||||
eq(message.getTemplateParams()))).thenReturn(sendResult);
|
eq(message.getTemplateParams()))).thenReturn(sendResult);
|
||||||
|
|
||||||
|
@ -260,8 +258,8 @@ public class SmsSendServiceImplTest extends BaseMockitoUnitTest {
|
||||||
smsService.doSendSms(message);
|
smsService.doSendSms(message);
|
||||||
// 断言
|
// 断言
|
||||||
verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
|
verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
|
||||||
eq(sendResult.getCode()), eq(sendResult.getMsg()), eq(sendResult.getApiCode()),
|
eq(sendResult.getSuccess()), eq(sendResult.getApiCode()),
|
||||||
eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getData().getSerialNo()));
|
eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getSerialNo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package cn.iocoder.yudao.module.system.service.sms;
|
package cn.iocoder.yudao.module.system.service.sms;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
|
||||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
||||||
|
@ -65,7 +64,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testCreateSmsTemplate_success() {
|
public void testCreateSmsTemplate_success() throws Throwable {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
SmsTemplateCreateReqVO reqVO = randomPojo(SmsTemplateCreateReqVO.class, o -> {
|
SmsTemplateCreateReqVO reqVO = randomPojo(SmsTemplateCreateReqVO.class, o -> {
|
||||||
o.setContent("正在进行登录操作{operation},您的验证码是{code}");
|
o.setContent("正在进行登录操作{operation},您的验证码是{code}");
|
||||||
|
@ -80,8 +79,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
|
||||||
when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
|
when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
|
||||||
// mock 获得 API 短信模板成功
|
// mock 获得 API 短信模板成功
|
||||||
when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
|
when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
|
||||||
when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
|
when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(
|
||||||
o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
|
randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus())));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO);
|
Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO);
|
||||||
|
@ -96,7 +95,7 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testUpdateSmsTemplate_success() {
|
public void testUpdateSmsTemplate_success() throws Throwable {
|
||||||
// mock 数据
|
// mock 数据
|
||||||
SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
|
SmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
|
||||||
smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
|
smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
|
||||||
|
@ -115,8 +114,8 @@ public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
|
||||||
when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
|
when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
|
||||||
// mock 获得 API 短信模板成功
|
// mock 获得 API 短信模板成功
|
||||||
when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
|
when(smsChannelService.getSmsClient(eq(reqVO.getChannelId()))).thenReturn(smsClient);
|
||||||
when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(randomPojo(SmsCommonResult.class, SmsTemplateRespDTO.class,
|
when(smsClient.getSmsTemplate(eq(reqVO.getApiTemplateId()))).thenReturn(
|
||||||
o -> o.setCode(GlobalErrorCodeConstants.SUCCESS.getCode())));
|
randomPojo(SmsTemplateRespDTO.class, o -> o.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus())));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
smsTemplateService.updateSmsTemplate(reqVO);
|
smsTemplateService.updateSmsTemplate(reqVO);
|
||||||
|
|
Loading…
Reference in New Issue