Skip to content

Commit

Permalink
根据 code review 对腾讯云短信实现优化
Browse files Browse the repository at this point in the history
  • Loading branch information
FinallySays committed Apr 6, 2022
1 parent 9726560 commit 91f758c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package cn.iocoder.yudao.framework.common.util.collection;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.TypeUtil;
import org.springframework.cglib.core.TypeUtils;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;

/**
* Array 工具类
Expand Down Expand Up @@ -30,4 +41,16 @@ public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newEle
return result;
}

public static <T, V> V[] toArray(Collection<T> from, Function<T, V> mapper) {
return toArray(convertList(from, mapper));
}

@SuppressWarnings("unchecked")
public static <T> T[] toArray(Collection<T> from) {
if (CollectionUtil.isEmpty(from)) {
return (T[]) (new Object[0]);
}
return ArrayUtil.toArray(from, (Class<T>) CollectionUtil.getElementType(from.iterator()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.ImmutableMap;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
Expand Down Expand Up @@ -171,21 +170,4 @@ public static <T> Collection<T> singleton(T deptId) {
return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
}

// TODO @FinallySays:建议放在 ArrayUtils 里,和 hutool 对齐
public static <T, V> V[] toArray(List<T> from, Function<T, V> mapper) {
return toArray(convertList(from, mapper));
}

@SuppressWarnings("unchecked")
public static <T> T[] toArray(List<T> from) {
if (CollectionUtil.isEmpty(from)) {
return (T[]) (new Object[0]);
}
Class<T> clazz = (Class<T>) from.get(0).getClass();
T[] result = (T[]) Array.newInstance(clazz, from.size());
for (int i = 0; i < from.size(); i++) {
result[i] = from.get(i);
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
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.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
Expand All @@ -22,10 +23,8 @@
import com.tencentcloudapi.sms.v20210111.models.*;
import lombok.Data;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

Expand All @@ -37,28 +36,24 @@
* <p>
* 参见 https://cloud.tencent.com/document/product/382/52077
*
* @author : shiwp
* @author shiwp
*/
// TODO @author 后面,空格即可
public class TencentSmsClient extends AbstractSmsClient {

private SmsClient client;

public TencentSmsClient(SmsChannelProperties properties) {
// TODO @FinallySays:注释的时候,中英文之间要空格哈
// 腾讯云发放短信的时候需要额外的参数sdkAppId, 所以和secretId组合在一起放到apiKey字段中,格式为[secretId sdkAppId],
// 这边需要做拆分重新封装到properties内
// 腾讯云发放短信的时候需要额外的参数 sdkAppId, 所以和 secretId 组合在一起放到 apiKey 字段中,格式为[secretId sdkAppId],
// 这边需要做拆分重新封装到 properties 内
super(TencentSmsChannelProperties.build(properties), new TencentSmsCodeMapping());
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}

@Override
protected void doInit() {
// init或者refresh时需要重新封装properties
// TODO @FinallySays:是不是不用这个变量呀?p
final SmsChannelProperties p = properties;
properties = TencentSmsChannelProperties.build(p);
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
// init 或者 refresh 时需要重新封装 properties
properties = TencentSmsChannelProperties.build(properties);
// 实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId,secretKey。
Credential credential = new Credential(properties.getApiKey(), properties.getApiSecret());
client = new SmsClient(credential, "ap-nanjing");
}
Expand All @@ -68,8 +63,7 @@ protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId,
String mobile,
String apiTemplateId,
List<KeyValue<String, Object>> templateParams) throws Throwable {

return invoke(() -> buildSendSmsRequest(sendLogId, mobile, apiTemplateId, templateParams), // TODO @FinallySays:上面不用空行
return invoke(() -> buildSendSmsRequest(sendLogId, mobile, apiTemplateId, templateParams),
this::doSendSms0,
response -> {
SendStatus sendStatus = response.getSendStatusSet()[0];
Expand All @@ -79,11 +73,11 @@ protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId,
}

/**
* 调用腾讯云SDK发送短信
* 调用腾讯云 SDK 发送短信
*
* @param request 发送短信请求
* @return 发送短信响应
* @throws TencentCloudSDKException SDK用来封装发送短信失败
* @throws TencentCloudSDKException SDK 用来封装发送短信失败
*/
private SendSmsResponse doSendSms0(SendSmsRequest request) throws TencentCloudSDKException {
return client.SendSms(request);
Expand All @@ -104,10 +98,10 @@ private SendSmsRequest buildSendSmsRequest(Long sendLogId,
List<KeyValue<String, Object>> templateParams) {
SendSmsRequest request = new SendSmsRequest();
request.setSmsSdkAppId(((TencentSmsChannelProperties) properties).getSdkAppId());
request.setPhoneNumberSet(CollectionUtils.toArray(Collections.singletonList(mobile)));
request.setPhoneNumberSet(new String[]{mobile});
request.setSignName(properties.getSignature());
request.setTemplateId(apiTemplateId);
request.setTemplateParamSet(CollectionUtils.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)));
return request;
}
Expand All @@ -120,11 +114,11 @@ protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Th
data.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription());
data.setReceiveTime(status.getReceiveTime()).setSuccess("SUCCESS".equalsIgnoreCase(status.getStatus()));
data.setMobile(status.getMobile()).setSerialNo(status.getSerialNo());
// TODO @FinallySays:建议直接判断是否为空,酱紫更易读一些
Optional.ofNullable(status.getSessionContext()).map(SessionContext::getLogId)
.ifPresentOrElse(data::setLogId, () -> {
throw new IllegalStateException(StrUtil.format("未回传logId,需联系腾讯云解决。"));
});
SessionContext context;
Long logId;
Assert.notNull(context = status.getSessionContext(), "回执信息中未解析出 context,请联系腾讯云小助手");
Assert.notNull(logId = context.getLogId(), "回执信息中未解析出 logId,请联系腾讯云小助手");
data.setLogId(logId);
return data;
});
}
Expand All @@ -146,7 +140,7 @@ SmsTemplateRespDTO convertTemplateStatusDTO(DescribeTemplateListStatus templateS
}
SmsTemplateAuditStatusEnum auditStatus;
Assert.notNull(templateStatus.getStatusCode(),
StrUtil.format("短信模版审核状态为null,模版id{}", templateStatus.getTemplateId()));
StrUtil.format("短信模版审核状态为 null,模版 id{}", templateStatus.getTemplateId()));
switch (templateStatus.getStatusCode().intValue()) {
case -1:
auditStatus = SmsTemplateAuditStatusEnum.FAIL;
Expand All @@ -158,7 +152,7 @@ SmsTemplateRespDTO convertTemplateStatusDTO(DescribeTemplateListStatus templateS
auditStatus = SmsTemplateAuditStatusEnum.CHECKING;
break;
default:
throw new IllegalStateException(StrUtil.format("不能解析短信模版审核状态{},模版id{}",
throw new IllegalStateException(StrUtil.format("不能解析短信模版审核状态{},模版 id{}",
templateStatus.getStatusCode(), templateStatus.getTemplateId()));
}
SmsTemplateRespDTO data = new SmsTemplateRespDTO();
Expand All @@ -169,24 +163,23 @@ SmsTemplateRespDTO convertTemplateStatusDTO(DescribeTemplateListStatus templateS

/**
* 封装查询模版审核状态请求
* @param apiTemplateId api的模版id
* @param apiTemplateId api 的模版 id
* @return 查询模版审核状态请求
*/
private DescribeSmsTemplateListRequest buildSmsTemplateStatusRequest(String apiTemplateId) {
DescribeSmsTemplateListRequest request = new DescribeSmsTemplateListRequest();
// TODO TODO @FinallySays: new Long[]{Long.parseLong(apiTemplateId)} 就 ok 啦
request.setTemplateIdSet(CollectionUtils.toArray(Collections.singletonList(apiTemplateId), Long::parseLong));
// 地区
request.setInternational(0L); // TODO @FinallySays:0L 最好说明下哈;
request.setTemplateIdSet(new Long[]{Long.parseLong(apiTemplateId)});
// 地区 0:表示国内短信。1:表示国际/港澳台短信。
request.setInternational(0L);
return request;
}

/**
* 调用腾讯云SDK查询短信模版状态
* 调用腾讯云 SDK 查询短信模版状态
*
* @param request 查询短信模版状态请求
* @return 查询短信模版状态响应
* @throws TencentCloudSDKException SDK用来封装查询短信模版状态失败
* @throws TencentCloudSDKException SDK 用来封装查询短信模版状态失败
*/
private DescribeSmsTemplateListResponse doGetSmsTemplate0(DescribeSmsTemplateListRequest request) throws TencentCloudSDKException {
return client.DescribeSmsTemplateList(request);
Expand Down Expand Up @@ -285,13 +278,12 @@ public static TencentSmsChannelProperties build(SmsChannelProperties properties)
return (TencentSmsChannelProperties) properties;
}
TencentSmsChannelProperties result = BeanUtil.toBean(properties, TencentSmsChannelProperties.class);
// TODO @FinallySays:comb=》combine,不缩写好点哈
String combKey = properties.getApiKey();
Assert.notEmpty(combKey, "apiKey 不能为空");
String[] keys = combKey.trim().split(" ");
// TODO @FinallySays:建议写多个断言好点,嘿嘿。然后 Assert 支持占位符
Assert.isTrue(keys.length == 2 && StrUtil.isNotBlank(keys[0]) && StrUtil.isNotBlank(keys[1]),
"腾讯云短信api配置格式错误,请配置为[secretId sdkAppId]");
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import cn.hutool.core.util.StrUtil;
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.CollectionUtils;
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.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
Expand Down Expand Up @@ -89,7 +89,7 @@ public void testDoSendSms() throws Throwable {
assertEquals(mobile, request.getPhoneNumberSet()[0]);
assertEquals(properties.getSignature(), request.getSignName());
assertEquals(apiTemplateId, request.getTemplateId());
assertEquals(toJsonString(CollectionUtils.toArray(new ArrayList<>(MapUtils.convertMap(templateParams).values()), String::valueOf)), toJsonString(request.getTemplateParamSet()));
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);
Expand Down

0 comments on commit 91f758c

Please sign in to comment.