mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-22 15:21:53 +08:00
增加七牛云短信实现
This commit is contained in:
parent
efc5ea23bf
commit
4f7ac969fe
@ -5,6 +5,8 @@ import cn.hutool.core.map.TableMap;
|
|||||||
import cn.hutool.core.net.url.UrlBuilder;
|
import cn.hutool.core.net.url.UrlBuilder;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.util.UriComponents;
|
import org.springframework.web.util.UriComponents;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
@ -122,5 +124,43 @@ public class HttpUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP post 请求,基于 {@link cn.hutool.http.HttpUtil} 实现
|
||||||
|
*
|
||||||
|
* 为什么要封装该方法,因为 HttpUtil 默认封装的方法,没有允许传递 headers 参数
|
||||||
|
*
|
||||||
|
* @param url URL
|
||||||
|
* @param headers 请求头
|
||||||
|
* @param requestBody 请求体
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
public static String post(String url, Map<String, String> headers, String requestBody) {
|
||||||
|
|
||||||
|
try (HttpResponse response = HttpRequest.post(url)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.body(requestBody)
|
||||||
|
.execute()) {
|
||||||
|
return response.body();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP get 请求,基于 {@link cn.hutool.http.HttpUtil} 实现
|
||||||
|
*
|
||||||
|
* 为什么要封装该方法,因为 HttpUtil 默认封装的方法,没有允许传递 headers 参数
|
||||||
|
*
|
||||||
|
* @param url URL
|
||||||
|
* @param headers 请求头
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
public static String get(String url, Map<String, String> headers) {
|
||||||
|
|
||||||
|
try (HttpResponse response = HttpRequest.get(url)
|
||||||
|
.addHeaders(headers)
|
||||||
|
.execute()) {
|
||||||
|
return response.body();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.sms;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
|
|
||||||
import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum;
|
import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum;
|
||||||
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -14,8 +12,6 @@ import jakarta.annotation.Resource;
|
|||||||
import jakarta.annotation.security.PermitAll;
|
import jakarta.annotation.security.PermitAll;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 短信回调")
|
@Tag(name = "管理后台 - 短信回调")
|
||||||
@ -29,7 +25,6 @@ public class SmsCallbackController {
|
|||||||
@PostMapping("/aliyun")
|
@PostMapping("/aliyun")
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/document_detail/120998.html 文档")
|
@Operation(summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/document_detail/120998.html 文档")
|
||||||
@OperateLog(enable = false)
|
|
||||||
public CommonResult<Boolean> receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable {
|
public CommonResult<Boolean> receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable {
|
||||||
String text = ServletUtils.getBody(request);
|
String text = ServletUtils.getBody(request);
|
||||||
smsSendService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text);
|
smsSendService.receiveSmsStatus(SmsChannelEnum.ALIYUN.getCode(), text);
|
||||||
@ -39,7 +34,6 @@ public class SmsCallbackController {
|
|||||||
@PostMapping("/tencent")
|
@PostMapping("/tencent")
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/52077 文档")
|
@Operation(summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/52077 文档")
|
||||||
@OperateLog(enable = false)
|
|
||||||
public CommonResult<Boolean> receiveTencentSmsStatus(HttpServletRequest request) throws Throwable {
|
public CommonResult<Boolean> receiveTencentSmsStatus(HttpServletRequest request) throws Throwable {
|
||||||
String text = ServletUtils.getBody(request);
|
String text = ServletUtils.getBody(request);
|
||||||
smsSendService.receiveSmsStatus(SmsChannelEnum.TENCENT.getCode(), text);
|
smsSendService.receiveSmsStatus(SmsChannelEnum.TENCENT.getCode(), text);
|
||||||
@ -50,9 +44,18 @@ public class SmsCallbackController {
|
|||||||
@PostMapping("/huawei")
|
@PostMapping("/huawei")
|
||||||
@PermitAll
|
@PermitAll
|
||||||
@Operation(summary = "华为云短信的回调", description = "参见 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html 文档")
|
@Operation(summary = "华为云短信的回调", description = "参见 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html 文档")
|
||||||
@OperateLog(enable = false)
|
|
||||||
public CommonResult<Boolean> receiveHuaweiSmsStatus(@RequestBody String requestBody) throws Throwable {
|
public CommonResult<Boolean> receiveHuaweiSmsStatus(@RequestBody String requestBody) throws Throwable {
|
||||||
smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), requestBody);
|
smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), requestBody);
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/qiniu")
|
||||||
|
@PermitAll
|
||||||
|
@Operation(summary = "七牛云短信的回调", description = "参见 https://developer.qiniu.com/sms/5910/message-push 文档")
|
||||||
|
public CommonResult<Boolean> receiveQiniuSmsStatus(@RequestBody String requestBody) throws Throwable {
|
||||||
|
smsSendService.receiveSmsStatus(SmsChannelEnum.QINIU.getCode(), requestBody);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,172 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.crypto.digest.HMac;
|
||||||
|
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||||
|
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.http.HttpUtils;
|
||||||
|
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
|
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.enums.SmsTemplateAuditStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 七牛云短信客户端的实现类
|
||||||
|
*
|
||||||
|
* @author scholar
|
||||||
|
* @since 2024/08/26 15:35
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class QiniuSmsClient extends AbstractSmsClient {
|
||||||
|
|
||||||
|
private static final String HOST = "sms.qiniuapi.com";
|
||||||
|
|
||||||
|
private static final String PATH = "/v1/message/single";
|
||||||
|
|
||||||
|
private static final String TEMPLATE_PATH = "/v1/template";
|
||||||
|
|
||||||
|
public QiniuSmsClient(SmsChannelProperties properties) {
|
||||||
|
super(properties);
|
||||||
|
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
|
||||||
|
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 {
|
||||||
|
|
||||||
|
// 1. 执行请求
|
||||||
|
// 参考链接 https://developer.qiniu.com/sms/5824/through-the-api-send-text-messages
|
||||||
|
LinkedHashMap<String, Object> body = new LinkedHashMap<>();
|
||||||
|
Map<String, Object> paramsMap = templateParams.stream()
|
||||||
|
.collect(Collectors.toMap(KeyValue::getKey, KeyValue::getValue));
|
||||||
|
|
||||||
|
body.put("template_id", apiTemplateId);
|
||||||
|
body.put("mobile", mobile);
|
||||||
|
body.put("parameters", paramsMap);
|
||||||
|
body.put("seq", Long.toString(sendLogId));
|
||||||
|
|
||||||
|
JSONObject response = request("POST", body, null);
|
||||||
|
// 2. 解析请求
|
||||||
|
return new SmsSendRespDTO().setSuccess(response.containsKey("message_id"))
|
||||||
|
.setSerialNo(response.getStr("message_id"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求七牛云短信
|
||||||
|
*
|
||||||
|
* @see <a href="https://developer.qiniu.com/sms/5842/sms-api-authentication"</>
|
||||||
|
* @param httpMethod http请求方法
|
||||||
|
* @param queryParams 请求参数
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
private JSONObject request(String httpMethod, LinkedHashMap<String, Object> body, Map<String, Object> queryParams) {
|
||||||
|
|
||||||
|
String signature = "";
|
||||||
|
String templateIdPath = "";
|
||||||
|
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||||
|
String signDate = dateFormat.format(new Date());
|
||||||
|
|
||||||
|
//请求头
|
||||||
|
Map<String, String> header = new HashMap<>(4);
|
||||||
|
header.put("HOST", HOST);
|
||||||
|
header.put("Authorization", signature);
|
||||||
|
header.put("Content-Type", "application/json");
|
||||||
|
header.put("X-Qiniu-Date", signDate);
|
||||||
|
|
||||||
|
String responseBody ="";
|
||||||
|
if(Objects.equals(httpMethod, "POST")){
|
||||||
|
header.put("Authorization", getSignature(httpMethod, HOST, PATH, JSONUtil.toJsonStr(body), signDate));
|
||||||
|
responseBody = HttpUtils.post("https://" + HOST + PATH, header, JSONUtil.toJsonStr(body));
|
||||||
|
}else { // GET
|
||||||
|
templateIdPath = TEMPLATE_PATH + "/" + queryParams.get("template_id");
|
||||||
|
header.put("Authorization", getSignature(httpMethod, HOST, templateIdPath, null, signDate));
|
||||||
|
responseBody = HttpUtils.get("https://" + HOST + templateIdPath, header);
|
||||||
|
}
|
||||||
|
return JSONUtil.parseObj(responseBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignature(String method, String host, String path, String body, String signDate) {
|
||||||
|
|
||||||
|
StringBuilder dataToSign = new StringBuilder();
|
||||||
|
dataToSign.append(method.toUpperCase()).append(" ").append(path);
|
||||||
|
dataToSign.append("\nHost: ").append(host);
|
||||||
|
dataToSign.append("\n").append("Content-Type").append(": ").append("application/json");
|
||||||
|
dataToSign.append("\n").append("X-Qiniu-Date").append(": ").append(signDate);
|
||||||
|
dataToSign.append("\n\n");
|
||||||
|
if (ObjectUtil.isNotEmpty(body)) {
|
||||||
|
dataToSign.append(body);
|
||||||
|
}
|
||||||
|
HMac hMac = new HMac(HmacAlgorithm.HmacSHA1, properties.getApiSecret().getBytes(StandardCharsets.UTF_8));
|
||||||
|
byte[] signData = hMac.digest(dataToSign.toString().getBytes(StandardCharsets.UTF_8));
|
||||||
|
String encodedSignature = Base64.getEncoder().encodeToString(signData);
|
||||||
|
|
||||||
|
return "Qiniu " + properties.getApiKey() + ":" + encodedSignature;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||||
|
|
||||||
|
JSONObject status = JSONUtil.parseObj(text);
|
||||||
|
//字段参考 https://developer.qiniu.com/sms/5910/message-push
|
||||||
|
return ListUtil.of(new SmsReceiveRespDTO()
|
||||||
|
.setSuccess("DELIVRD".equals(status.getJSONArray("items").getJSONObject(0).getStr("status"))) // 是否接收成功
|
||||||
|
.setErrorMsg(status.getJSONArray("items").getJSONObject(0).getStr("status"))
|
||||||
|
.setMobile(status.getJSONArray("items").getJSONObject(0).getStr("mobile")) // 手机号
|
||||||
|
.setReceiveTime(LocalDateTimeUtil.of(status.getJSONArray("items").getJSONObject(0).getLong("delivrd_at")*1000L))
|
||||||
|
.setSerialNo(status.getJSONArray("items").getJSONObject(0).getStr("message_id")) // 发送序列号
|
||||||
|
.setLogId(Long.valueOf(status.getJSONArray("items").getJSONObject(0).getStr("seq")))); // logId
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
|
||||||
|
// 1. 执行请求
|
||||||
|
// 参考链接 https://developer.qiniu.com/sms/5969/query-a-single-template
|
||||||
|
HashMap<String, Object> queryParam = new HashMap<>();
|
||||||
|
queryParam.put("template_id", apiTemplateId);
|
||||||
|
JSONObject response = request("GET", null, queryParam);
|
||||||
|
|
||||||
|
// 2.1 请求失败
|
||||||
|
String status = response.getStr("audit_status");
|
||||||
|
if (!Objects.equals(status, "passed")) {
|
||||||
|
log.error("[getSmsTemplate][模版编号({}) 响应不正确({})]", apiTemplateId, response);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 2.2 请求成功
|
||||||
|
return new SmsTemplateRespDTO()
|
||||||
|
.setId(response.getStr("id"))
|
||||||
|
.setContent(response.getStr("template"))
|
||||||
|
.setAuditStatus(convertSmsTemplateAuditStatus(response.getStr("audit_status")))
|
||||||
|
.setAuditReason(response.getStr("reject_reason"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Integer convertSmsTemplateAuditStatus(String templateStatus) {
|
||||||
|
|
||||||
|
if(Objects.equals(templateStatus, "passed")){
|
||||||
|
return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
|
||||||
|
}else {
|
||||||
|
throw new IllegalArgumentException(String.format("未知审核状态(%str)", templateStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ public enum SmsChannelEnum {
|
|||||||
ALIYUN("ALIYUN", "阿里云"),
|
ALIYUN("ALIYUN", "阿里云"),
|
||||||
TENCENT("TENCENT", "腾讯云"),
|
TENCENT("TENCENT", "腾讯云"),
|
||||||
HUAWEI("HUAWEI", "华为云"),
|
HUAWEI("HUAWEI", "华为云"),
|
||||||
|
QINIU("QINIU", "七牛云"),
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,3 +35,4 @@ public enum SmsChannelEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,128 @@
|
|||||||
|
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
|
||||||
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
|
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||||
|
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.enums.SmsTemplateAuditStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mockStatic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link QiniuSmsClient} 的单元测试
|
||||||
|
*
|
||||||
|
* @author scholar
|
||||||
|
*/
|
||||||
|
public class QiniuSmsClientTest extends BaseMockitoUnitTest {
|
||||||
|
|
||||||
|
private final SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
|
.setApiKey(randomString())// 随机一个 apiKey,避免构建报错
|
||||||
|
.setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错
|
||||||
|
.setSignature("芋道源码");
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private QiniuSmsClient smsClient = new QiniuSmsClient(properties);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoInit() {
|
||||||
|
// 调用
|
||||||
|
smsClient.doInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoSendSms_success() 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(
|
||||||
|
"{\"message_id\":\"17245678901\"}"
|
||||||
|
);
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||||
|
apiTemplateId, templateParams);
|
||||||
|
// 断言
|
||||||
|
assertTrue(result.getSuccess());
|
||||||
|
assertEquals("17245678901", result.getSerialNo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoSendSms_fail() 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(
|
||||||
|
"{\"error\":\"BadToken\",\"message\":\"Your authorization token is invalid\",\"request_id\":\"etziWcJFo1C8Ne8X\"}"
|
||||||
|
);
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile,
|
||||||
|
apiTemplateId, templateParams);
|
||||||
|
// 断言
|
||||||
|
assertFalse(result.getSuccess());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSmsTemplate() throws Throwable {
|
||||||
|
try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) {
|
||||||
|
// 准备参数
|
||||||
|
String apiTemplateId = randomString();
|
||||||
|
// mock 方法
|
||||||
|
httpUtilsMockedStatic.when(() -> HttpUtils.get(anyString(), anyMap()))
|
||||||
|
.thenReturn("{\"audit_status\":\"passed\",\"created_at\":1724231187,\"description\":\"\",\"disable_broadcast\":false,\"disable_broadcast_reason\":\"\",\"disable_reason\":\"\",\"disabled\":false,\"id\":\"1826184073773596672\",\"is_oversea\":false,\"name\":\"dd\",\"parameters\":[\"code\"],\"reject_reason\":\"\",\"signature_id\":\"1826099896017498112\",\"signature_text\":\"yudao\",\"template\":\"您的验证码为:${code}\",\"type\":\"verification\",\"uid\":1383022432,\"updated_at\":1724288561,\"variable_count\":0}");
|
||||||
|
// 调用
|
||||||
|
SmsTemplateRespDTO result = smsClient.getSmsTemplate(apiTemplateId);
|
||||||
|
// 断言
|
||||||
|
assertEquals("1826184073773596672", result.getId());
|
||||||
|
assertEquals("您的验证码为:${code}", result.getContent());
|
||||||
|
assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getAuditStatus());
|
||||||
|
assertEquals("", result.getAuditReason());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseSmsReceiveStatus() {
|
||||||
|
// 准备参数
|
||||||
|
String text = "{\"items\":[{\"mobile\":\"18881234567\",\"message_id\":\"10135515063508004167\",\"status\":\"DELIVRD\",\"delivrd_at\":1724591666,\"error\":\"DELIVRD\",\"seq\":\"123\"}]}";
|
||||||
|
// 调用
|
||||||
|
List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text);
|
||||||
|
// 断言
|
||||||
|
assertEquals(1, statuses.size());
|
||||||
|
assertTrue(statuses.getFirst().getSuccess());
|
||||||
|
assertEquals("DELIVRD", statuses.getFirst().getErrorMsg());
|
||||||
|
assertEquals(LocalDateTime.of(2024, 8, 25, 21, 14, 26), statuses.getFirst().getReceiveTime());
|
||||||
|
assertEquals("18881234567", statuses.getFirst().getMobile());
|
||||||
|
assertEquals("10135515063508004167", statuses.getFirst().getSerialNo());
|
||||||
|
assertEquals(123, statuses.getFirst().getLogId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
|
package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
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.SmsSendRespDTO;
|
||||||
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||||
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
|
import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
|
||||||
@ -11,39 +11,19 @@ import org.junit.jupiter.api.Test;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 各种 {@link SmsClientTests 集成测试
|
* 各种 {@link SmsClient} 的集成测试
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
public class SmsClientTests {
|
public class SmsClientTests {
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
public void testHuaweiSmsClient_sendSms() throws Throwable {
|
|
||||||
SmsChannelProperties properties = new SmsChannelProperties()
|
|
||||||
.setApiKey("123")
|
|
||||||
.setApiSecret("456")
|
|
||||||
.setSignature("runpu");
|
|
||||||
HuaweiSmsClient client = new HuaweiSmsClient(properties);
|
|
||||||
// 准备参数
|
|
||||||
Long sendLogId = System.currentTimeMillis();
|
|
||||||
String mobile = "15601691323";
|
|
||||||
String apiTemplateId = "xx test01";
|
|
||||||
List<KeyValue<String, Object>> templateParams = List.of(new KeyValue<>("code", "1024"));
|
|
||||||
// 调用
|
|
||||||
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
|
||||||
// 打印结果
|
|
||||||
System.out.println(smsSendRespDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== 阿里云 ==========
|
// ========== 阿里云 ==========
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
public void testAliyunSmsClient_getSmsTemplate() throws Throwable {
|
public void testAliyunSmsClient_getSmsTemplate() throws Throwable {
|
||||||
SmsChannelProperties properties = new SmsChannelProperties()
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
|
.setApiKey(System.getenv("SMS_ALIYUN_ACCESS_KEY"))
|
||||||
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz");
|
.setApiSecret(System.getenv("SMS_ALIYUN_SECRET_KEY"));
|
||||||
AliyunSmsClient client = new AliyunSmsClient(properties);
|
AliyunSmsClient client = new AliyunSmsClient(properties);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
String apiTemplateId = "SMS_207945135";
|
String apiTemplateId = "SMS_207945135";
|
||||||
@ -57,9 +37,9 @@ public class SmsClientTests {
|
|||||||
@Disabled
|
@Disabled
|
||||||
public void testAliyunSmsClient_sendSms() throws Throwable {
|
public void testAliyunSmsClient_sendSms() throws Throwable {
|
||||||
SmsChannelProperties properties = new SmsChannelProperties()
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR")
|
.setApiKey(System.getenv("SMS_ALIYUN_ACCESS_KEY"))
|
||||||
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
|
.setApiSecret(System.getenv("SMS_ALIYUN_SECRET_KEY"))
|
||||||
.setSignature("runpu");
|
.setSignature("Ballcat");
|
||||||
AliyunSmsClient client = new AliyunSmsClient(properties);
|
AliyunSmsClient client = new AliyunSmsClient(properties);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long sendLogId = System.currentTimeMillis();
|
Long sendLogId = System.currentTimeMillis();
|
||||||
@ -71,49 +51,21 @@ public class SmsClientTests {
|
|||||||
System.out.println(sendRespDTO);
|
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
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
public void testTencentSmsClient_sendSms() throws Throwable {
|
public void testTencentSmsClient_sendSms() throws Throwable {
|
||||||
|
String sdkAppId = "1400500458";
|
||||||
SmsChannelProperties properties = new SmsChannelProperties()
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR 1428926523")
|
.setApiKey(System.getenv("SMS_TENCENT_ACCESS_KEY") + " " + sdkAppId)
|
||||||
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
|
.setApiSecret(System.getenv("SMS_TENCENT_SECRET_KEY"))
|
||||||
.setSignature("芋道源码");
|
.setSignature("芋道源码");
|
||||||
TencentSmsClient client = new TencentSmsClient(properties);
|
TencentSmsClient client = new TencentSmsClient(properties);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long sendLogId = System.currentTimeMillis();
|
Long sendLogId = System.currentTimeMillis();
|
||||||
String mobile = "15601691323";
|
String mobile = "15601691323";
|
||||||
String apiTemplateId = "2136358";
|
String apiTemplateId = "358212";
|
||||||
// 调用
|
// 调用
|
||||||
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, List.of(new KeyValue<>("code", "1024")));
|
SmsSendRespDTO sendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, List.of(new KeyValue<>("code", "1024")));
|
||||||
// 打印结果
|
// 打印结果
|
||||||
@ -123,17 +75,77 @@ public class SmsClientTests {
|
|||||||
@Test
|
@Test
|
||||||
@Disabled
|
@Disabled
|
||||||
public void testTencentSmsClient_getSmsTemplate() throws Throwable {
|
public void testTencentSmsClient_getSmsTemplate() throws Throwable {
|
||||||
|
String sdkAppId = "1400500458";
|
||||||
SmsChannelProperties properties = new SmsChannelProperties()
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
.setApiKey("LTAI5tAicJAxaSFiZuGGeXHR 1428926523")
|
.setApiKey(System.getenv("SMS_TENCENT_ACCESS_KEY") + " " + sdkAppId)
|
||||||
.setApiSecret("Fdr9vadxnDvS6GJU0W1tijQ0VmLhYz")
|
.setApiSecret(System.getenv("SMS_TENCENT_SECRET_KEY"))
|
||||||
.setSignature("芋道源码");
|
.setSignature("芋道源码");
|
||||||
TencentSmsClient client = new TencentSmsClient(properties);
|
TencentSmsClient client = new TencentSmsClient(properties);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
String apiTemplateId = "2136358";
|
String apiTemplateId = "358212";
|
||||||
// 调用
|
// 调用
|
||||||
SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
|
SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
|
||||||
// 打印结果
|
// 打印结果
|
||||||
System.out.println(template);
|
System.out.println(template);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// ========== 华为云 ==========
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void testHuaweiSmsClient_sendSms() throws Throwable {
|
||||||
|
String sender = "x8824060312575";
|
||||||
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
|
.setApiKey(System.getenv("SMS_HUAWEI_ACCESS_KEY") + " " + sender)
|
||||||
|
.setApiSecret(System.getenv("SMS_HUAWEI_SECRET_KEY"))
|
||||||
|
.setSignature("runpu");
|
||||||
|
HuaweiSmsClient client = new HuaweiSmsClient(properties);
|
||||||
|
// 准备参数
|
||||||
|
Long sendLogId = System.currentTimeMillis();
|
||||||
|
String mobile = "17321315478";
|
||||||
|
String apiTemplateId = "3644cdab863546a3b718d488659a99ef";
|
||||||
|
List<KeyValue<String, Object>> templateParams = List.of(new KeyValue<>("code", "1024"));
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||||
|
// 打印结果
|
||||||
|
System.out.println(smsSendRespDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 七牛云 ==========
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void testQiniuSmsClient_sendSms() throws Throwable {
|
||||||
|
|
||||||
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
|
.setApiKey("SMS_QINIU_ACCESS_KEY")
|
||||||
|
.setApiSecret("SMS_QINIU_SECRET_KEY");
|
||||||
|
QiniuSmsClient client = new QiniuSmsClient(properties);
|
||||||
|
// 准备参数
|
||||||
|
Long sendLogId = System.currentTimeMillis();
|
||||||
|
String mobile = "17321315478";
|
||||||
|
String apiTemplateId = "3644cdab863546a3b718d488659a99ef";
|
||||||
|
List<KeyValue<String, Object>> templateParams = List.of(new KeyValue<>("code", "1122"));
|
||||||
|
// 调用
|
||||||
|
SmsSendRespDTO smsSendRespDTO = client.sendSms(sendLogId, mobile, apiTemplateId, templateParams);
|
||||||
|
// 打印结果
|
||||||
|
System.out.println(smsSendRespDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Disabled
|
||||||
|
public void testQiniuSmsClient_getSmsTemplate() throws Throwable {
|
||||||
|
|
||||||
|
SmsChannelProperties properties = new SmsChannelProperties()
|
||||||
|
.setApiKey("SMS_QINIU_ACCESS_KEY")
|
||||||
|
.setApiSecret("SMS_QINIU_SECRET_KEY");
|
||||||
|
QiniuSmsClient client = new QiniuSmsClient(properties);
|
||||||
|
// 准备参数
|
||||||
|
String apiTemplateId = "3644cdab863546a3b718d488659a99ef";
|
||||||
|
// 调用
|
||||||
|
SmsTemplateRespDTO template = client.getSmsTemplate(apiTemplateId);
|
||||||
|
// 打印结果
|
||||||
|
System.out.println(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user