magic 参数处理&AbstractSmsClient模版优化

This commit is contained in:
FinallySays
2022-04-08 11:10:39 +08:00
parent 2e66845584
commit eb147a92ff
6 changed files with 125 additions and 42 deletions

View File

@@ -31,7 +31,7 @@ public abstract class AbstractSmsClient implements SmsClient {
protected final SmsCodeMapping codeMapping;
public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) {
this.properties = properties;
this.properties = prepareProperties(properties);
this.codeMapping = codeMapping;
}
@@ -54,11 +54,21 @@ public abstract class AbstractSmsClient implements SmsClient {
return;
}
log.info("[refresh][配置({})发生变化,重新初始化]", properties);
this.properties = properties;
this.properties = prepareProperties(properties);
// 初始化
this.init();
}
/**
* 在赋值给{@link this#properties}前,子类可根据需要预处理短信渠道配置
*
* @param properties 数据库中存储的短信渠道配置
* @return 满足子类实现的短信渠道配置
*/
protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {
return properties;
}
@Override
public Long getId() {
return properties.getId();

View File

@@ -14,6 +14,7 @@ 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.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.yudao.framework.sms.core.property.TencentSmsChannelProperties;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
@@ -42,21 +43,33 @@ public class TencentSmsClient extends AbstractSmsClient {
private SmsClient client;
/**
* 调用成功 code
*/
public static final String API_SUCCESS_CODE = "Ok";
/**
* REGION, 使用南京
*/
private static final String ENDPOINT = "ap-nanjing";
/**
* 是否国际/港澳台短信:
* 0表示国内短信。
* 1表示国际/港澳台短信。
*/
private static final long INTERNATIONAL = 0L;
public TencentSmsClient(SmsChannelProperties properties) {
// 腾讯云发放短信的时候,需要额外的参数 sdkAppId。考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
// 因此,这边需要使用 TencentSmsChannelProperties 做拆分,重新封装到 properties 内。
super(TencentSmsChannelProperties.build(properties), new TencentSmsCodeMapping());
super(properties, new TencentSmsCodeMapping());
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
@Override
protected void doInit() {
// init 或者 refresh 时,需要重新封装 properties
properties = TencentSmsChannelProperties.build(properties);
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretIdsecretKey
Credential credential = new Credential(properties.getApiKey(), properties.getApiSecret());
// TODO @FinallySays那把 ap-nanjing 枚举下到这个类的静态变量里哈。
client = new SmsClient(credential, "ap-nanjing");
client = new SmsClient(credential, ENDPOINT);
}
@Override
@@ -73,6 +86,20 @@ public class TencentSmsClient extends AbstractSmsClient {
});
}
/**
* 腾讯云发放短信的时候,需要额外的参数 sdkAppId。
* 考虑到不破坏原有的 apiKey + apiSecret 的结构,所以将 secretId 拼接到 apiKey 字段中,格式为 "secretId sdkAppId"。
* 因此,这边需要使用 TencentSmsChannelProperties 做拆分,重新封装到 properties 内。
*
* @param properties 数据库中存储的短信渠道配置
* @return TencentSmsChannelProperties
*/
@Override
protected SmsChannelProperties prepareProperties(SmsChannelProperties properties) {
return TencentSmsChannelProperties.build(properties);
}
/**
* 调用腾讯云 SDK 发送短信
*
@@ -113,7 +140,7 @@ public class TencentSmsClient extends AbstractSmsClient {
return CollectionUtils.convertList(callback, status -> {
SmsReceiveRespDTO data = new SmsReceiveRespDTO();
data.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription());
data.setReceiveTime(status.getReceiveTime()).setSuccess("SUCCESS".equalsIgnoreCase(status.getStatus()));
data.setReceiveTime(status.getReceiveTime()).setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()));
data.setMobile(status.getMobile()).setSerialNo(status.getSerialNo());
SessionContext context;
Long logId;
@@ -130,7 +157,7 @@ public class TencentSmsClient extends AbstractSmsClient {
this::doGetSmsTemplate0,
response -> {
SmsTemplateRespDTO data = convertTemplateStatusDTO(response.getDescribeTemplateStatusSet()[0]);
return SmsCommonResult.build("Ok", null, response.getRequestId(), data, codeMapping);
return SmsCommonResult.build(API_SUCCESS_CODE, null, response.getRequestId(), data, codeMapping);
});
}
@@ -171,8 +198,7 @@ public class TencentSmsClient extends AbstractSmsClient {
DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
// 地区 0表示国内短信。1表示国际/港澳台短信。
// TODO @FinallySays那把 0L 枚举下到这个类的静态变量里哈。
request.setInternational(0L);
request.setInternational(INTERNATIONAL);
return request;
}
@@ -206,6 +232,11 @@ public class TencentSmsClient extends AbstractSmsClient {
@Data
private static class SmsReceiveStatus {
/**
* 短信接受成功 code
*/
public static final String SUCCESS_CODE = "SUCCESS";
/**
* 用户实际接收到短信的时间
*/
@@ -270,27 +301,4 @@ public class TencentSmsClient extends AbstractSmsClient {
R apply(T t) throws TencentCloudSDKException;
}
// TODO @FinallySays要不单独一个类不用作为内部类哈。这样可能一看就知道腾讯短信是特殊的
@Data
private static class TencentSmsChannelProperties extends SmsChannelProperties {
private String 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;
}
}
}

View File

@@ -19,7 +19,7 @@ public class TencentSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
switch (apiCode) {
case "Ok": return GlobalErrorCodeConstants.SUCCESS;
case TencentSmsClient.API_SUCCESS_CODE: return GlobalErrorCodeConstants.SUCCESS;
case "FailedOperation.ContainSensitiveWord": return SMS_SEND_CONTENT_INVALID;
case "FailedOperation.JsonParseFail":
case "MissingParameter.EmptyPhoneNumberSet":

View File

@@ -0,0 +1,41 @@
package cn.iocoder.yudao.framework.sms.core.property;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
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;
}
}