Springboot - 接入阿里云短信服务
1.加入maven依赖
<!--阿里云的短信服务SDK-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.1.0</version>
</dependency>
2.创建自动注入配置
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author Created by 谭健 on 2018/5/31 0031. 星期四. 12:03.
* © All Rights Reserved.
*/
@Slf4j
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "aliyun.sms")
public class AliyunSMSConfig {
private String accessKeyId;
private String accessKeySecret;
private String product;
private String domain;
private String regionId;
private String signName;
private String dateFormat;
private String endpointName;
}
3.填写注入配置
// 在application.yml中增加如下配置
#--------------------------短信--------------------------
aliyun:
sms:
accessKeyId: -------
accessKeySecret: -------
product: Dysmsapi
domain: dysmsapi.aliyuncs.com
regionId: cn-hangzhou
signName: OnlineZuozuo
dateFormat: yyyyMMdd
endpointName: cn-hangzhou
4.创建Spring Bean
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.simply.zuozuo.config.plugin.AliyunSMSConfig;
import com.simply.zuozuo.util.ApplicationContextUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author Created by 谭健 on 2018/5/31 0031. 星期四. 13:05.
* © All Rights Reserved.
*/
@Component
@Slf4j
public class SimpleSMSSender {
// 自动注册短信服务的配置
@Autowired
private AliyunSMSConfig smsConfig;
public static SMS newSMS(){
return new SMS();
}
// 一个短信实体
@Data
public static class SMS {
private String phoneNumbers;
private String templateParam;
private String outId;
private String templateCode;
}
@Data
public static class Result {
private SendSmsResponse sendSmsResponse;
// private QuerySendDetailsResponse querySendDetailsResponse;
private SMS sms;
// private Query query;
}
// 如果希望使用静态方法调用的形式发送可以加入下面2个方法进行发送
// 如果希望使用@Autowired 自动注册的方式可以不加下面2个方法
public static Result send(SMS sms) {
SimpleSMSSender simpleSMSSender = (SimpleSMSSender) ApplicationContextUtils.get("simpleSMSSender");
return simpleSMSSender.sendSms(sms);
}
public static QuerySendDetailsResponse query(Query query) {
SimpleSMSSender simpleSMSSender = (SimpleSMSSender) ApplicationContextUtils.get("simpleSMSSender");
return simpleSMSSender.querySendDetails(query);
}
/**
* 发送短信
*
*
* 发送验证码类的短信时,每个号码每分钟最多发送一次,每个小时最多发送5次。
* 其它类短信频控请参考阿里云
*
* @param sms 短信
*/
public Result sendSms(SMS sms) {
IAcsClient acsClient = getClient();
SendSmsRequest request = getRequest(sms);
SendSmsResponse sendSmsResponse = null;
try {
sendSmsResponse = acsClient.getAcsResponse(request);
} catch (ClientException e) {
log.error("发送短信发生错误。错误代码是 [{}],错误消息是 [{}],错误请求ID是 [{}],错误Msg是 [{}],错误类型是 [{}]", e.getErrCode(), e.getMessage(), e.getRequestId(), e.getErrMsg(), e.getErrorType());
e.printStackTrace();
}
// 由于响应不及时,不能在这里构建查询,直接查询,smsSendDetailDTOs 会获取到null,可以考虑异步方法 线程睡眠5秒再查询,结果保存数据库进行持久化
// // 构建查询
// Query query = new Query();
// query.setBizId(sendSmsResponse.getBizId());
// query.setCurrentPage(1L);
// query.setPageSize(10L);
// query.setPhoneNumber(sms.getPhoneNumbers());
// query.setSendDate(new Date());
// // 查询发送结果
// QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(query);
Result result = new Result();
result.setSendSmsResponse(sendSmsResponse);
// result.setQuerySendDetailsResponse(querySendDetailsResponse);
// result.setQuery(query);
result.setSms(sms);
return result;
}
public static Query newQuery(){
return new Query();
}
// 构建一个查询器
@Data
public static class Query {
/** 业务ID */
private String bizId;
private String phoneNumber;
private Date sendDate;
private Long pageSize;
private Long currentPage;
}
/**
* 查询短信发送结果
*
* @param query 查询条件
*/
public QuerySendDetailsResponse querySendDetails(Query query) {
IAcsClient acsClient = getClient();
QuerySendDetailsRequest request = new QuerySendDetailsRequest();
request.setPhoneNumber(query.getPhoneNumber());
request.setBizId(query.getBizId());
SimpleDateFormat ft = new SimpleDateFormat(smsConfig.getDateFormat());
request.setSendDate(ft.format(query.getSendDate()));
request.setPageSize(query.getPageSize());
request.setCurrentPage(query.getCurrentPage());
QuerySendDetailsResponse querySendDetailsResponse = null;
try {
querySendDetailsResponse = acsClient.getAcsResponse(request);
} catch (ClientException e) {
e.printStackTrace();
}
return querySendDetailsResponse;
}
// 获取短信请求
private SendSmsRequest getRequest(SMS sms) {
SendSmsRequest request = new SendSmsRequest();
request.setPhoneNumbers(sms.getPhoneNumbers());
request.setSignName(smsConfig.getSignName());
request.setTemplateCode(sms.getTemplateCode());
request.setTemplateParam(sms.getTemplateParam());
request.setOutId(sms.getOutId());
return request;
}
// 获取短信发送服务机
private IAcsClient getClient() {
IClientProfile profile = DefaultProfile.getProfile(smsConfig.getRegionId(), smsConfig.getAccessKeyId(), smsConfig.getAccessKeySecret());
try {
DefaultProfile.addEndpoint(smsConfig.getEndpointName(), smsConfig.getRegionId(), smsConfig.getProduct(), smsConfig.getDomain());
} catch (ClientException e) {
e.printStackTrace();
}
return new DefaultAcsClient(profile);
}
}
5.发送用例
// 使用静态方法
@GetMapping("/sms")
@ResponseBody
public String sms() {
SimpleSMSSender.SMS sms = SimpleSMSSender.newSMS();
sms.setPhoneNumbers("15197447018");
sms.setTemplateParam("{\"code\":\"123456\"}");
sms.setTemplateCode("SMS_136166452");
SimpleSMSSender.Result result = SimpleSMSSender.send(sms);
return JSON.toJSONString(result);
}
// 使用自动注册
@Autowired
private SimpleSMSSender simpleSMSSender;
@GetMapping("/sms/auto")
@ResponseBody
public String smsAuto() {
SimpleSMSSender.SMS sms = SimpleSMSSender.newSMS();
sms.setPhoneNumbers("13526401709");
sms.setTemplateParam("{\"code\":\"123456\"}");
sms.setTemplateCode("SMS_136166452");
SimpleSMSSender.Result result = simpleSMSSender.sendSms(sms);
return JSON.toJSONString(result);
}
6.发送详解
// 上面的代码是对Springboot做了兼容处理和封装的
// 下面的代码详细说明发送过程以及发送结果
// 如有需要,可以根据此段代码进行自己的封装
// 自己封装全部弄好,弄完整,包括申请账号,创建短信模版,创建key和secret,创建签名等,在不出任何意料之外的bug时,工期约1天。
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
* # Copyright (c) 2010-2018 Online zuozuo
* # Copyright (c) 2018 Online zuozuo
* # @email : [email protected]
*/
public class SmsDemo {
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
static final String accessKeyId = "---------";
static final String accessKeySecret = "---------";
public static SendSmsResponse sendSms() throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers("15197447018");
//必填:短信签名-可在短信控制台中找到
request.setSignName("OnlineZuozuo");
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("SMS_136166452");
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"
request.setTemplateParam("{\"code\":\"123456\"}");
//选填-上行短信扩展码(无特殊需求用户请忽略此字段)
//request.setSmsUpExtendCode("90997");
//可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
request.setOutId("yourOutId");
//hint 此处可能会抛出异常,注意catch
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
return sendSmsResponse;
}
public static QuerySendDetailsResponse querySendDetails(String bizId) throws ClientException {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象
QuerySendDetailsRequest request = new QuerySendDetailsRequest();
//必填-号码
request.setPhoneNumber("15197447018");
//可选-流水号
request.setBizId(bizId);
//必填-发送日期 支持30天内记录查询,格式yyyyMMdd
SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
request.setSendDate(ft.format(new Date()));
//必填-页大小
request.setPageSize(10L);
//必填-当前页码从1开始计数
request.setCurrentPage(1L);
//hint 此处可能会抛出异常,注意catch
QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
return querySendDetailsResponse;
}
public static void main(String[] args) throws ClientException, InterruptedException {
//发短信
SendSmsResponse response = sendSms();
System.out.println("短信接口返回的数据----------------");
System.out.println("Code=" + response.getCode());
System.out.println("Message=" + response.getMessage());
System.out.println("RequestId=" + response.getRequestId());
System.out.println("BizId=" + response.getBizId());
// 对接上面的,如果这里不等待,直接查询,会查到一个空的结果
Thread.sleep(3000L);
//查明细
if (response.getCode() != null && response.getCode().equals("OK")) {
QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(response.getBizId());
System.out.println("短信明细查询接口返回数据----------------");
System.out.println("Code=" + querySendDetailsResponse.getCode());
System.out.println("Message=" + querySendDetailsResponse.getMessage());
int i = 0;
for (QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse.getSmsSendDetailDTOs()) {
System.out.println("SmsSendDetailDTO[" + i + "]:");
System.out.println("Content=" + smsSendDetailDTO.getContent());
System.out.println("ErrCode=" + smsSendDetailDTO.getErrCode());
System.out.println("OutId=" + smsSendDetailDTO.getOutId());
System.out.println("PhoneNum=" + smsSendDetailDTO.getPhoneNum());
System.out.println("ReceiveDate=" + smsSendDetailDTO.getReceiveDate());
System.out.println("SendDate=" + smsSendDetailDTO.getSendDate());
System.out.println("SendStatus=" + smsSendDetailDTO.getSendStatus());
System.out.println("Template=" + smsSendDetailDTO.getTemplateCode());
}
System.out.println("TotalCount=" + querySendDetailsResponse.getTotalCount());
System.out.println("RequestId=" + querySendDetailsResponse.getRequestId());
}
}
}