短信回调的解析重构

pull/2/head
YunaiV 2021-04-04 13:12:42 +08:00
parent c91833a504
commit 8ab29d2a25
13 changed files with 254 additions and 215 deletions

View File

@ -39,6 +39,6 @@ public interface SmsClient {
* @return
* @throws Throwable text
*/
SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
}

View File

@ -1,9 +1,7 @@
package cn.iocoder.dashboard.framework.sms.core.client.dto;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
@ -12,35 +10,39 @@ import java.util.Date;
* @author
*/
@Data
public class SmsReceiveRespDTO implements Serializable {
public class SmsReceiveRespDTO {
/**
*
*
*/
private String apiId;
private Boolean success;
/**
* API
*/
private String errorCode;
/**
* API
*/
private String errorMsg;
/**
* {@link SysSmsSendStatusEnum}
*
*/
private Integer sendStatus;
private String mobile;
/**
*
*/
private Date receiveTime;
/**
*
* API
*/
private String phone;
private String serialNo;
/**
*
*
*
* SysSmsLogDO
*/
private String message;
private Long logId;
/**
*
*/
private Date sendTime;
/**
*
*/
private Object callbackResponseBody;
}

View File

@ -90,7 +90,7 @@ public abstract class AbstractSmsClient implements SmsClient {
throws Throwable;
@Override
public SmsCommonResult<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
try {
return doParseSmsReceiveStatus(text);
} catch (Throwable ex) {
@ -99,6 +99,6 @@ public abstract class AbstractSmsClient implements SmsClient {
}
}
protected abstract SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
}

View File

@ -1,7 +1,5 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.core.KeyValue;
import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
@ -9,7 +7,6 @@ import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.dashboard.util.collection.MapUtils;
import cn.iocoder.dashboard.util.json.JsonUtils;
import com.aliyuncs.DefaultAcsClient;
@ -20,16 +17,17 @@ import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
*
@ -40,8 +38,9 @@ import java.util.Map;
@Slf4j
public class AliyunSmsClient extends AbstractSmsClient {
private static final String PRODUCT = "Dystopi";
private static final String DOMAIN = "dysmsapi.aliyuncs.com";
/**
* REGION, 使
*/
private static final String ENDPOINT = "cn-hangzhou";
/**
@ -56,7 +55,6 @@ public class AliyunSmsClient extends AbstractSmsClient {
@Override
protected void doInit() {
IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
DefaultProfile.addEndpoint(ENDPOINT, PRODUCT, DOMAIN);
acsClient = new DefaultAcsClient(profile);
}
@ -93,133 +91,80 @@ public class AliyunSmsClient extends AbstractSmsClient {
return ex.getErrMsg() + " => " + ex.getErrorDescription();
}
/**
* [{
* "send_time" : "2017-08-30 00:00:00",
* "report_time" : "2017-08-30 00:00:00",
* "success" : true,
* "err_msg" : "用户接收成功",
* "err_code" : "DELIVERED",
* "phone_number" : "18612345678",
* "sms_size" : "1",
* "biz_id" : "932702304080415357^0",
* "out_id" : "1184585343"
* }]
*
* @param request
* @return
* @throws Exception
*/
public SmsReceiveRespDTO smsSendCallbackHandle(ServletRequest request) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
String paramStr = reader.readLine();
List<Map<String, Object>> params = JsonUtils.parseObject(paramStr, new TypeReference<List<Map<String, Object>>>() {
});
if (CollectionUtil.isNotEmpty(params)) {
Map<String, Object> sendResultParamMap = params.get(0);
return CallbackHelper.of(sendResultParamMap).toResultDetail();
}
return null;
}
@Override
protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
return null;
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return statuses.stream().map(status -> {
SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
resp.setSuccess(status.getSuccess());
resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg());
resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime());
resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()));
return resp;
}).collect(Collectors.toList());
}
/**
*
*
*
* https://help.aliyun.com/document_detail/101867.html 文档
*
* @author
*/
private static class CallbackHelper {
private final Map<String, Object> sendResultParamMap;
private CallbackHelper(Map<String, Object> sendResultParamMap) {
this.sendResultParamMap = sendResultParamMap;
}
public static CallbackHelper of(Map<String, Object> sendResultParamMap) {
return new CallbackHelper(sendResultParamMap);
}
public Integer getSendStatus() {
return ((Boolean) sendResultParamMap.get(CallbackField.SUCCESS))
? SysSmsSendStatusEnum.SUCCESS.getStatus()
: SysSmsSendStatusEnum.FAILURE.getStatus();
}
public String getBizId() {
return sendResultParamMap.get(CallbackField.BIZ_ID).toString();
}
public String getErrMsg() {
return sendResultParamMap.get(CallbackField.ERR_MSG).toString();
}
public String getErrCode() {
return sendResultParamMap.get(CallbackField.ERR_CODE).toString();
}
public Date getSendTime() {
return DateUtil.parseTime(sendResultParamMap.get(CallbackField.SEND_TIME).toString());
}
public String getPhoneNumber() {
return sendResultParamMap.get(CallbackField.PHONE_NUMBER).toString();
}
public String getOutId() {
return sendResultParamMap.get(CallbackField.OUT_ID).toString();
}
public SmsReceiveRespDTO toResultDetail() {
SmsReceiveRespDTO resultDetail = new SmsReceiveRespDTO();
resultDetail.setSendStatus(getSendStatus());
resultDetail.setApiId(getBizId());
resultDetail.setSendTime(getSendTime());
resultDetail.setPhone(getPhoneNumber());
resultDetail.setMessage(getErrMsg());
resultDetail.setCallbackResponseBody(generateSuccessResponseBody());
return resultDetail;
}
@Data
public static class SmsReceiveStatus {
/**
*
*
*/
private Map<String, Object> generateSuccessResponseBody() {
Map<String, Object> result = new HashMap<>();
result.put("code", 0);
result.put("msg", "成功");
return result;
}
@JsonProperty("phone_number")
private String phoneNumber;
/**
*
*/
@JsonProperty("send_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private Date sendTime;
/**
*
*/
@JsonProperty("report_time")
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private Date reportTime;
/**
*
*/
private Boolean success;
/**
*
*/
@JsonProperty("err_msg")
private String errMsg;
/**
*
*/
@JsonProperty("err_code")
private String errCode;
/**
*
*/
@JsonProperty("biz_id")
private String bizId;
/**
*
*
* SysSmsLogDO
*/
@JsonProperty("out_id")
private String outId;
/**
* 123
*
* 140 140
*/
@JsonProperty("sms_size")
private Integer smsSize;
}
/**
*
*/
private interface CallbackField {
//是否成功 boolean
String SUCCESS = "success";
//发送时间
String SEND_TIME = "send_time";
//错误信息
String ERR_MSG = "err_msg";
//错误编码
String ERR_CODE = "err_code";
//手机号
String PHONE_NUMBER = "phone_number";
//用户序列号 out_id
String OUT_ID = "out_id";
//biz_id 即 apiId 唯一标识
String BIZ_ID = "biz_id";
}
}

View File

@ -1,8 +1,6 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.iocoder.dashboard.common.core.KeyValue;
@ -11,11 +9,9 @@ import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.dashboard.util.date.DateUtils;
import cn.iocoder.dashboard.util.json.JsonUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result;
@ -23,10 +19,11 @@ import com.yunpian.sdk.model.SmsSingleSend;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
/**
*
@ -42,9 +39,6 @@ public class YunpianSmsClient extends AbstractSmsClient {
*/
private volatile YunpianClient client;
private final TypeReference<List<Map<String, String>>> callbackType = new TypeReference<List<Map<String, String>>>() {
};
public YunpianSmsClient(SmsChannelProperties properties) {
super(properties, new YunpianSmsCodeMapping());
}
@ -105,28 +99,17 @@ public class YunpianSmsClient extends AbstractSmsClient {
return sendResult.getMsg() + " => " + sendResult.getDetail();
}
/**
* request
*
* @param request
* @return
* @throws UnsupportedEncodingException
*/
private Map<String, String> getRequestParams(ServletRequest request) throws UnsupportedEncodingException {
Map<String, String[]> parameterMap = request.getParameterMap();
String[] smsStatuses = parameterMap.get(YunpianConstant.SMS_STATUS);
String encode = URLEncoder.encode(smsStatuses[0], CharsetUtil.UTF_8);
List<Map<String, String>> paramList = JsonUtils.parseObject(encode, callbackType);
if (CollectionUtil.isNotEmpty(paramList)) {
return paramList.get(0);
}
throw new IllegalArgumentException("YunpianSmsClient getRequestParams fail! can't format RequestParam: "
+ JsonUtils.toJsonString(request.getParameterMap()));
}
@Override
protected SmsCommonResult<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
return null;
protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
return statuses.stream().map(status -> {
SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS"));
resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail());
resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime());
resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid());
return resp;
}).collect(Collectors.toList());
}
/**
@ -139,6 +122,24 @@ public class YunpianSmsClient extends AbstractSmsClient {
@Data
public static class SmsReceiveStatus {
/**
*
*
* SUCCESS / FAIL使 Boolean
*/
@JsonProperty("report_status")
private String reportStatus;
/**
*
*/
private String mobile;
/**
* "DB:0103"
*
*
*/
@JsonProperty("error_msg")
private String errorMsg;
/**
*
*
@ -160,26 +161,8 @@ public class YunpianSmsClient extends AbstractSmsClient {
*
*/
@JsonProperty("user_receive_time")
@JsonFormat(pattern = DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
private Date userReceiveTime;
/**
* "DB:0103"
*
*
*/
@JsonProperty("error_msg")
private String errorMsg;
/**
*
*/
private String mobile;
/**
*
*
* SUCCESS / FAIL使 Boolean
*/
@JsonProperty("report_status")
private String reportStatus;
}

