Commit 786d9819 authored by honghy's avatar honghy

调整测试短信节点

parent 9ede7f2e
......@@ -3,6 +3,9 @@ package cn.iocoder.yudao.framework.common.util.date;
import cn.hutool.core.date.DateUtil;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
......@@ -167,4 +170,24 @@ public class DateUtils {
calendar.add(Calendar.DAY_OF_MONTH, days);
return calendar.getTime();
}
/**
* 解析并转换时间为本地时间
* 本方法将给定的ISO 8601格式的日期时间字符串解析为日期对象,并转换为本地时间
*
* @param deliverTime ISO 8601格式的日期时间字符串
* @return 返回转换后的本地时间日期对象
*/
public static Date parseAndConvertToLocalDate(String deliverTime) {
// 定义 ISO 8601 格式的日期时间解析器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
// 将字符串解析为 ZonedDateTime 对象
ZonedDateTime utcDateTime = ZonedDateTime.parse(deliverTime, formatter);
// 获取本地时区
ZoneId localZoneId = ZoneId.systemDefault();
// 将 UTC 时间转换为本地时间
ZonedDateTime localDateTime = utcDateTime.withZoneSameInstant(localZoneId);
// 将 ZonedDateTime 转换为 Date
return Date.from(localDateTime.toInstant());
}
}
......@@ -43,8 +43,8 @@ public class SendChampHttp {
Request req = Request.create(RECEIVE_URL + id, Request.Method.GET, "");
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);
......
package cn.iocoder.yudao.framework.sms.core.client.dto;
import lombok.Data;
/**
* SendChamp发送返回结果
*
* 该类用于封装SendChamp发送操作的返回结果,包括发送状态码、数据信息、错误信息等
* 主要用于处理和解析SendChamp API的响应内容
*
* @author Jayden
* @date 2024/11/23
*/
@Data
public class SendChampResult {
// 响应状态码,用于表示发送操作的结果状态
private int code;
// 发送数据信息,包括发送消息的ID、业务ID和总联系人数
private Data data;
// 错误信息,用于描述发送操作中可能出现的错误详情
private String errors;
// 消息信息,通常用于提供更详细的响应描述
private String message;
// 响应状态,以字符串形式表示发送操作的状态
private String status;
/**
* 发送数据信息
* 该内部类用于详细描述发送操作的相关数据,包括发送消息的唯一标识、业务标识和联系人的总数
*/
@lombok.Data
public static class Data {
// 发送消息的唯一标识符
private String id;
// 业务标识符,用于关联发送消息的特定业务
private String businessId;
// 总联系人数,表示发送消息所涉及的联系人数量
private int totalContacts;
}
}
......@@ -14,6 +14,7 @@ import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
......@@ -91,14 +92,15 @@ public class SendChampSmsClient extends AbstractSmsClient {
// 获取响应体
String result = response.getBody();
// 解析响应结果
Map<?, ?> responseObj = JSON.parseObject(result, Map.class);
Map<?, ?> data = (Map<?, ?>) responseObj.get("data");
SendChampResult sendChampResult = JSON.parseObject(result, SendChampResult.class);
SendChampResult.Data data = sendChampResult.getData();
// 构建发送结果
String id = String.valueOf(data.get("business_id"));
if ("null".equals(id)) {
id = String.valueOf(data.get("id"));
String id = data.getBusinessId();
if (StringUtils.isBlank(id)) {
id = data.getId();
}
smsCommonResult = SmsCommonResult.build(String.valueOf(responseObj.get("message")), String.valueOf(responseObj.get("message")), id, null, codeMapping);
smsCommonResult = SmsCommonResult.build(sendChampResult.getMessage(), sendChampResult.getMessage(), id, null, codeMapping);
smsCommonResult.setData(new SmsSendRespDTO().setSerialNo(id));
}
} catch (Exception e) {
......@@ -202,4 +204,5 @@ public class SendChampSmsClient extends AbstractSmsClient {
private String status;
}
}
package cn.iocoder.yudao.framework.sms.core.client.impl.yCloud;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.json.core.KeyValue;
import cn.iocoder.yudao.framework.http.core.Response;
import cn.iocoder.yudao.framework.http.sms.YCloudWhatsappHttp;
......@@ -9,13 +10,13 @@ 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.enums.YCloudReceiveStatusEnum;
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;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
......@@ -100,19 +101,19 @@ public class YCloudSmsClient extends AbstractSmsClient {
try {
// 发送短信并获取响应
Response response = yCloudWhatsappHttp.getReceiveStatus(yCloudWhatsappHttp.setHeader(properties.getApiSecret()), smsLogDO.getApiSerialNo());
// 解析响应内容为Map对象,以便后续处理
Map<?, ?> responseObj = JSON.parseObject(response.getBody(), Map.class);
// 解析响应内容为对象,以便后续处理
SmsReceiveStatus smsReceiveStatus = JSON.parseObject(response.getBody(), SmsReceiveStatus.class);
// 获取短信状态
String status = (String) responseObj.get("status");
if (status == null){
if (smsReceiveStatus == null) {
return smsLogDTO;
}
String status = smsReceiveStatus.getStatus();
// 如果短信状态为已送达或已读取,则进一步处理
if ("delivered".equals(status) || "read".equals(status)) {
if (YCloudReceiveStatusEnum.DELIVERED.getCode().equals(status) || YCloudReceiveStatusEnum.READ.getCode().equals(status)) {
// 获取送达时间
String deliverTime = (String) responseObj.get("deliverTime");
String deliverTime = smsReceiveStatus.getDeliverTime();
// 解析并转换送达时间为本地时间
Date localDate = parseAndConvertToLocalDate(deliverTime);
Date localDate = DateUtils.parseAndConvertToLocalDate(deliverTime);
// 更新短信日志DTO的接收时间和接收状态
smsLogDTO.setReceiveTime(localDate);
smsLogDTO.setReceiveStatus(ReceiveStatusEnum.Receive_STATUS_10.getValue());
......@@ -127,26 +128,6 @@ public class YCloudSmsClient extends AbstractSmsClient {
return smsLogDTO;
}
/**
* 解析并转换时间为本地时间
* 本方法将给定的ISO 8601格式的日期时间字符串解析为日期对象,并转换为本地时间
*
* @param deliverTime ISO 8601格式的日期时间字符串
* @return 返回转换后的本地时间日期对象
*/
private Date parseAndConvertToLocalDate(String deliverTime) {
// 定义 ISO 8601 格式的日期时间解析器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX");
// 将字符串解析为 ZonedDateTime 对象
ZonedDateTime utcDateTime = ZonedDateTime.parse(deliverTime, formatter);
// 获取本地时区
ZoneId localZoneId = ZoneId.systemDefault();
// 将 UTC 时间转换为本地时间
ZonedDateTime localDateTime = utcDateTime.withZoneSameInstant(localZoneId);
// 将 ZonedDateTime 转换为 Date
return Date.from(localDateTime.toInstant());
}
@Override
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) {
throw new UnsupportedOperationException("无回调");
......@@ -158,4 +139,24 @@ public class YCloudSmsClient extends AbstractSmsClient {
.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
return SmsCommonResult.build("accepted", "accepted", null, data, codeMapping);
}
/**
* 短信接收状态
* <p>
*
* @author 捷道源码
*/
@Data
public static class SmsReceiveStatus {
/**
* status
*/
@JsonProperty("status")
private String status;
/**
* reference
*/
@JsonProperty("deliverTime")
private String deliverTime;
}
}
package cn.iocoder.yudao.framework.sms.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 返回状态
* @author Jayden
* @date 2024/11/23
*/
@Getter
@AllArgsConstructor
public enum SendChampReceiveStatusEnum {
SENT("sent","The message has been sent successfully."),
DELIVERED("delivered","The message has been delivered to the customer."),
PENDING("pending","The message has been sent to a downstream mobile operator and provider and we are waiting for Delivery Report to be returned."),
FAILED("failed","The message couldn't be sent and delivered. More detail can be found in the reason and the error code."),
LOW_FUNDS("low_funds","The message failed due to insufficient funds."),
REJECTED("rejected","The message has been rejected, this is usually due to malicious requests."),
EXPIRED("expired","The message session has expired.");
private final String code;
private final String description;
}
package cn.iocoder.yudao.framework.sms.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 返回状态
*
* @author Jayden
* @date 2024/11/23
*/
@Getter
@AllArgsConstructor
public enum YCloudReceiveStatusEnum {
ACCEPTED("accepted", "The messaging request is accepted by our system."),
FAILED("failed", "A message sent by your business failed to send."),
SENT("sent", "A message sent by your business is in transit within WhatsApp's systems."),
DELIVERED("delivered", "A message sent by your business was delivered to the user's device."),
READ("read", "A message sent by your business was read by the user.");
private final String code;
private final String description;
}
......@@ -61,7 +61,7 @@ public class SmsCallbackController {
public CommonResult<Boolean> receiveSendchampSmsStatus(HttpServletRequest request) {
String text = ServletUtil.getBody(request);
SendChampSmsClient.SmsReceiveStatus smsReceiveStatus = JsonUtils.parseObject(text, SendChampSmsClient.SmsReceiveStatus.class);
smsLogService.updateSendchampReceive(smsReceiveStatus);
smsLogService.updateSendChampReceive(smsReceiveStatus);
return success(true);
}
}
......@@ -2,15 +2,15 @@ package cn.iocoder.yudao.module.system.controller.admin.sms;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.spring.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.excel.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode.SmsNodeBackVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode.SmsNodeCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode.SmsNodeQueryVO;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode.SmsNodeUpdateReqVO;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode.*;
import cn.iocoder.yudao.module.system.convert.sms.SmsNodeConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsNodeDO;
import cn.iocoder.yudao.module.system.service.sms.SmsNodeService;
import cn.iocoder.yudao.module.system.service.sms.SmsSendService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
......@@ -37,6 +37,9 @@ public class SmsNodeController {
@Resource
private SmsNodeService smsNodeService;
@Resource
private SmsSendService smsSendService;
@PostMapping("/create")
@ApiOperation("创建短信节点")
@PreAuthorize("@ss.hasPermission('system:sms-node:create')")
......@@ -98,4 +101,13 @@ public class SmsNodeController {
List<SmsNodeBackVO> datas = SmsNodeConvert.INSTANCE.convertList(list);
ExcelUtils.write(response, "短信节点.xls", "数据", SmsNodeBackVO.class, datas);
}
@GetMapping("/test")
@ApiOperation("测试短信节点")
public CommonResult<Boolean> test(@Valid SmsNodeTestVO smsNodeTestVO) {
smsSendService.sendSingleSmsV2(smsNodeTestVO.getMobile(), SecurityFrameworkUtils.getLoginUserId(), UserTypeEnum.ADMIN.getValue(), smsNodeTestVO.getNodeValue(),
smsNodeTestVO.getCountryCode(), smsNodeTestVO.getIsOrders(), smsNodeTestVO.getIsTransport(), smsNodeTestVO.getTransportId(),
smsNodeTestVO.getMessageType(), smsNodeTestVO.getTemplateParams(), null, smsNodeTestVO.getNodeTemplateSn());
return success(true);
}
}
package cn.iocoder.yudao.module.system.controller.admin.sms.vo.smsNode;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* 测试节点
*
* @author Jayden
* @date 2024/11/23
*/
@Data
public class SmsNodeTestVO {
@ApiModelProperty(value = "节点", required = true)
@NotNull(message = "节点不能为空")
private String nodeValue;
@ApiModelProperty(value = "运输方式ID", required = true)
@NotNull(message = "运输方式ID不能为空")
private Integer transportId;
@ApiModelProperty(value = "手机号不能为空", required = true)
@NotNull(message = "手机号不能为空")
private String mobile;
@ApiModelProperty(value = "国家区号不能为空", required = true)
@NotNull(message = "国家区号不能为空")
private String countryCode;
@ApiModelProperty(value = "是否匹配运输方式", required = true)
@NotNull(message = "是否匹配运输方式不能为空")
private Integer isTransport;
@ApiModelProperty(value = "多订单", required = true)
@NotNull(message = "多订单不能为空")
private Integer isOrders;
@ApiModelProperty(value = "模板序号", required = true)
@NotNull(message = "模板序号不能为空")
private Integer nodeTemplateSn;
@ApiModelProperty(value = "发送类型", required = true)
@NotNull(message = "发送类型不能为空")
private Integer messageType;
@ApiModelProperty(value = "参数")
private Map<String, Object> templateParams;
}
......@@ -115,8 +115,7 @@ public interface SmsLogService {
List<SmsLogDO> selectReceiveList(Integer time);
/**
* 更新sendchamp回调状态
* @param smsReceiveStatus
* 更新sendChamp回调状态
*/
void updateSendchampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus);
void updateSendChampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus);
}
......@@ -3,6 +3,7 @@ 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.enums.ReceiveStatusEnum;
import cn.iocoder.yudao.framework.sms.core.enums.SendChampReceiveStatusEnum;
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;
......@@ -160,11 +161,11 @@ public class SmsLogServiceImpl implements SmsLogService {
}
@Override
public void updateSendchampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus) {
if ("delivered".equals(smsReceiveStatus.getStatus())) {
List<SmsLogDO> smsLogDOS = smsLogMapper.selectList(new SmsLogExportReqVO().setApiSerialNo(smsReceiveStatus.getReference()));
if (smsLogDOS != null) {
SmsLogDO smsLogDO = smsLogDOS.get(0);
public void updateSendChampReceive(SendChampSmsClient.SmsReceiveStatus smsReceiveStatus) {
if (SendChampReceiveStatusEnum.DELIVERED.getCode().equals(smsReceiveStatus.getStatus())) {
List<SmsLogDO> smsLogs = smsLogMapper.selectList(new SmsLogExportReqVO().setApiSerialNo(smsReceiveStatus.getReference()));
if (smsLogs != null) {
SmsLogDO smsLogDO = smsLogs.get(0);
smsLogDO.setReceiveStatus(ReceiveStatusEnum.Receive_STATUS_10.getValue());
smsLogDO.setReceiveTime(new Date());
smsLogMapper.updateById(smsLogDO);
......
......@@ -17,7 +17,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsNodeDO;
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.stereotype.Service;
import org.springframework.validation.annotation.Validated;
......@@ -151,8 +150,7 @@ public class SmsNodeServiceImpl extends AbstractService<SmsNodeMapper, SmsNodeDO
}
// 接收失败,则重发
if (ReceiveStatusEnum.Receive_STATUS_20.getValue() == smsLog.getReceiveStatus()) {
smsLog.setReceiveTime(smsLog.getReceiveTime());
if (ReceiveStatusEnum.Receive_STATUS_20.getValue().equals(smsLog.getReceiveStatus())) {
smsLog.setNum(1);
// 从Redis中获取短信节点信息
String node = redisHelper.get(SYSTEM_SMS_NODE_KEY + smsLog.getNodeId());
......
......@@ -106,9 +106,9 @@ public interface SmsSendService {
* @param userType 用户类型
* @param nodeValue 节点值,用于确定短信内容
* @param areaCode 区域代码,用于确定短信发送的国家或地区
* @param isOrders 订单相关标志
* @param isTransport 物流相关标志
* @param transportId 物流
* @param isOrders 是否多订单
* @param isTransport 是否匹配运输方式
* @param transportId 运输方式
* @param messageType 发送类型
* @param templateParams 短信模板参数
* @param smsLogId 重发短信时的原短信日志id
......
......@@ -307,9 +307,9 @@ public class SmsSendServiceImpl implements SmsSendService {
* @param userType 用户类型
* @param nodeValue 节点值,用于确定短信内容
* @param areaCode 区域代码,用于确定短信发送的国家或地区
* @param isOrders 订单相关标志
* @param isTransport 物流相关标志
* @param transportId 物流
* @param isOrders 是否多订单
* @param isTransport 是否匹配运输方式
* @param transportId 运输方式
* @param messageType 发送类型
* @param templateParams 短信模板参数
* @param smsLogId 重发短信时的原短信日志id
......
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