【功能优化】短信:华为云的实现优化

This commit is contained in:
YunaiV 2024-08-18 19:52:48 +08:00
parent 8cce737523
commit 5b7e637ebf
8 changed files with 130 additions and 213 deletions

View File

@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import com.xingyuv.captcha.util.StreamUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@ -13,8 +12,6 @@ import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 短信回调")

View File

@ -26,15 +26,9 @@ public abstract class AbstractSmsClient implements SmsClient {
* 初始化
*/
public final void init() {
doInit();
log.debug("[init][配置({}) 初始化完成]", properties);
}
/**
* 自定义初始化
*/
protected abstract void doInit();
public final void refresh(SmsChannelProperties properties) {
// 判断是否更新
if (properties.equals(this.properties)) {

View File

@ -50,10 +50,6 @@ public class AliyunSmsClient extends AbstractSmsClient {
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
@Override
protected void doInit() {
}
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
List<KeyValue<String, Object>> templateParams) throws Throwable {
@ -80,7 +76,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
@Override
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
JSONArray statuses = JSONUtil.parseArray(text);
// 字段参考
// 字段参考 https://help.aliyun.com/zh/sms/developer-reference/smsreport-2
return convertList(statuses, status -> {
JSONObject statusObj = (JSONObject) status;
return new SmsReceiveRespDTO()
@ -166,7 +162,8 @@ public class AliyunSmsClient extends AbstractSmsClient {
String hashedRequestBody = DigestUtil.sha256Hex(requestBody);
// 4. 构建 Authorization 签名
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名

View File

@ -36,10 +36,6 @@ public class DebugDingTalkSmsClient extends AbstractSmsClient {
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
@Override
protected void doInit() {
}
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
@ -15,23 +17,19 @@ import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespD
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.time.LocalDateTime;
import static cn.hutool.crypto.digest.DigestUtil.sha256Hex;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
// todo @scholar参考阿里云在优化下
/**
* 华为短信客户端的实现类
*
@ -41,13 +39,11 @@ import static cn.hutool.crypto.digest.DigestUtil.sha256Hex;
@Slf4j
public class HuaweiSmsClient extends AbstractSmsClient {
public static final String URL = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1";//APP接入地址+接口访问URI
public static final String HOST = "smsapi.cn-north-4.myhuaweicloud.com:443";
public static final String SIGNEDHEADERS = "content-type;host;x-sdk-date";
private static final String URL = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1";//APP接入地址+接口访问URI
private static final String HOST = "smsapi.cn-north-4.myhuaweicloud.com:443";
private static final String SIGNEDHEADERS = "content-type;host;x-sdk-date";
@Override
protected void doInit() {
}
private static final String RESPONSE_CODE_SUCCESS = "000000";
public HuaweiSmsClient(SmsChannelProperties properties) {
super(properties);
@ -58,139 +54,96 @@ public class HuaweiSmsClient extends AbstractSmsClient {
@Override
public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
List<KeyValue<String, Object>> templateParams) throws Throwable {
// 1. 执行请求
// 参考链接 https://support.huaweicloud.com/api-msgsms/sms_05_0001.html
// 相比较阿里短信华为短信发送的时候需要额外的参数通道号考虑到不破坏原有的的结构
// 所以将 通道号 拼接到 apiTemplateId 字段中格式为 "apiTemplateId 通道号"空格为分隔符
String sender = StrUtil.subAfter(apiTemplateId, " ", true); //中国大陆短信签名通道号或全球短信通道号
String templateId = StrUtil.subBefore(apiTemplateId, " ", true); //模板ID
//选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
// 相比较阿里短信华为短信发送的时候需要额外的参数通道号考虑到不破坏原有的的结构
// 所以将 sender 通道号拼接到 apiTemplateId 字段中格式为 "apiTemplateId 通道号"空格为分隔符
String sender = apiTemplateId.split(" ")[1]; // 中国大陆短信签名通道号或全球短信通道号
String templateId = apiTemplateId.split(" ")[0]; //模板ID
String statusCallBack = properties.getCallbackUrl();
StringBuilder requestBody = new StringBuilder();
appendToBody(requestBody, "from=", sender);
appendToBody(requestBody, "&to=", mobile);
appendToBody(requestBody, "&templateId=", templateId);
appendToBody(requestBody, "&templateParas=", JsonUtils.toJsonString(
convertList(templateParams, kv -> String.valueOf(kv.getValue()))));
appendToBody(requestBody, "&statusCallback=", statusCallBack);
appendToBody(requestBody, "&extend=", String.valueOf(sendLogId));
JSONObject response = request("/sms/batchSendSms/v1/", "POST", requestBody.toString());
List<String> templateParas = CollectionUtils.convertList(templateParams, kv -> String.valueOf(kv.getValue()));
JSONObject JsonResponse = request(sendLogId,sender,mobile,templateId,templateParas,statusCallBack);
return new SmsSendRespDTO().setSuccess("000000".equals(JsonResponse.getStr("code")))
.setSerialNo(JsonResponse.getJSONArray("result").getJSONObject(0).getStr("smsMsgId"))
.setApiCode(JsonResponse.getJSONArray("result").getJSONObject(0).getStr("status"));
// 2. 解析请求
if (!response.containsKey("result")) { // 例如说密钥不正确
return new SmsSendRespDTO().setSuccess(false)
.setApiCode(response.getStr("code"))
.setApiMsg(response.getStr("description"));
}
JSONObject sendResult = response.getJSONArray("result").getJSONObject(0);
return new SmsSendRespDTO().setSuccess(RESPONSE_CODE_SUCCESS.equals(response.getStr("code")))
.setSerialNo(sendResult.getStr("smsMsgId")).setApiCode(sendResult.getStr("status"));
}
JSONObject request(Long sendLogId,String sender,String mobile,String templateId,List<String> templateParas,String statusCallBack) throws UnsupportedEncodingException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String sdkDate = sdf.format(new Date());
// ************* 步骤 1拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/sms/batchSendSms/v1/";
String canonicalQueryString = "";//查询参数为空
String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n"
+ "host:"+ HOST +"\n"
+ "x-sdk-date:" + sdkDate + "\n";
String body = buildRequestBody(sender, mobile, templateId, templateParas, statusCallBack, sendLogId);
if (null == body || body.isEmpty()) {
return null;
}
String hashedRequestBody = sha256Hex(body);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + SIGNEDHEADERS + "\n" + hashedRequestBody;
// ************* 步骤 2拼接待签名字符串 *************
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = "SDK-HMAC-SHA256" + "\n" + sdkDate + "\n" + hashedCanonicalRequest;
// ************* 步骤 3计算签名 *************
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign);
// ************* 步骤 4拼接 Authorization *************
String authorization = "SDK-HMAC-SHA256" + " " + "Access=" + properties.getApiKey() + ", "
+ "SignedHeaders=" + SIGNEDHEADERS + ", " + "Signature=" + signature;
// ************* 步骤 5构造HttpRequest 并执行request请求获得response *************
/**
* 请求华为云短信
*
* @see <a href="认证鉴权">https://support.huaweicloud.com/api-msgsms/sms_05_0046.html</a>
* @param uri 请求 URI
* @param method 请求 Method
* @param requestBody 请求 Body
* @return 请求结果
*/
private JSONObject request(String uri, String method, String requestBody) {
// 1.1 请求 Header
TreeMap<String, String> headers = new TreeMap<>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
String sdkDate = FastDateFormat.getInstance("yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone("UTC")).format(new Date());
headers.put("X-Sdk-Date", sdkDate);
headers.put("host", HOST);
headers.put("Authorization", authorization);
String responseBody = HttpUtils.post(URL, headers, body);
// 1.2 构建签名 Header
String canonicalQueryString = ""; // 查询参数为空
String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n"
+ "host:"+ HOST +"\n" + "x-sdk-date:" + sdkDate + "\n";
String canonicalRequest = method + "\n" + uri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + SIGNEDHEADERS + "\n" + sha256Hex(requestBody);
String stringToSign = "SDK-HMAC-SHA256" + "\n" + sdkDate + "\n" + sha256Hex(canonicalRequest);
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
headers.put("Authorization", "SDK-HMAC-SHA256" + " " + "Access=" + properties.getApiKey()
+ ", " + "SignedHeaders=" + SIGNEDHEADERS + ", " + "Signature=" + signature);
// 2. 发起请求
String responseBody = HttpUtils.post(URL, headers, requestBody);
return JSONUtil.parseObj(responseBody);
//
//
// HttpResponse response = HttpRequest.post(URL)
// .header("Content-Type", "application/x-www-form-urlencoded")
// .header("X-Sdk-Date", sdkDate)
// .header("host",HOST)
// .header("Authorization", authorization)
// .body(body)
// .execute();
//
// return JSONUtil.parseObj(response.body());
}
static String buildRequestBody(String sender, String receiver, String templateId, List<String> templateParas,
String statusCallBack, Long sendLogId) throws UnsupportedEncodingException {
if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
|| templateId.isEmpty()) {
System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
return null;
}
StringBuilder body = new StringBuilder();
appendToBody(body, "from=", sender);
appendToBody(body, "&to=", receiver);
appendToBody(body, "&templateId=", templateId);
appendToBody(body, "&templateParas=", JsonUtils.toJsonString(templateParas));
appendToBody(body, "&statusCallback=", statusCallBack);
appendToBody(body, "&signature=", null);
appendToBody(body, "&extend=", String.valueOf(sendLogId));
return body.toString();
}
private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException {
if (null != val && !val.isEmpty()) {
body.append(key).append(URLEncoder.encode(val, "UTF-8"));
}
}
@Override
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String requestBody) {
System.out.println("text in parseSmsReceiveStatus===== " + requestBody);
Map<String, String> params = new HashMap<>();
try {
String[] pairs = requestBody.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
String key = URLDecoder.decode(pair.substring(0, idx), "UTF-8");
String value = URLDecoder.decode(pair.substring(idx + 1), "UTF-8");
params.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
List<SmsReceiveRespDTO> respDTOS = new ArrayList<>();
respDTOS.add(new SmsReceiveRespDTO()
Map<String, String> params = HttpUtil.decodeParamMap(requestBody, StandardCharsets.UTF_8);
// 字段参考 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html
return ListUtil.of(new SmsReceiveRespDTO()
.setSuccess("DELIVRD".equals(params.get("status"))) // 是否接收成功
.setErrorCode(params.get("status")) // 状态报告编码
.setErrorMsg(params.get("statusDesc"))
.setMobile(params.get("to")) // 手机号
.setReceiveTime(LocalDateTime.ofInstant(Instant.parse(params.get("updateTime")), ZoneId.of("UTC"))) // 状态报告时间
.setSerialNo(params.get("smsMsgId")) // 发送序列号
.setLogId(Long.valueOf(params.get("extend")))//logId
);
return respDTOS;
.setLogId(Long.valueOf(params.get("extend")))); // 用户序列号
}
@Override
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
//华为短信模板查询和发送短信是不同的两套key和secret与阿里腾讯的区别较大这里模板查询校验暂不实现
return new SmsTemplateRespDTO().setId(null).setContent(null)
// 相比较阿里短信华为短信发送的时候需要额外的参数通道号考虑到不破坏原有的的结构
// 所以将 sender 通道号拼接到 apiTemplateId 字段中格式为 "apiTemplateId 通道号"空格为分隔符
String[] strs = apiTemplateId.split(" ");
Assert.isTrue(strs.length == 2, "格式不正确需要满足apiTemplateId sender");
return new SmsTemplateRespDTO().setId(strs[0]).setContent(null)
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null);
}
@SuppressWarnings("CharsetObjectCanBeUsed")
private static void appendToBody(StringBuilder body, String key, String value) throws UnsupportedEncodingException {
if (StrUtil.isNotEmpty(value)) {
body.append(key).append(URLEncoder.encode(value, CharsetUtil.CHARSET_UTF_8.name()));
}
}
}

View File

@ -56,10 +56,6 @@ public class TencentSmsClient extends AbstractSmsClient {
validateSdkAppId(properties);
}
@Override
protected void doInit() {
}
/**
* 参数校验腾讯云的 SDK AppId
*

View File

@ -36,15 +36,8 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
@InjectMocks
private HuaweiSmsClient smsClient = new HuaweiSmsClient(properties);
@Test
public void testDoInit() {
// 调用
smsClient.doInit();
}
@Test
public void testDoSendSms_success() throws Throwable {
try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
// 准备参数
Long sendLogId = randomLongId();
@ -55,9 +48,7 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
// mock 方法
httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
.thenReturn(
"{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"000000\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"000000\",\"description\":\"Success\"}\n"
);
.thenReturn("{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"000000\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"000000\",\"description\":\"Success\"}\n");
// 调用
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
@ -66,12 +57,11 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
assertTrue(result.getSuccess());
assertEquals("d6e3cdd0-522b-4692-8304-a07553cdf591_8539659", result.getSerialNo());
assertEquals("000000", result.getApiCode());
}
}
@Test
public void testDoSendSms_fail() throws Throwable {
public void testDoSendSms_fail_01() throws Throwable {
try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
// 准备参数
Long sendLogId = randomLongId();
@ -82,17 +72,39 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
// mock 方法
httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
.thenReturn(
"{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"E200015\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"E000000\",\"description\":\"Success\"}\n"
);
.thenReturn("{\"result\":[{\"total\":1,\"originTo\":\"17321315478\",\"createTime\":\"2024-08-18T11:32:20Z\",\"from\":\"x8824060312575\",\"smsMsgId\":\"06e4b966-ad87-479f-8b74-f57fb7aafb60_304613461\",\"countryId\":\"CN\",\"status\":\"E200033\"}],\"code\":\"E000510\",\"description\":\"The SMS fails to be sent. For details, see status.\"}");
// 调用
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
apiTemplateId, templateParams);
// 断言
assertFalse(result.getSuccess());
assertEquals("d6e3cdd0-522b-4692-8304-a07553cdf591_8539659", result.getSerialNo());
assertEquals("E200015", result.getApiCode());
assertEquals("06e4b966-ad87-479f-8b74-f57fb7aafb60_304613461", result.getSerialNo());
assertEquals("E200033", result.getApiCode());
}
}
@Test
public void testDoSendSms_fail_02() throws Throwable {
try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
// 准备参数
Long sendLogId = randomLongId();
String mobile = randomString();
String apiTemplateId = randomString() + " " + randomString();
List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
new KeyValue<>("1", 1234), new KeyValue<>("2", "login"));
// mock 方法
httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString()))
.thenReturn("{\"code\":\"E000102\",\"description\":\"Invalid app_key.\"}");
// 调用
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
apiTemplateId, templateParams);
// 断言
assertFalse(result.getSuccess());
assertEquals("E000102", result.getApiCode());
assertEquals("Invalid app_key.", result.getApiMsg());
}
}
@ -105,10 +117,11 @@ public class HuaweiSmsClientTest extends BaseMockitoUnitTest {
List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
// 断言
assertEquals(1, statuses.size());
assertTrue(statuses.getFirst().getSuccess());
assertEquals("DELIVRD", statuses.getFirst().getErrorCode());
assertEquals(LocalDateTime.of(2024, 8, 15, 3, 0, 34), statuses.getFirst().getReceiveTime());
assertEquals("70207ed7-1d02-41b0-8537-bb25fd1c2364_143684459", statuses.getFirst().getSerialNo());
SmsReceiveRespDTO status = statuses.get(0);
assertTrue(status.getSuccess());
assertEquals("DELIVRD", status.getErrorCode());
assertEquals(LocalDateTime.of(2024, 8, 15, 3, 0, 34), status.getReceiveTime());
assertEquals("70207ed7-1d02-41b0-8537-bb25fd1c2364_143684459", status.getSerialNo());
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.module.system.framework.sms.core.client.SmsClient;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test;
import java.util.List;
/**
* 各种 {@link SmsClientTests 集成测试
* 各种 {@link SmsClient} 集成测试
*
* @author 芋道源码
*/
@ -23,8 +23,8 @@ public class SmsClientTests {
@Disabled
public void testAliyunSmsClient_getSmsTemplate() throws Throwable {
SmsChannelProperties properties = new SmsChannelProperties()
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz");
.setApiKey(System.getenv("SMS_ALIYUN_ACCESS_KEY"))
.setApiSecret(System.getenv("SMS_ALIYUN_SECRET_KEY"));
AliyunSmsClient client = new AliyunSmsClient(properties);
// 准备参数
String apiTemplateId = "SMS_207945135";
@ -38,9 +38,9 @@ public class SmsClientTests {
@Disabled
public void testAliyunSmsClient_sendSms() throws Throwable {
SmsChannelProperties properties = new SmsChannelProperties()
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
.setSignature("runpu");
.setApiKey(System.getenv("SMS_ALIYUN_ACCESS_KEY"))
.setApiSecret(System.getenv("SMS_ALIYUN_SECRET_KEY"))
.setSignature("Ballcat");
AliyunSmsClient client = new AliyunSmsClient(properties);
// 准备参数
Long sendLogId = System.currentTimeMillis();
@ -52,35 +52,6 @@ public class SmsClientTests {
System.out.println(sendRespDTO);
}
@Test
@Disabled
public void testAliyunSmsClient_parseSmsReceiveStatus() {
SmsChannelProperties properties = new SmsChannelProperties()
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz");
AliyunSmsClient client = new AliyunSmsClient(properties);
// 准备参数
String text = "[\n" +
" {\n" +
" \"phone_number\" : \"13900000001\",\n" +
" \"send_time\" : \"2017-01-01 11:12:13\",\n" +
" \"report_time\" : \"2017-02-02 22:23:24\",\n" +
" \"success\" : true,\n" +
" \"err_code\" : \"DELIVERED\",\n" +
" \"err_msg\" : \"用户接收成功\",\n" +
" \"sms_size\" : \"1\",\n" +
" \"biz_id\" : \"12345\",\n" +
" \"out_id\" : \"67890\"\n" +
" }\n" +
"]";
// mock 方法
// 调用
List<SmsReceiveRespDTO> statuses = client.parseSmsReceiveStatus(text);
// 打印结果
System.out.println(statuses);
}
// ========== 腾讯云 ==========
@Test
@ -123,14 +94,14 @@ public class SmsClientTests {
@Disabled
public void testHuaweiSmsClient_sendSms() throws Throwable {
SmsChannelProperties properties = new SmsChannelProperties()
.setApiKey("123")
.setApiSecret("456")
.setApiKey(System.getenv("SMS_HUAWEI_ACCESS_KEY"))
.setApiSecret(System.getenv("SMS_HUAWEI_SECRET_KEY"))
.setSignature("runpu");
HuaweiSmsClient client = new HuaweiSmsClient(properties);
// 准备参数
Long sendLogId = System.currentTimeMillis();
String mobile = "15601691323";
String apiTemplateId = "xx test01";
String mobile = "17321315478";
String apiTemplateId = "3644cdab863546a3b718d488659a99ef x8824060312575";
List<KeyValue<String, Object>> templateParams = List.of(new KeyValue<>("code", "1024"));
// 调用
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);