View File

@ -152,7 +152,7 @@ public class SysSmsServiceImpl implements SysSmsService {
SmsClient smsClient = smsClientFactory.getSmsClient(channelCode);
Assert.notNull(smsClient, String.format("短信客户端(%s) 不存在", channelCode));
// 解析内容
SmsCommonResult<SmsReceiveRespDTO> receiveResult = smsClient.parseSmsReceiveStatus(text);
List<SmsReceiveRespDTO> receiveResults = smsClient.parseSmsReceiveStatus(text);
}
}

View File

@ -9,6 +9,11 @@ import java.util.Date;
*/
public class DateUtils {
/**
* -
*/
public static final String TIME_ZONE_DEFAULT = "GMT+8";
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
public static Date addTime(Duration duration) {

View File

@ -2,7 +2,6 @@ package cn.iocoder.dashboard.util.json;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -80,10 +79,4 @@ public class JsonUtils {
}
}
public static void main(String[] args) {
String text = "[{\"sid\":9527,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"},{\"sid\":9528,\"uid\":null,\"user_receive_time\":\"2014-03-17 22:55:23\",\"error_msg\":\"\",\"mobile\":\"15212341234\",\"report_status\":\"SUCCESS\"}]";
List<YunpianSmsClient.SmsReceiveStatus> result = parseArray(text, YunpianSmsClient.SmsReceiveStatus.class);
System.out.println(result);
}
}

View File

@ -13,7 +13,7 @@ import java.util.List;
/**
* {@link AliyunSmsClient}
*/
public class AliyunSmsClientTest {
public class AliyunSmsClientIntegrationTest {
@Test
public void testSend() {

View File

@ -34,7 +34,7 @@ public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest
private SysUserService userService;
@Test
public void testSendSingleSms_() {
public void testSendSingleSms_yunpianSuccess() {
// 参数准备
String mobile = "15601691399";
Long userId = 1L;
@ -50,7 +50,7 @@ public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest
}
@Test
public void testSendSingleSms_() {
public void testSendSingleSms_aliyunSuccess() {
// 参数准备
String mobile = "15601691399";
Long userId = 1L;

View File

@ -0,0 +1 @@
package cn.iocoder.dashboard.framework;

View File

@ -0,0 +1,60 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.util.date.DateUtils;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link AliyunSmsClient}
*/
public class AliyunSmsClientTest {
@InjectMocks
private final AliyunSmsClient smsClient = new AliyunSmsClient(null);
@Test
void doInit() {
}
@Test
void doSendSms() {
}
@Test
public void testDoTParseSmsReceiveStatus() throws Throwable {
// 准备参数
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 = smsClient.doParseSmsReceiveStatus(text);
// 断言
assertEquals(1, statuses.size());
assertTrue(statuses.get(0).getSuccess());
assertEquals("DELIVERED", statuses.get(0).getErrorCode());
assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
assertEquals("13900000001", statuses.get(0).getMobile());
assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime());
assertEquals("12345", statuses.get(0).getSerialNo());
assertEquals(67890L, statuses.get(0).getLogId());
}
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.dashboard.util.date.DateUtils;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* {@link YunpianSmsClient}
*/
public class YunpianSmsClientTest {
@InjectMocks
private final YunpianSmsClient smsClient = new YunpianSmsClient(null);
@Test
void doInit() {
}
@Test
void doSendSms() {
}
@Test
void testDoParseSmsReceiveStatus() throws Throwable {
// 准备参数
String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]";
// mock 方法
// 调用
// 断言
// 调用
List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
// 断言
assertEquals(1, statuses.size());
assertTrue(statuses.get(0).getSuccess());
assertEquals("", statuses.get(0).getErrorCode());
assertNull(statuses.get(0).getErrorMsg());
assertEquals("15205201314", statuses.get(0).getMobile());
assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime());
assertEquals("9527", statuses.get(0).getSerialNo());
assertEquals(1024L, statuses.get(0).getLogId());
}
}