潘志宝
4 天以前 10edab49cfd859ea4928c969da658b4a548f5b71
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.framework.sms.core.client.impl;
H 2
3 import cn.hutool.core.lang.Assert;
4 import com.iailab.framework.common.core.KeyValue;
5 import com.iailab.framework.common.util.collection.MapUtils;
6 import com.iailab.framework.common.util.json.JsonUtils;
7 import com.iailab.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
8 import com.iailab.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
9 import com.iailab.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
10 import com.iailab.module.system.framework.sms.core.client.impl.AbstractSmsClient;
11 import com.iailab.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
12 import com.iailab.module.system.framework.sms.core.property.SmsChannelProperties;
13 import com.aliyuncs.DefaultAcsClient;
14 import com.aliyuncs.IAcsClient;
15 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
16 import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
17 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
18 import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
19 import com.aliyuncs.profile.DefaultProfile;
20 import com.aliyuncs.profile.IClientProfile;
21 import com.fasterxml.jackson.annotation.JsonFormat;
22 import com.fasterxml.jackson.annotation.JsonProperty;
23 import com.google.common.annotations.VisibleForTesting;
24 import lombok.Data;
25 import lombok.extern.slf4j.Slf4j;
26
27 import java.time.LocalDateTime;
28 import java.util.List;
29 import java.util.Objects;
30
31 import static com.iailab.framework.common.util.collection.CollectionUtils.convertList;
32 import static com.iailab.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
33 import static com.iailab.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
34
35 /**
36  * 阿里短信客户端的实现类
37  *
38  * @author zzf
39  * @since 2021/1/25 14:17
40  */
41 @Slf4j
42 public class AliyunSmsClient extends AbstractSmsClient {
43
44     /**
45      * 调用成功 code
46      */
47     public static final String API_CODE_SUCCESS = "OK";
48
49     /**
50      * REGION, 使用杭州
51      */
52     private static final String ENDPOINT = "cn-hangzhou";
53
54     /**
55      * 阿里云客户端
56      */
57     private volatile IAcsClient client;
58
59     public AliyunSmsClient(SmsChannelProperties properties) {
60         super(properties);
61         Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
62         Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
63     }
64
65     @Override
66     protected void doInit() {
67         IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
68         client = new DefaultAcsClient(profile);
69     }
70
71     @Override
72     public SmsSendRespDTO sendSms(Long sendLogId, String mobile, String apiTemplateId,
73                                   List<KeyValue<String, Object>> templateParams) throws Throwable {
74         // 构建请求
75         SendSmsRequest request = new SendSmsRequest();
76         request.setPhoneNumbers(mobile);
77         request.setSignName(properties.getSignature());
78         request.setTemplateCode(apiTemplateId);
79         request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
80         request.setOutId(String.valueOf(sendLogId));
81         // 执行请求
82         SendSmsResponse response = client.getAcsResponse(request);
83         return new SmsSendRespDTO().setSuccess(Objects.equals(response.getCode(), API_CODE_SUCCESS)).setSerialNo(response.getBizId())
84                 .setApiRequestId(response.getRequestId()).setApiCode(response.getCode()).setApiMsg(response.getMessage());
85     }
86
87     @Override
88     public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
89         List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
90         return convertList(statuses, status -> new SmsReceiveRespDTO().setSuccess(status.getSuccess())
91                 .setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg())
92                 .setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime())
93                 .setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId())));
94     }
95
96     @Override
97     public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) throws Throwable {
98         // 构建请求
99         QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
100         request.setTemplateCode(apiTemplateId);
101         // 执行请求
102         QuerySmsTemplateResponse response = client.getAcsResponse(request);
103         if (response.getTemplateStatus() == null) {
104             return null;
105         }
106         return new SmsTemplateRespDTO().setId(response.getTemplateCode()).setContent(response.getTemplateContent())
107                 .setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
108     }
109
110     @VisibleForTesting
111     Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
112         switch (templateStatus) {
113             case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
114             case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
115             case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
116             default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
117         }
118     }
119
120     /**
121      * 短信接收状态
122      *
123      * 参见 <a href="https://help.aliyun.com/document_detail/101867.html">文档</a>
124      *
125      * @author iailab
126      */
127     @Data
128     public static class SmsReceiveStatus {
129
130         /**
131          * 手机号
132          */
133         @JsonProperty("phone_number")
134         private String phoneNumber;
135         /**
136          * 发送时间
137          */
138         @JsonProperty("send_time")
139         @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
140         private LocalDateTime sendTime;
141         /**
142          * 状态报告时间
143          */
144         @JsonProperty("report_time")
145         @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
146         private LocalDateTime reportTime;
147         /**
148          * 是否接收成功
149          */
150         private Boolean success;
151         /**
152          * 状态报告说明
153          */
154         @JsonProperty("err_msg")
155         private String errMsg;
156         /**
157          * 状态报告编码
158          */
159         @JsonProperty("err_code")
160         private String errCode;
161         /**
162          * 发送序列号
163          */
164         @JsonProperty("biz_id")
165         private String bizId;
166         /**
167          * 用户序列号
168          *
169          * 这里我们传递的是 SysSmsLogDO 的日志编号
170          */
171         @JsonProperty("out_id")
172         private String outId;
173         /**
174          * 短信长度,例如说 1、2、3
175          *
176          * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送
177          */
178         @JsonProperty("sms_size")
179         private Integer smsSize;
180
181     }
182
183 }