mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-08-15 02:31:53 +08:00
Merge branch 'develop' of https://gitee.com/scholarli/ruoyi-vue-pro_1 into develop
# Conflicts: # yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClient.java # yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientTests.java # yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/TencentSmsClientTest.java
This commit is contained in:
@@ -2,38 +2,30 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONArray;
|
||||
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.ArrayUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
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.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import jakarta.xml.bind.DatatypeConverter;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.hutool.crypto.digest.DigestUtil.sha256Hex;
|
||||
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.TIME_ZONE_DEFAULT;
|
||||
|
||||
// TODO @scholar 建议参考 AliyunSmsClient 优化下
|
||||
|
||||
/**
|
||||
* 腾讯云短信功能实现
|
||||
*
|
||||
@@ -104,14 +96,15 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
body.put("TemplateId",apiTemplateId);
|
||||
body.put("TemplateParamSet",ArrayUtils.toArray(templateParams, e -> String.valueOf(e.getValue())));
|
||||
|
||||
JSONObject JsonResponse = sendSmsRequest(body,"SendSms","2021-01-11","ap-guangzhou");
|
||||
SmsResponse smsResponse = getSmsSendResponse(JsonResponse);
|
||||
|
||||
return new SmsSendRespDTO().setSuccess(smsResponse.success).setApiMsg(smsResponse.data.toString());
|
||||
JSONObject JsonResponse = request(body,"SendSms","2021-01-11","ap-guangzhou");
|
||||
|
||||
return new SmsSendRespDTO().setSuccess(API_CODE_SUCCESS.equals(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("Code")))
|
||||
.setApiRequestId(JsonResponse.getJSONObject("Response").getStr("RequestId"))
|
||||
.setSerialNo(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("SerialNo"))
|
||||
.setApiMsg(JsonResponse.getJSONObject("Response").getJSONArray("SendStatusSet").getJSONObject(0).getStr("Message"));
|
||||
}
|
||||
|
||||
JSONObject sendSmsRequest(TreeMap<String, Object> body,String action,String version,String region) throws Exception {
|
||||
JSONObject request(TreeMap<String, Object> body,String action,String version,String region) throws Exception {
|
||||
|
||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
@@ -156,12 +149,9 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
headers.put("X-TC-Version", version);
|
||||
headers.put("X-TC-Region", region);
|
||||
|
||||
HttpResponse response = HttpRequest.post("https://"+host)
|
||||
.addHeaders(headers)
|
||||
.body(JSONUtil.toJsonStr(body))
|
||||
.execute();
|
||||
String responseBody = HttpUtils.post("https://"+host, headers, JSONUtil.toJsonStr(body));
|
||||
|
||||
return JSONUtil.parseObj(response.body());
|
||||
return JSONUtil.parseObj(responseBody);
|
||||
}
|
||||
|
||||
public static byte[] hmac256(byte[] key, String msg) throws Exception {
|
||||
@@ -171,22 +161,20 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private SmsResponse getSmsSendResponse(JSONObject resJson) {
|
||||
SmsResponse smsResponse = new SmsResponse();
|
||||
JSONArray statusJson =resJson.getJSONObject("Response").getJSONArray("SendStatusSet");
|
||||
smsResponse.setSuccess("Ok".equals(statusJson.getJSONObject(0).getStr("Code")));
|
||||
smsResponse.setData(resJson);
|
||||
return smsResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
|
||||
List<SmsReceiveStatus> callback = JsonUtils.parseArray(text, SmsReceiveStatus.class);
|
||||
return convertList(callback, status -> new SmsReceiveRespDTO()
|
||||
.setSuccess(SmsReceiveStatus.SUCCESS_CODE.equalsIgnoreCase(status.getStatus()))
|
||||
.setErrorCode(status.getErrCode()).setErrorMsg(status.getDescription())
|
||||
.setMobile(status.getMobile()).setReceiveTime(status.getReceiveTime())
|
||||
.setSerialNo(status.getSerialNo()).setLogId(status.getSessionContext().getLogId()));
|
||||
|
||||
JSONArray statuses = JSONUtil.parseArray(text);
|
||||
// 字段参考
|
||||
return convertList(statuses, status -> {
|
||||
JSONObject statusObj = (JSONObject) status;
|
||||
return new SmsReceiveRespDTO()
|
||||
.setSuccess("SUCCESS".equals(statusObj.getStr("report_status"))) // 是否接收成功
|
||||
.setErrorCode(statusObj.getStr("errmsg")) // 状态报告编码
|
||||
.setMobile(statusObj.getStr("mobile")) // 手机号
|
||||
.setReceiveTime(statusObj.getLocalDateTime("user_receive_time", null)) // 状态报告时间
|
||||
.setSerialNo(statusObj.getStr("sid")); // 发送序列号
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -194,48 +182,22 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
|
||||
// 构建请求
|
||||
TreeMap<String, Object> body = new TreeMap<>();
|
||||
body.put("International",0);
|
||||
body.put("International",INTERNATIONAL_CHINA);
|
||||
Integer[] templateIds = {Integer.valueOf(apiTemplateId)};
|
||||
body.put("TemplateIdSet",templateIds);
|
||||
|
||||
JSONObject JsonResponse = sendSmsRequest(body,"DescribeSmsTemplateList","2021-01-11","ap-guangzhou");
|
||||
QuerySmsTemplateResponse smsTemplateResponse = getSmsTemplateResponse(JsonResponse);
|
||||
String templateId = Integer.toString(smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getTemplateId());
|
||||
String content = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getTemplateContent();
|
||||
Integer templateStatus = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getStatusCode();
|
||||
String auditReason = smsTemplateResponse.getDescribeTemplateStatusSet().get(0).getReviewReply();
|
||||
JSONObject JsonResponse = request(body,"DescribeSmsTemplateList","2021-01-11","ap-guangzhou");
|
||||
System.out.println("JsonResponse======"+JsonResponse);
|
||||
|
||||
return new SmsTemplateRespDTO().setId(templateId).setContent(content)
|
||||
JSONObject TemplateStatusSet = JsonResponse.getJSONObject("Response").getJSONArray("DescribeTemplateStatusSet").getJSONObject(0);
|
||||
String content = TemplateStatusSet.get("TemplateContent").toString();
|
||||
int templateStatus = Integer.parseInt(TemplateStatusSet.get("StatusCode").toString());
|
||||
String auditReason = TemplateStatusSet.get("ReviewReply").toString();
|
||||
|
||||
return new SmsTemplateRespDTO().setId(apiTemplateId).setContent(content)
|
||||
.setAuditStatus(convertSmsTemplateAuditStatus(templateStatus)).setAuditReason(auditReason);
|
||||
}
|
||||
|
||||
private QuerySmsTemplateResponse getSmsTemplateResponse(JSONObject resJson) {
|
||||
|
||||
QuerySmsTemplateResponse smsTemplateResponse = new QuerySmsTemplateResponse();
|
||||
|
||||
smsTemplateResponse.setRequestId(resJson.getJSONObject("Response").getStr("RequestId"));
|
||||
|
||||
smsTemplateResponse.setDescribeTemplateStatusSet(new ArrayList<>());
|
||||
|
||||
QuerySmsTemplateResponse.TemplateInfo templateInfo = new QuerySmsTemplateResponse.TemplateInfo();
|
||||
|
||||
Object statusObject = resJson.getJSONObject("Response").getJSONArray("DescribeTemplateStatusSet").get(0);
|
||||
|
||||
JSONObject statusJSON = new JSONObject(statusObject);
|
||||
|
||||
templateInfo.setTemplateContent(statusJSON.get("TemplateContent").toString());
|
||||
|
||||
templateInfo.setStatusCode(Integer.parseInt(statusJSON.get("StatusCode").toString()));
|
||||
|
||||
templateInfo.setReviewReply(statusJSON.get("ReviewReply").toString());
|
||||
|
||||
templateInfo.setTemplateId(Integer.parseInt(statusJSON.get("TemplateId").toString()));
|
||||
|
||||
smsTemplateResponse.getDescribeTemplateStatusSet().add(templateInfo);
|
||||
|
||||
return smsTemplateResponse;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Integer convertSmsTemplateAuditStatus(int templateStatus) {
|
||||
switch (templateStatus) {
|
||||
@@ -245,113 +207,4 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SmsResponse {
|
||||
|
||||
/**
|
||||
* 是否成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 厂商原返回体
|
||||
*/
|
||||
private Object data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>类名: QuerySmsTemplateResponse
|
||||
* <p>说明: sms模板查询返回信息
|
||||
*
|
||||
* @author :scholar
|
||||
* 2024/07/17 0:25
|
||||
**/
|
||||
@Data
|
||||
public static class QuerySmsTemplateResponse {
|
||||
private List<TemplateInfo> DescribeTemplateStatusSet;
|
||||
private String RequestId;
|
||||
@Data
|
||||
static class TemplateInfo {
|
||||
private String TemplateName;
|
||||
private Integer TemplateId;
|
||||
private Integer International;
|
||||
private String ReviewReply;
|
||||
private long CreateTime;
|
||||
private String TemplateContent;
|
||||
private Integer StatusCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class SmsReceiveStatus {
|
||||
|
||||
/**
|
||||
* 短信接受成功 code
|
||||
*/
|
||||
public static final String SUCCESS_CODE = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 用户实际接收到短信的时间
|
||||
*/
|
||||
@JsonProperty("user_receive_time")
|
||||
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
|
||||
private LocalDateTime receiveTime;
|
||||
|
||||
/**
|
||||
* 国家(或地区)码
|
||||
*/
|
||||
@JsonProperty("nationcode")
|
||||
private String nationCode;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 实际是否收到短信接收状态,SUCCESS(成功)、FAIL(失败)
|
||||
*/
|
||||
@JsonProperty("report_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 用户接收短信状态码错误信息
|
||||
*/
|
||||
@JsonProperty("errmsg")
|
||||
private String errCode;
|
||||
|
||||
/**
|
||||
* 用户接收短信状态描述
|
||||
*/
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 本次发送标识 ID(与发送接口返回的SerialNo对应)
|
||||
*/
|
||||
@JsonProperty("sid")
|
||||
private String serialNo;
|
||||
|
||||
/**
|
||||
* 用户的 session 内容(与发送接口的请求参数 SessionContext 一致)
|
||||
*/
|
||||
@JsonProperty("ext")
|
||||
private SessionContext sessionContext;
|
||||
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Data
|
||||
static class SessionContext {
|
||||
|
||||
/**
|
||||
* 发送短信记录id
|
||||
*/
|
||||
private Long logId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user