Commit 9ede7f2e authored by Smile's avatar Smile

Merge remote-tracking branch 'origin/jd_dev' into jd_dev

parents 53d520e3 3bed07dc
......@@ -126,7 +126,9 @@ INSERT INTO `jiedao`.`system_dict_data`( `sort`, `label`, `value`, `dict_type`,
INSERT INTO `jiedao`.`system_dict_data`( `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `label_en`) VALUES ( 1, '短信', '1', 'system_sms_template_message_type', 0, 'default', '', NULL, '2740', '2024-11-04 17:17:48', '2740', '2024-11-04 17:18:16', b'0', 'message');
INSERT INTO `jiedao`.`system_dict_type`(`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('模板语言', 'system_sms_template_language', 0, NULL, '2740', '2024-11-04 17:38:08', '2740', '2024-11-04 17:38:08', b'0');
INSERT INTO `jiedao`.`system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `label_en`) VALUES (1, 'en', 'en', 'system_sms_template_language', 0, 'default', '', NULL, '2740', '2024-11-04 17:40:55', '2740', '2024-11-04 17:40:55', b'0', 'en');
INSERT INTO `jiedao`.`system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `label_en`) VALUES (1, '英文', 'en', 'system_sms_template_language', 0, 'default', '', NULL, '2740', '2024-11-04 17:40:55', '2741', '2024-11-22 15:30:55', b'0', 'en');
INSERT INTO `jiedao`.`system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `label_en`) VALUES (3, '中文', 'zh_CN', 'system_sms_template_language', 0, 'default', '', NULL, '2741', '2024-11-22 15:30:09', '2741', '2024-11-22 15:31:05', b'0', 'zh_CN');
INSERT INTO `jiedao`.`system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `label_en`) VALUES (2, '法文', 'fr', 'system_sms_template_language', 0, 'default', '', NULL, '2741', '2024-11-22 15:30:46', '2741', '2024-11-22 15:31:01', b'0', 'fr');
INSERT INTO `jiedao`.`system_sms_node`(`node_value`, `is_transport`, `transport_id`, `is_orders`, `country_id`, `country_code`, `status`, `template_id_one`, `template_id_two`, `template_id_three`, `template_id_four`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('air-shipment-warehouse', 1, 3, 1, 0, '0', 0, 51, NULL, NULL, NULL, '2740', '2024-11-14 15:17:49', '2740', '2024-11-15 09:45:52', b'0');
INSERT INTO `jiedao`.`system_sms_node`(`node_value`, `is_transport`, `transport_id`, `is_orders`, `country_id`, `country_code`, `status`, `template_id_one`, `template_id_two`, `template_id_three`, `template_id_four`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('air-shipment-warehouse', 1, 3, 0, 0, '0', 0, 50, NULL, NULL, NULL, '2740', '2024-11-14 15:17:36', '2740', '2024-11-15 09:45:44', b'0');
......
package cn.iocoder.yudao.framework.http.example;
package cn.iocoder.yudao.framework.http.sms;
import cn.iocoder.yudao.framework.http.core.Request;
import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.core.client.HttpClient;
import cn.iocoder.yudao.framework.http.core.client.HttpClientFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
......@@ -15,7 +16,8 @@ import java.util.Map;
* @author wuxian
* @since 2024-10-23
**/
public class SendchampHttp {
@Slf4j
public class SendChampHttp {
private static final String SMS_URL = "https://api.sendchamp.com/api/v1/sms/send";
......@@ -27,8 +29,8 @@ public class SendchampHttp {
req.setParamFormat(Request.ParamFormat.JSON);
try {
Response res = client.execute(req, Request.Option.create(0, 0, header));
System.out.println("response code ---------------------------->" + res.getCode());
System.out.println("response content is --------------------》" + res.getBody());
log.warn("response code ---------------------------->" + res.getCode());
log.warn("response content is --------------------》" + res.getBody());
return res;
} catch (Exception e) {
throw new RuntimeException(e);
......@@ -50,7 +52,7 @@ public class SendchampHttp {
}
@NotNull
public static Map<String, String> setHeader(String apiKey) {
public Map<String, String> setHeader(String apiKey) {
Map<String, String> header = new HashMap<>();
header.put("Accept", "application/json,text/plain,*/*");
header.put("Content-Type", "application/json");
......@@ -59,7 +61,7 @@ public class SendchampHttp {
}
@NotNull
public static Map<String, Object> setParams(String to, String message, String senderName) {
public Map<String, Object> setParams(String to, String message, String senderName) {
Map<String, Object> param = new HashMap<>();
param.put("to", to);
param.put("message", message);
......@@ -69,19 +71,19 @@ public class SendchampHttp {
}
public static void main(String[] args) {
SendchampHttp test = new SendchampHttp();
SendChampHttp test = new SendChampHttp();
// String to = "2348140352000";
String to = "8618926674857";
String senderName = "Sendchamp";
String senderName = "ECLogistics";
//信息如果超过200字符,需要拆成多条短信,多次发送
String message = "Good day!This is E&C logistics(ship from China to Nigeria),It has been a while since we last worked together, and we would like to reestablish our partnership. Our main service: GROUPAGE/FULL CONTAINE";
Map<String, Object> param = setParams(to, message, senderName);
Map<String, Object> param = test.setParams(to, message, senderName);
String apiKey = "Bearer sendchamp_live_$2a$10$vQPdaDjl96Ybc5tzFmZYg.nqGirXuJBGDqJArthZnFR8P9mM5Z/JO";
Map<String, String> header = setHeader(apiKey);
test.getReceiveStatus(header, "66e6e9df-b454-4df7-a968-af944a535757");
Map<String, String> header = test.setHeader(apiKey);
// test.getReceiveStatus(header, "66e6e9df-b454-4df7-a968-af944a535757");
test.postReq(param,header);
}
......
package cn.iocoder.yudao.framework.http.example;
package cn.iocoder.yudao.framework.http.sms;
import cn.iocoder.yudao.framework.http.core.Request;
import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.core.client.HttpClient;
import cn.iocoder.yudao.framework.http.core.client.HttpClientFactory;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -14,6 +15,7 @@ import java.util.Map;
* @author wuxian
* @since 2024-10-23
**/
@Slf4j
public class WhisperClientHttp {
public void testPost(){
......@@ -47,8 +49,8 @@ public class WhisperClientHttp {
req.setParamFormat(Request.ParamFormat.JSON);
try {
Response res = client.execute(req,Request.Option.create(0,0,header));
System.out.println("response code ---------------------------->"+res.getCode());
System.out.println("response content is --------------------》"+res.getBody());
log.warn("response code ---------------------------->"+res.getCode());
log.warn("response content is --------------------》"+res.getBody());
} catch (Exception e) {
throw new RuntimeException(e);
}
......
package cn.iocoder.yudao.framework.http.example;
package cn.iocoder.yudao.framework.http.sms;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.http.core.Request;
......@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.core.client.HttpClient;
import cn.iocoder.yudao.framework.http.core.client.HttpClientFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.time.ZoneId;
import java.time.ZonedDateTime;
......@@ -16,6 +17,7 @@ import java.util.*;
* @author wuxian
* @since 2024-10-30
**/
@Slf4j
public class YCloudWhatsappHttp {
private HttpClient client = null;
......@@ -36,8 +38,8 @@ public class YCloudWhatsappHttp {
Request req = Request.create(WA_URL, Request.Method.POST, param);
req.setParamFormat(Request.ParamFormat.JSON);
Response res = client.execute(req, Request.Option.create(0, 0, header));
System.out.println("response code ---------------------------->" + res.getCode());
System.out.println("response content is --------------------》" + res.getBody());
log.warn("response code ---------------------------->" + res.getCode());
log.warn("response content is --------------------》" + res.getBody());
return res;
}
......@@ -45,8 +47,8 @@ public class YCloudWhatsappHttp {
public Response getReceiveStatus(Map<String, String> header, String id) {
Request req = Request.create(RECEIVE_URL + id, Request.Method.GET, "");
Response res = client.execute(req, Request.Option.create(0, 0, header));
System.out.println("response code ---------------------------->" + res.getCode());
System.out.println("response content is --------------------》" + res.getBody());
log.warn("response code ---------------------------->" + res.getCode());
log.warn("response content is --------------------》" + res.getBody());
return res;
}
......
......@@ -64,8 +64,6 @@ public interface SmsClient {
/**
* 查询短信发送状态
*
* @param smsLogDO
* @return
*/
SmsLogDTO getReceiveStatus(SmsLogDTO smsLogDO);
}
......@@ -11,9 +11,9 @@ import lombok.ToString;
/**
* 短信的 CommonResult 拓展类
*
* <p>
* 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
*
* <p>
* 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
*
* @author 捷道源码
......@@ -25,7 +25,7 @@ public class SmsCommonResult<T> extends CommonResult<T> {
/**
* API 返回错误码
*
* <p>
* 由于第三方的错误码可能是字符串,所以使用 String 类型
*/
private String apiCode;
......
......@@ -40,7 +40,7 @@ public class SmsReceiveRespDTO {
private String serialNo;
/**
* 短信日志编号
*
* <p>
* 对应 SysSmsLogDO 的编号
*/
private Long logId;
......
......@@ -21,7 +21,7 @@ public class SmsTemplateRespDTO {
private String content;
/**
* 审核状态
*
* <p>
* 枚举 {@link SmsTemplateAuditStatusEnum}
*/
private Integer auditStatus;
......
......@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendchampSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendChampSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.yCloud.YCloudSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
......@@ -87,7 +87,7 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
case DEBUG_DING_TALK:
return new DebugDingTalkSmsClient(properties);
case SENDCHAMP:
return new SendchampSmsClient(properties);
return new SendChampSmsClient(properties);
case YCLOUD:
return new YCloudSmsClient(properties);
}
......
......@@ -92,7 +92,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
}
@Override
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) {
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return statuses.stream().map(status -> {
SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
......@@ -196,7 +196,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
querySendDetailsRequest.setBizId(smsLogDO.getApiSerialNo());
// 初始化查询响应对象
QuerySendDetailsResponse acsResponse = null;
QuerySendDetailsResponse acsResponse;
try {
// 发起查询请求并获取响应
acsResponse = client.getAcsResponse(querySendDetailsRequest);
......@@ -249,7 +249,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
/**
* 短信接收状态
* <p>
* 参见 https://help.aliyun.com/document_detail/101867.html 文档
* 参见 <a href="https://help.aliyun.com/document_detail/101867.html">...</a> 文档
*
* @author 捷道源码
*/
......
......@@ -7,8 +7,8 @@ import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
/**
* 阿里云的 SmsCodeMapping 实现类
*
* 参见 https://help.aliyun.com/document_detail/101346.htm 文档
* <p>
* 参见 <a href="https://help.aliyun.com/document_detail/101346.htm">...</a> 文档
*
* @author 捷道源码
*/
......
package cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.core.KeyValue;
import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.example.SendchampHttp;
import cn.iocoder.yudao.framework.http.sms.SendChampHttp;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.*;
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.ReceiveStatusEnum;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
......@@ -22,18 +22,18 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Sendchamp客户端
* SendChamp客户端
* @author jayden
*/
@Slf4j
public class SendchampSmsClient extends AbstractSmsClient {
public class SendChampSmsClient extends AbstractSmsClient {
// 创建HTTP客户端实例,用于发送短信
private final SendchampHttp sendchampHttp = new SendchampHttp();
private final SendChampHttp sendchampHttp = new SendChampHttp();
// 定义发送方名称,此处为固定值
private final String senderName = "Sendchamp";
public SendchampSmsClient(SmsChannelProperties properties) {
super(properties, new SendchampSmsCodeMapping());
public SendChampSmsClient(SmsChannelProperties properties) {
super(properties, new SendChampSmsCodeMapping());
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
......@@ -44,7 +44,7 @@ public class SendchampSmsClient extends AbstractSmsClient {
}
@Override
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
return null;
}
......@@ -80,10 +80,10 @@ public class SendchampSmsClient extends AbstractSmsClient {
try {
// 如果信息超过200字符,需要拆分成多条短信发送
List<String> messages = splitContent(content, 200);
List<String> messages = splitContent(content);
for (String message : messages) {
// 设置发送短信所需的参数
Map<String, Object> param = sendchampHttp.setParams(mobile, message, senderName);
Map<String, Object> param = sendchampHttp.setParams(mobile, message, "Sendchamp");
// 设置请求头,包含认证信息
Map<String, String> header = sendchampHttp.setHeader("Bearer " + properties.getApiSecret());
// 发送POST请求
......@@ -91,8 +91,8 @@ public class SendchampSmsClient extends AbstractSmsClient {
// 获取响应体
String result = response.getBody();
// 解析响应结果
Map<?, ?> responseObj = JsonUtils.parseObject(result, Map.class);
Map<String, Object> data = (Map<String, Object>) responseObj.get("data");
Map<?, ?> responseObj = JSON.parseObject(result, Map.class);
Map<?, ?> data = (Map<?, ?>) responseObj.get("data");
// 构建发送结果
String id = String.valueOf(data.get("business_id"));
if ("null".equals(id)) {
......@@ -148,15 +148,14 @@ public class SendchampSmsClient extends AbstractSmsClient {
* 拆分内容
* 将内容拆分成多个部分,每个部分不超过 maxLength 字符
*
* @param content 待拆分的内容
* @param maxLength 每个部分的最大长度
* @param content 待拆分的内容
* @return 拆分后的内容列表
*/
private List<String> splitContent(String content, int maxLength) {
private List<String> splitContent(String content) {
List<String> messages = new ArrayList<>();
int start = 0;
while (start < content.length()) {
int end = Math.min(start + maxLength, content.length());
int end = Math.min(start + 200, content.length());
messages.add(content.substring(start, end));
start = end;
}
......@@ -164,12 +163,12 @@ public class SendchampSmsClient extends AbstractSmsClient {
}
@Override
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) {
return null;
}
@Override
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {
protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
return SmsCommonResult.build("accepted", "accepted", null, data, codeMapping);
......
......@@ -6,16 +6,18 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
/**
* sendchamp SmsCodeMapping 实现类
* SendChamp SmsCodeMapping 实现类
* @author Jayden
*/
public class SendchampSmsCodeMapping implements SmsCodeMapping {
public class SendChampSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
switch (apiCode) {
case "accepted": return GlobalErrorCodeConstants.SUCCESS;
case "processing": return GlobalErrorCodeConstants.SUCCESS;
case "send": return GlobalErrorCodeConstants.SUCCESS;
case "delivered": return GlobalErrorCodeConstants.SUCCESS;
case "accepted":
case "processing":
case "send":
case "delivered":
return GlobalErrorCodeConstants.SUCCESS;
}
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
}
......
package cn.iocoder.yudao.framework.sms.core.client.impl.yCloud;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.core.KeyValue;
import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.example.YCloudWhatsappHttp;
import cn.iocoder.yudao.framework.http.sms.YCloudWhatsappHttp;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.*;
import cn.iocoder.yudao.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendchampSmsCodeMapping;
import cn.iocoder.yudao.framework.sms.core.enums.ReceiveStatusEnum;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import java.time.ZoneId;
......@@ -34,7 +33,7 @@ public class YCloudSmsClient extends AbstractSmsClient {
private final YCloudWhatsappHttp yCloudWhatsappHttp = new YCloudWhatsappHttp();
public YCloudSmsClient(SmsChannelProperties properties) {
super(properties, new SendchampSmsCodeMapping());
super(properties, new YCloudSmsCodeMapping());
Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
}
......@@ -45,7 +44,7 @@ public class YCloudSmsClient extends AbstractSmsClient {
}
@Override
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
return null;
}
......@@ -76,7 +75,7 @@ public class YCloudSmsClient extends AbstractSmsClient {
yCloudWhatsappHttp.setParams(code, smsTemplateDTO.getApiTemplateId(), smsTemplateDTO.getLanguage(), mobile));
// 解析结果
Map<String, Object> responseObj = JsonUtils.parseObject(response.getBody(), Map.class);
Map<?, ?> responseObj = JSON.parseObject(response.getBody(), Map.class);
// 构建短信发送结果对象
SmsCommonResult<SmsSendRespDTO> smsCommonResult = SmsCommonResult.build(String.valueOf(responseObj.get("status")), String.valueOf(responseObj.get("status")), String.valueOf(responseObj.get("id")), null, codeMapping);
// 设置短信发送结果的详细信息
......@@ -102,11 +101,14 @@ public class YCloudSmsClient extends AbstractSmsClient {
// 发送短信并获取响应
Response response = yCloudWhatsappHttp.getReceiveStatus(yCloudWhatsappHttp.setHeader(properties.getApiSecret()), smsLogDO.getApiSerialNo());
// 解析响应内容为Map对象,以便后续处理
Map<String, Object> responseObj = JsonUtils.parseObject(response.getBody(), Map.class);
Map<?, ?> responseObj = JSON.parseObject(response.getBody(), Map.class);
// 获取短信状态
String status = (String) responseObj.get("status");
if (status == null){
return smsLogDTO;
}
// 如果短信状态为已送达或已读取,则进一步处理
if (status != null && ("delivered".equals(status) || "read".equals(status))) {
if ("delivered".equals(status) || "read".equals(status)) {
// 获取送达时间
String deliverTime = (String) responseObj.get("deliverTime");
// 解析并转换送达时间为本地时间
......
......@@ -14,9 +14,9 @@ import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
public class YCloudSmsCodeMapping implements SmsCodeMapping {
@Override
public ErrorCode apply(String apiCode) {
switch (apiCode) {
case "success": return GlobalErrorCodeConstants.SUCCESS;
if ("success".equals(apiCode)) {
return GlobalErrorCodeConstants.SUCCESS;
}
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
}
}
......@@ -16,7 +16,7 @@ public enum ReceiveStatusEnum {
Receive_STATUS_10("接收成功", 10),
Receive_STATUS_20("接收失败", 20);
private String name;
private final String name;
private Integer value;
private final Integer value;
}
......@@ -1245,8 +1245,8 @@ public class OrderCargoControlPickServiceImpl extends AbstractService<OrderCargo
reqDTO.setMobile(consignorPhone);
reqDTO.setUserId(consignorCustomerId);
reqDTO.setNodeValue(nodeValue);
reqDTO.setIsTransport(SmsIsTransportEnum.SMS_ORDERS_1.getValue());
reqDTO.setTransportId(orderDO.getTransportId());
reqDTO.setIsTransport(SmsIsTransportEnum.SMS_ORDERS_0.getValue());
reqDTO.setTransportId(TransportTypeEnum.OTHER.getValue());
reqDTO.setIsOrders(SmsIsOrdersEnum.SMS_ORDERS_0.getValue());
reqDTO.setMessageType(SmsMessageTypeEnum.SMS_MESSAGE_TYPE_1.getValue());
reqDTO.setTemplateParams(templateParams);
......
package cn.iocoder.yudao.module.system.enums.sms;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.util.json.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 国家编号枚举
*
......@@ -19,7 +15,7 @@ public enum SmsCountryCodeEnum {
SMS_COUNTRY_CODE_0("全部", "0"),
SMS_COUNTRY_CODE_1("其他", "1");
private String name;
private final String name;
private String value;
private final String value;
}
......@@ -15,7 +15,7 @@ public enum SmsIsOrdersEnum {
SMS_ORDERS_0("否", 0),
SMS_ORDERS_1("是", 1);
private String name;
private final String name;
private Integer value;
private final Integer value;
}
......@@ -15,7 +15,7 @@ public enum SmsIsTransportEnum {
SMS_ORDERS_0("否", 0),
SMS_ORDERS_1("是", 1);
private String name;
private final String name;
private Integer value;
private final Integer value;
}
......@@ -16,7 +16,7 @@ public enum SmsMessageTypeEnum {
SMS_MESSAGE_TYPE_2("whatsapp", 2),
SMS_MESSAGE_TYPE_3("email", 3);
private String name;
private final String name;
private Integer value;
private final Integer value;
}
......@@ -15,7 +15,7 @@ public enum SystemStatusEnum {
SYSTEM_STATUS_0("开启", 0),
SYSTEM_STATUS_1("关闭", 1);
private String name;
private final String name;
private Integer value;
private final Integer value;
}
......@@ -5,14 +5,13 @@ import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendchampSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendChampSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.module.system.service.sms.SmsLogService;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
......@@ -23,6 +22,9 @@ import javax.servlet.http.HttpServletRequest;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* @author ECIT-2
*/
@Api(tags = "管理后台 - 短信回调")
@RestController
@RequestMapping("/system/sms/callback")
......@@ -31,7 +33,7 @@ public class SmsCallbackController {
@Resource
private SmsSendService smsSendService;
@Autowired
@Resource
private SmsLogService smsLogService;
@PostMapping("/yunpian")
......@@ -58,7 +60,7 @@ public class SmsCallbackController {
@OperateLog(enable = false)
public CommonResult<Boolean> receiveSendchampSmsStatus(HttpServletRequest request) {
String text = ServletUtil.getBody(request);
SendchampSmsClient.SmsReceiveStatus smsReceiveStatus = JsonUtils.parseObject(text, SendchampSmsClient.SmsReceiveStatus.class);
SendChampSmsClient.SmsReceiveStatus smsReceiveStatus = JsonUtils.parseObject(text, SendChampSmsClient.SmsReceiveStatus.class);
smsLogService.updateSendchampReceive(smsReceiveStatus);
return success(true);
}
......
......@@ -48,9 +48,9 @@ public interface SmsLogMapper extends BaseMapperX<SmsLogDO> {
"DELETE FROM system_sms_log WHERE date(create_time) <= date(date_sub(now(), interval 90 day))"
})
int clearLog(Integer day);
default List<SmsLogDO> selectReceiveList() {
default List<SmsLogDO> selectReceiveList(Integer time) {
return selectList(new QueryWrapperX<SmsLogDO>()
.apply("create_time >= NOW() - INTERVAL 20 HOUR")
.apply(String.format("create_time >= NOW() - INTERVAL %d HOUR",time))
.eq("template_type", 2)
.lt("num", 1)
.ne("receive_status", 10));
......
package cn.iocoder.yudao.module.system.job.sms;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.module.system.service.sms.SmsNodeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 短信接收 Job
*
* @author Jayden
* @date 2024/11/21
*/
@Component
@Slf4j
public class SmsReceiveJob implements JobHandler {
@Autowired
private SmsNodeService smsNodeService;
@Override
public String execute(String time) {
if (StringUtils.isBlank(time)) {
log.error("短信接收参数错误:{},此参数不能为空", time);
return "短信接收参数错误,此参数不能为空";
}
smsNodeService.scheduleReceiveRefresh(Integer.valueOf(time));
return "短信接收 Job 执行成功";
}
}
......@@ -23,14 +23,14 @@ import java.util.List;
public class SmsProducer {
@Resource
private RedisMQTemplate redisMQTemplate;
private RedisMQTemplate redisMqTemplate;
/**
* 发送 {@link SmsChannelRefreshMessage} 消息
*/
public void sendSmsChannelRefreshMessage() {
SmsChannelRefreshMessage message = new SmsChannelRefreshMessage();
redisMQTemplate.send(message);
redisMqTemplate.send(message);
}
/**
......@@ -38,7 +38,7 @@ public class SmsProducer {
*/
public void sendSmsTemplateRefreshMessage() {
SmsTemplateRefreshMessage message = new SmsTemplateRefreshMessage();
redisMQTemplate.send(message);
redisMqTemplate.send(message);
}
/**
......@@ -54,10 +54,10 @@ public class SmsProducer {
Long channelId, String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
SmsSendMessage message = new SmsSendMessage().setLogId(logId).setMobile(mobile);
message.setChannelId(channelId).setApiTemplateId(apiTemplateId).setTemplateParams(templateParams);
redisMQTemplate.send(message);
redisMqTemplate.send(message);
}
public void sendSmsSendMessageV2(SmsSendMessageV2 message) {
redisMQTemplate.send(message);
redisMqTemplate.send(message);
}
}
......@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.service.sms;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.web.config.BusinessProperties;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
......@@ -36,17 +35,8 @@ public class SmsCodeServiceImpl implements SmsCodeService {
@Resource
private SmsSendService smsSendService;
@Resource
private BusinessProperties businessProperties;
@Override
public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
// SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(reqDTO.getScene());
// Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene());
// if (Objects.nonNull(businessProperties) && businessProperties.isDebug()) {
// // TODO debug业务模式下不需要生成发送验证码,固定使用9999
// return;
// }
// 创建验证码
String code = createSmsCode(reqDTO.getMobile(), reqDTO.getNodeValue(), reqDTO.getCreateIp());
// 发送验证码
......
package cn.iocoder.yudao.module.system.service.sms;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendchampSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendChampSmsClient;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
......@@ -112,11 +112,11 @@ public interface SmsLogService {
void updateBatchSmsLog(List<SmsLogDO> resendSmsLogList);
List<SmsLogDO> selectReceiveList();
List<SmsLogDO> selectReceiveList(Integer time);
/**
* 更新sendchamp回调状态
* @param smsReceiveStatus
*/
void updateSendchampReceive(SendchampSmsClient.SmsReceiveStatus smsReceiveStatus);
void updateSendchampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus);
}
package cn.iocoder.yudao.module.system.service.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendchampSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.sendchamp.SendChampSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.ReceiveStatusEnum;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogPageReqVO;
......@@ -155,12 +155,12 @@ public class SmsLogServiceImpl implements SmsLogService {
}
@Override
public List<SmsLogDO> selectReceiveList() {
return smsLogMapper.selectReceiveList();
public List<SmsLogDO> selectReceiveList(Integer time) {
return smsLogMapper.selectReceiveList(time);
}
@Override
public void updateSendchampReceive(SendchampSmsClient.SmsReceiveStatus smsReceiveStatus) {
public void updateSendchampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus) {
if ("delivered".equals(smsReceiveStatus.getStatus())) {
List<SmsLogDO> smsLogDOS = smsLogMapper.selectList(new SmsLogExportReqVO().setApiSerialNo(smsReceiveStatus.getReference()));
if (smsLogDOS != null) {
......
......@@ -81,4 +81,9 @@ public interface SmsNodeService extends IService<SmsNodeDO> {
* @return 缓存键
*/
String buildCacheKey(SmsNodeDO smsNodeDO);
/**
* 短信重发定时任务
*/
void scheduleReceiveRefresh(Integer time);
}
......@@ -18,7 +18,6 @@ import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsNodeMapper;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
......@@ -44,16 +43,16 @@ public class SmsNodeServiceImpl extends AbstractService<SmsNodeMapper, SmsNodeDO
@Resource
private SmsNodeMapper smsNodeMapper;
@Autowired
@Resource
private RedisHelper redisHelper;
@Autowired
@Resource
private SmsLogService smsLogService;
@Autowired
@Resource
private SmsClientFactory smsClientFactory;
@Autowired
@Resource
private SmsSendService smsSendService;
/**
......@@ -112,14 +111,12 @@ public class SmsNodeServiceImpl extends AbstractService<SmsNodeMapper, SmsNodeDO
}
/**
* 每半小时执行一次
* 短信重发定时任务
*/
@Scheduled(cron = "0 0/30 * * * ?")
public void scheduleReceiveRefresh() {
public void scheduleReceiveRefresh(Integer time) {
try {
// 获取需要重发短信的日志列表
List<SmsLogDO> smsLogs = smsLogService.selectReceiveList();
List<SmsLogDO> smsLogs = smsLogService.selectReceiveList(time);
if (smsLogs != null) {
for (SmsLogDO smsLog : smsLogs) {
try {
......@@ -144,12 +141,18 @@ public class SmsNodeServiceImpl extends AbstractService<SmsNodeMapper, SmsNodeDO
private void processSmsLog(SmsLogDO smsLog) {
// 根据渠道ID获取短信客户端
SmsClient smsClient = smsClientFactory.getSmsClient(smsLog.getChannelId());
// 获取短信接收状态
SmsLogDTO receiveStatus = smsClient.getReceiveStatus(SmsLogConvert.INSTANCE.toDto(smsLog));
smsLog.setReceiveStatus(receiveStatus.getReceiveStatus());
try {
// 获取短信接收状态
SmsLogDTO receiveStatus = smsClient.getReceiveStatus(SmsLogConvert.INSTANCE.toDto(smsLog));
smsLog.setReceiveStatus(receiveStatus.getReceiveStatus());
} catch (Exception e) {
smsLog.setReceiveStatus(ReceiveStatusEnum.Receive_STATUS_20.getValue());
log.error("获取短信接收状态失败: {}", smsLog, e);
}
// 接收失败,则重发
if (ReceiveStatusEnum.Receive_STATUS_20.getValue() == receiveStatus.getReceiveStatus()) {
smsLog.setReceiveTime(receiveStatus.getReceiveTime());
if (ReceiveStatusEnum.Receive_STATUS_20.getValue() == smsLog.getReceiveStatus()) {
smsLog.setReceiveTime(smsLog.getReceiveTime());
smsLog.setNum(1);
// 从Redis中获取短信节点信息
String node = redisHelper.get(SYSTEM_SMS_NODE_KEY + smsLog.getNodeId());
......
......@@ -30,7 +30,6 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.alibaba.fastjson.JSON;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
......@@ -71,10 +70,10 @@ public class SmsSendServiceImpl implements SmsSendService {
@Resource
private BusinessProperties businessProperties;
@Autowired
@Resource
private SmsNodeService smsNodeService;
@Autowired
@Resource
private RedisHelper redisHelper;
@Override
......@@ -231,7 +230,7 @@ public class SmsSendServiceImpl implements SmsSendService {
/**
* 将参数模板,处理成有序的 KeyValue 数组
* <p>
* 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 https://cloud.tencent.com/document/product/382/39023
* 原因是,部分短信平台并不是使用 key 作为参数,而是数组下标,例如说腾讯云 <a href="https://cloud.tencent.com/document/product/382/39023">...</a>
*
* @param template 短信模板
* @param templateParams 原始参数
......
......@@ -23,7 +23,6 @@ import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
import com.alibaba.fastjson.JSON;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
......@@ -68,7 +67,7 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
@Resource
private SmsProducer smsProducer;
@Autowired
@Resource
private RedisHelper redisHelper;
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment