Commit efc5ea23bfcc6fb5ddc211e9a45f824ed751fc8f
1 parent
8242735d
完成todo部分
1,华为云短信实现优化,去除不必要VO; 2,增加华为云短信功能单测; 3,fix华为云短信接收状态回调的bug;
Showing
3 changed files
with
183 additions
and
100 deletions
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java
| ... | ... | @@ -5,16 +5,17 @@ import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 5 | 5 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 6 | 6 | import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; |
| 7 | 7 | import cn.iocoder.yudao.module.system.service.sms.SmsSendService; |
| 8 | +import com.xingyuv.captcha.util.StreamUtils; | |
| 8 | 9 | import io.swagger.v3.oas.annotations.Operation; |
| 9 | 10 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 10 | -import org.springframework.web.bind.annotation.PostMapping; | |
| 11 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 12 | -import org.springframework.web.bind.annotation.RestController; | |
| 11 | +import org.springframework.web.bind.annotation.*; | |
| 13 | 12 | |
| 14 | 13 | import jakarta.annotation.Resource; |
| 15 | 14 | import jakarta.annotation.security.PermitAll; |
| 16 | 15 | import jakarta.servlet.http.HttpServletRequest; |
| 17 | 16 | |
| 17 | +import java.nio.charset.Charset; | |
| 18 | + | |
| 18 | 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 19 | 20 | |
| 20 | 21 | @Tag(name = "管理后台 - 短信回调") |
| ... | ... | @@ -50,10 +51,8 @@ public class SmsCallbackController { |
| 50 | 51 | @PermitAll |
| 51 | 52 | @Operation(summary = "华为云短信的回调", description = "参见 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html 文档") |
| 52 | 53 | @OperateLog(enable = false) |
| 53 | - public CommonResult<Boolean> receiveHuaweiSmsStatus(HttpServletRequest request) throws Throwable { | |
| 54 | - String text = ServletUtils.getBody(request); | |
| 55 | - smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), text); | |
| 54 | + public CommonResult<Boolean> receiveHuaweiSmsStatus(@RequestBody String requestBody) throws Throwable { | |
| 55 | + smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), requestBody); | |
| 56 | 56 | return success(true); |
| 57 | 57 | } |
| 58 | - | |
| 59 | 58 | } | ... | ... |
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClient.java
| ... | ... | @@ -5,12 +5,11 @@ import cn.hutool.core.lang.Assert; |
| 5 | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | 6 | |
| 7 | 7 | import cn.hutool.crypto.SecureUtil; |
| 8 | -import cn.hutool.http.HttpRequest; | |
| 9 | -import cn.hutool.http.HttpResponse; | |
| 10 | 8 | import cn.hutool.json.JSONObject; |
| 11 | 9 | import cn.hutool.json.JSONUtil; |
| 12 | 10 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 13 | 11 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 12 | +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | |
| 14 | 13 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 15 | 14 | import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; |
| 16 | 15 | import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; |
| ... | ... | @@ -18,14 +17,14 @@ import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateR |
| 18 | 17 | import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum; |
| 19 | 18 | import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; |
| 20 | 19 | |
| 21 | -import com.fasterxml.jackson.annotation.JsonFormat; | |
| 22 | -import com.fasterxml.jackson.annotation.JsonProperty; | |
| 23 | -import lombok.Data; | |
| 24 | 20 | import lombok.extern.slf4j.Slf4j; |
| 25 | 21 | |
| 26 | 22 | import java.io.UnsupportedEncodingException; |
| 23 | +import java.net.URLDecoder; | |
| 27 | 24 | import java.net.URLEncoder; |
| 28 | 25 | import java.text.SimpleDateFormat; |
| 26 | +import java.time.Instant; | |
| 27 | +import java.time.ZoneId; | |
| 29 | 28 | import java.util.*; |
| 30 | 29 | |
| 31 | 30 | |
| ... | ... | @@ -33,9 +32,6 @@ import java.time.LocalDateTime; |
| 33 | 32 | |
| 34 | 33 | |
| 35 | 34 | import static cn.hutool.crypto.digest.DigestUtil.sha256Hex; |
| 36 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 37 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 38 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; | |
| 39 | 35 | |
| 40 | 36 | |
| 41 | 37 | /** |
| ... | ... | @@ -47,9 +43,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DE |
| 47 | 43 | @Slf4j |
| 48 | 44 | public class HuaweiSmsClient extends AbstractSmsClient { |
| 49 | 45 | |
| 50 | - /** | |
| 51 | - * 调用成功 code | |
| 52 | - */ | |
| 53 | 46 | public static final String URL = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1";//APP接入地址+接口访问URI |
| 54 | 47 | public static final String HOST = "smsapi.cn-north-4.myhuaweicloud.com:443"; |
| 55 | 48 | public static final String SIGNEDHEADERS = "content-type;host;x-sdk-date"; |
| ... | ... | @@ -78,13 +71,14 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 78 | 71 | |
| 79 | 72 | List<String> templateParas = CollectionUtils.convertList(templateParams, kv -> String.valueOf(kv.getValue())); |
| 80 | 73 | |
| 81 | - JSONObject JsonResponse = sendSmsRequest(sender,mobile,templateId,templateParas,statusCallBack); | |
| 82 | - SmsResponse smsResponse = getSmsSendResponse(JsonResponse); | |
| 74 | + JSONObject JsonResponse = request(sendLogId,sender,mobile,templateId,templateParas,statusCallBack); | |
| 83 | 75 | |
| 84 | - return new SmsSendRespDTO().setSuccess(smsResponse.success).setApiMsg(smsResponse.data.toString()); | |
| 76 | + return new SmsSendRespDTO().setSuccess("000000".equals(JsonResponse.getStr("code"))) | |
| 77 | + .setSerialNo(JsonResponse.getJSONArray("result").getJSONObject(0).getStr("smsMsgId")) | |
| 78 | + .setApiCode(JsonResponse.getJSONArray("result").getJSONObject(0).getStr("status")); | |
| 85 | 79 | } |
| 86 | 80 | |
| 87 | - JSONObject sendSmsRequest(String sender,String mobile,String templateId,List<String> templateParas,String statusCallBack) throws UnsupportedEncodingException { | |
| 81 | + JSONObject request(Long sendLogId,String sender,String mobile,String templateId,List<String> templateParas,String statusCallBack) throws UnsupportedEncodingException { | |
| 88 | 82 | |
| 89 | 83 | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.ENGLISH); |
| 90 | 84 | sdf.setTimeZone(TimeZone.getTimeZone("UTC")); |
| ... | ... | @@ -97,8 +91,7 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 97 | 91 | String canonicalHeaders = "content-type:application/x-www-form-urlencoded\n" |
| 98 | 92 | + "host:"+ HOST +"\n" |
| 99 | 93 | + "x-sdk-date:" + sdkDate + "\n"; |
| 100 | - //请求Body,不携带签名名称时,signature请填null | |
| 101 | - String body = buildRequestBody(sender, mobile, templateId, templateParas, statusCallBack, null); | |
| 94 | + String body = buildRequestBody(sender, mobile, templateId, templateParas, statusCallBack, sendLogId); | |
| 102 | 95 | if (null == body || body.isEmpty()) { |
| 103 | 96 | return null; |
| 104 | 97 | } |
| ... | ... | @@ -118,26 +111,29 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 118 | 111 | + "SignedHeaders=" + SIGNEDHEADERS + ", " + "Signature=" + signature; |
| 119 | 112 | |
| 120 | 113 | // ************* 步骤 5:构造HttpRequest 并执行request请求,获得response ************* |
| 121 | - HttpResponse response = HttpRequest.post(URL) | |
| 122 | - .header("Content-Type", "application/x-www-form-urlencoded") | |
| 123 | - .header("X-Sdk-Date", sdkDate) | |
| 124 | - .header("host",HOST) | |
| 125 | - .header("Authorization", authorization) | |
| 126 | - .body(body) | |
| 127 | - .execute(); | |
| 128 | - | |
| 129 | - return JSONUtil.parseObj(response.body()); | |
| 130 | - } | |
| 131 | - | |
| 132 | - private SmsResponse getSmsSendResponse(JSONObject resJson) { | |
| 133 | - SmsResponse smsResponse = new SmsResponse(); | |
| 134 | - smsResponse.setSuccess("000000".equals(resJson.getStr("code"))); | |
| 135 | - smsResponse.setData(resJson); | |
| 136 | - return smsResponse; | |
| 114 | + TreeMap<String, String> headers = new TreeMap<>(); | |
| 115 | + headers.put("Content-Type", "application/x-www-form-urlencoded"); | |
| 116 | + headers.put("X-Sdk-Date", sdkDate); | |
| 117 | + headers.put("host", HOST); | |
| 118 | + headers.put("Authorization", authorization); | |
| 119 | + | |
| 120 | + String responseBody = HttpUtils.post(URL, headers, body); | |
| 121 | + return JSONUtil.parseObj(responseBody); | |
| 122 | +// | |
| 123 | +// | |
| 124 | +// HttpResponse response = HttpRequest.post(URL) | |
| 125 | +// .header("Content-Type", "application/x-www-form-urlencoded") | |
| 126 | +// .header("X-Sdk-Date", sdkDate) | |
| 127 | +// .header("host",HOST) | |
| 128 | +// .header("Authorization", authorization) | |
| 129 | +// .body(body) | |
| 130 | +// .execute(); | |
| 131 | +// | |
| 132 | +// return JSONUtil.parseObj(response.body()); | |
| 137 | 133 | } |
| 138 | 134 | |
| 139 | 135 | static String buildRequestBody(String sender, String receiver, String templateId, List<String> templateParas, |
| 140 | - String statusCallBack, String signature) throws UnsupportedEncodingException { | |
| 136 | + String statusCallBack, Long sendLogId) throws UnsupportedEncodingException { | |
| 141 | 137 | if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty() |
| 142 | 138 | || templateId.isEmpty()) { |
| 143 | 139 | System.out.println("buildRequestBody(): sender, receiver or templateId is null."); |
| ... | ... | @@ -150,7 +146,9 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 150 | 146 | appendToBody(body, "&templateId=", templateId); |
| 151 | 147 | appendToBody(body, "&templateParas=", JsonUtils.toJsonString(templateParas)); |
| 152 | 148 | appendToBody(body, "&statusCallback=", statusCallBack); |
| 153 | - appendToBody(body, "&signature=", signature); | |
| 149 | + appendToBody(body, "&signature=", null); | |
| 150 | + appendToBody(body, "&extend=", String.valueOf(sendLogId)); | |
| 151 | + | |
| 154 | 152 | return body.toString(); |
| 155 | 153 | } |
| 156 | 154 | |
| ... | ... | @@ -160,12 +158,35 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 160 | 158 | } |
| 161 | 159 | } |
| 162 | 160 | @Override |
| 163 | - public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) { | |
| 164 | - List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class); | |
| 165 | - return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(Objects.equals(status.getStatus(),"DELIVRD")) | |
| 166 | - .setErrorCode(status.getStatus()).setErrorMsg(status.getStatus()) | |
| 167 | - .setMobile(status.getPhoneNumber()).setReceiveTime(status.getUpdateTime()) | |
| 168 | - .setSerialNo(status.getSmsMsgId())); | |
| 161 | + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String requestBody) { | |
| 162 | + | |
| 163 | + System.out.println("text in parseSmsReceiveStatus===== " + requestBody); | |
| 164 | + | |
| 165 | + Map<String, String> params = new HashMap<>(); | |
| 166 | + try { | |
| 167 | + String[] pairs = requestBody.split("&"); | |
| 168 | + for (String pair : pairs) { | |
| 169 | + int idx = pair.indexOf("="); | |
| 170 | + String key = URLDecoder.decode(pair.substring(0, idx), "UTF-8"); | |
| 171 | + String value = URLDecoder.decode(pair.substring(idx + 1), "UTF-8"); | |
| 172 | + params.put(key, value); | |
| 173 | + } | |
| 174 | + } catch (Exception e) { | |
| 175 | + e.printStackTrace(); | |
| 176 | + } | |
| 177 | + | |
| 178 | + List<SmsReceiveRespDTO> respDTOS = new ArrayList<>(); | |
| 179 | + respDTOS.add(new SmsReceiveRespDTO() | |
| 180 | + .setSuccess("DELIVRD".equals(params.get("status"))) // 是否接收成功 | |
| 181 | + .setErrorCode(params.get("status")) // 状态报告编码 | |
| 182 | + .setErrorMsg(params.get("statusDesc")) | |
| 183 | + .setMobile(params.get("to")) // 手机号 | |
| 184 | + .setReceiveTime(LocalDateTime.ofInstant(Instant.parse(params.get("updateTime")), ZoneId.of("UTC"))) // 状态报告时间 | |
| 185 | + .setSerialNo(params.get("smsMsgId")) // 发送序列号 | |
| 186 | + .setLogId(Long.valueOf(params.get("extend")))//logId | |
| 187 | + ); | |
| 188 | + | |
| 189 | + return respDTOS; | |
| 169 | 190 | } |
| 170 | 191 | |
| 171 | 192 | @Override |
| ... | ... | @@ -173,56 +194,5 @@ public class HuaweiSmsClient extends AbstractSmsClient { |
| 173 | 194 | //华为短信模板查询和发送短信,是不同的两套key和secret,与阿里、腾讯的区别较大,这里模板查询校验暂不实现。 |
| 174 | 195 | return new SmsTemplateRespDTO().setId(null).setContent(null) |
| 175 | 196 | .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(null); |
| 176 | - | |
| 177 | 197 | } |
| 178 | - | |
| 179 | - @Data | |
| 180 | - public static class SmsResponse { | |
| 181 | - | |
| 182 | - /** | |
| 183 | - * 是否成功 | |
| 184 | - */ | |
| 185 | - private boolean success; | |
| 186 | - | |
| 187 | - /** | |
| 188 | - * 厂商原返回体 | |
| 189 | - */ | |
| 190 | - private Object data; | |
| 191 | - | |
| 192 | - } | |
| 193 | - | |
| 194 | - | |
| 195 | - /** | |
| 196 | - * 短信接收状态 | |
| 197 | - * | |
| 198 | - * 参见 <a href="https://support.huaweicloud.com/api-msgsms/sms_05_0003.html">文档</a> | |
| 199 | - * | |
| 200 | - * @author scholar | |
| 201 | - */ | |
| 202 | - @Data | |
| 203 | - public static class SmsReceiveStatus { | |
| 204 | - | |
| 205 | - /** | |
| 206 | - * 本条状态报告对应的短信的接收方号码,仅当状态报告中携带了extend参数时才会同时携带该参数 | |
| 207 | - */ | |
| 208 | - @JsonProperty("to") | |
| 209 | - private String phoneNumber; | |
| 210 | - | |
| 211 | - /** | |
| 212 | - * 短信资源的更新时间,通常为短信平台接收短信状态报告的时间 | |
| 213 | - */ | |
| 214 | - @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) | |
| 215 | - private LocalDateTime updateTime; | |
| 216 | - | |
| 217 | - /** | |
| 218 | - * 短信状态报告枚举值 | |
| 219 | - */ | |
| 220 | - private String status; | |
| 221 | - | |
| 222 | - /** | |
| 223 | - * 发送短信成功时返回的短信唯一标识。 | |
| 224 | - */ | |
| 225 | - private String smsMsgId; | |
| 226 | - } | |
| 227 | - | |
| 228 | -} | |
| 198 | +} | |
| 229 | 199 | \ No newline at end of file | ... | ... |
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/HuaweiSmsClientTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.KeyValue; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.http.HttpUtils; | |
| 5 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | |
| 6 | +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; | |
| 7 | +import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; | |
| 8 | +import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties; | |
| 9 | +import com.google.common.collect.Lists; | |
| 10 | + | |
| 11 | +import org.junit.jupiter.api.Test; | |
| 12 | +import org.mockito.InjectMocks; | |
| 13 | +import org.mockito.MockedStatic; | |
| 14 | + | |
| 15 | +import java.time.LocalDateTime; | |
| 16 | +import java.util.List; | |
| 17 | + | |
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | |
| 19 | +import static org.junit.jupiter.api.Assertions.*; | |
| 20 | +import static org.mockito.ArgumentMatchers.*; | |
| 21 | +import static org.mockito.ArgumentMatchers.anyString; | |
| 22 | +import static org.mockito.Mockito.mockStatic; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * {@link HuaweiSmsClient} 的单元测试 | |
| 26 | + * | |
| 27 | + * @author scholar | |
| 28 | + */ | |
| 29 | +public class HuaweiSmsClientTest extends BaseMockitoUnitTest { | |
| 30 | + | |
| 31 | + private final SmsChannelProperties properties = new SmsChannelProperties() | |
| 32 | + .setApiKey(randomString())// 随机一个 apiKey,避免构建报错 | |
| 33 | + .setApiSecret(randomString()) // 随机一个 apiSecret,避免构建报错 | |
| 34 | + .setSignature("芋道源码"); | |
| 35 | + | |
| 36 | + @InjectMocks | |
| 37 | + private HuaweiSmsClient smsClient = new HuaweiSmsClient(properties); | |
| 38 | + | |
| 39 | + @Test | |
| 40 | + public void testDoInit() { | |
| 41 | + // 调用 | |
| 42 | + smsClient.doInit(); | |
| 43 | + } | |
| 44 | + | |
| 45 | + @Test | |
| 46 | + public void testDoSendSms_success() throws Throwable { | |
| 47 | + | |
| 48 | + try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) { | |
| 49 | + // 准备参数 | |
| 50 | + Long sendLogId = randomLongId(); | |
| 51 | + String mobile = randomString(); | |
| 52 | + String apiTemplateId = randomString() + " " + randomString(); | |
| 53 | + List<KeyValue<String, Object>> templateParams = Lists.newArrayList( | |
| 54 | + new KeyValue<>("1", 1234), new KeyValue<>("2", "login")); | |
| 55 | + | |
| 56 | + // mock 方法 | |
| 57 | + httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString())) | |
| 58 | + .thenReturn( | |
| 59 | + "{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"000000\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"000000\",\"description\":\"Success\"}\n" | |
| 60 | + ); | |
| 61 | + | |
| 62 | + // 调用 | |
| 63 | + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, | |
| 64 | + apiTemplateId, templateParams); | |
| 65 | + // 断言 | |
| 66 | + assertTrue(result.getSuccess()); | |
| 67 | + assertEquals("d6e3cdd0-522b-4692-8304-a07553cdf591_8539659", result.getSerialNo()); | |
| 68 | + assertEquals("000000", result.getApiCode()); | |
| 69 | + | |
| 70 | + } | |
| 71 | + } | |
| 72 | + | |
| 73 | + @Test | |
| 74 | + public void testDoSendSms_fail() throws Throwable { | |
| 75 | + try (MockedStatic<HttpUtils> httpUtilsMockedStatic = mockStatic(HttpUtils.class)) { | |
| 76 | + // 准备参数 | |
| 77 | + Long sendLogId = randomLongId(); | |
| 78 | + String mobile = randomString(); | |
| 79 | + String apiTemplateId = randomString() + " " + randomString(); | |
| 80 | + List<KeyValue<String, Object>> templateParams = Lists.newArrayList( | |
| 81 | + new KeyValue<>("1", 1234), new KeyValue<>("2", "login")); | |
| 82 | + | |
| 83 | + // mock 方法 | |
| 84 | + httpUtilsMockedStatic.when(() -> HttpUtils.post(anyString(), anyMap(), anyString())) | |
| 85 | + .thenReturn( | |
| 86 | + "{\"result\":[{\"originTo\":\"+86155****5678\",\"createTime\":\"2018-05-25T16:34:34Z\",\"from\":\"1069********0012\",\"smsMsgId\":\"d6e3cdd0-522b-4692-8304-a07553cdf591_8539659\",\"status\":\"E200015\",\"countryId\":\"CN\",\"total\":2}],\"code\":\"E000000\",\"description\":\"Success\"}\n" | |
| 87 | + ); | |
| 88 | + | |
| 89 | + // 调用 | |
| 90 | + SmsSendRespDTO result = smsClient.sendSms(sendLogId, mobile, | |
| 91 | + apiTemplateId, templateParams); | |
| 92 | + // 断言 | |
| 93 | + assertFalse(result.getSuccess()); | |
| 94 | + assertEquals("d6e3cdd0-522b-4692-8304-a07553cdf591_8539659", result.getSerialNo()); | |
| 95 | + assertEquals("E200015", result.getApiCode()); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + | |
| 99 | + @Test | |
| 100 | + public void testParseSmsReceiveStatus() { | |
| 101 | + // 准备参数 | |
| 102 | + String text = "sequence=1&total=1&statusDesc=%E7%94%A8%E6%88%B7%E5%B7%B2%E6%88%90%E5%8A%9F%E6%94%B6%E5%88%B0%E7%9F%AD%E4%BF%A1&updateTime=2024-08-15T03%3A00%3A34Z&source=2&smsMsgId=70207ed7-1d02-41b0-8537-bb25fd1c2364_143684459&status=DELIVRD&extend=176"; | |
| 103 | + | |
| 104 | + // 调用 | |
| 105 | + List<SmsReceiveRespDTO> statuses = smsClient.parseSmsReceiveStatus(text); | |
| 106 | + // 断言 | |
| 107 | + assertEquals(1, statuses.size()); | |
| 108 | + assertTrue(statuses.getFirst().getSuccess()); | |
| 109 | + assertEquals("DELIVRD", statuses.getFirst().getErrorCode()); | |
| 110 | + assertEquals(LocalDateTime.of(2024, 8, 15, 3, 0, 34), statuses.getFirst().getReceiveTime()); | |
| 111 | + assertEquals("70207ed7-1d02-41b0-8537-bb25fd1c2364_143684459", statuses.getFirst().getSerialNo()); | |
| 112 | + } | |
| 113 | + | |
| 114 | +} | ... | ... |