准备工作如下:
- 我们需要在阿里云上开通短信服务,这里可以买资源包,也可以自己充值;
- 创建短信验证签名,签名需要阿里后台审核,一般2小时左右;
- 创建短信模板;
- 在用户头像下菜单,(在AccessKey管理里面创建用户,给他短信的权限获取里面的账户和key) 创建阿里云的授权用户;
我们需要的数据:
名称 | 释义 |
---|---|
accessKeyId | 创建用户的id |
accessKeySecret | 创建用户的秘钥 |
signName | 短信签名名称 |
templateCode | 短信模板的id |
在工程中导入阿里短信的包,这里注意我是用的升级版的SDK 2017-05-25 参考链接点击进入
按照文档要求导入jar包:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea-openapi</artifactId>
<version>0.0.19</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.6</version>
</dependency>
我们先看看官方文档示例代码: 点击跳转示例
这是官方示例代码:
package com.aliyun.sample;
import com.aliyun.tea.*;
import com.aliyun.dysmsapi20170525.*;
import com.aliyun.dysmsapi20170525.models.*;
import com.aliyun.teaopenapi.*;
import com.aliyun.teaopenapi.models.*;
public class Sample {
/**
* 使用AK&SK初始化账号Client
* @param accessKeyId
* @param accessKeySecret
* @return Client
* @throws Exception
*/
public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
Config config = new Config()
// 您的AccessKey ID
.setAccessKeyId(accessKeyId)
// 您的AccessKey Secret
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new com.aliyun.dysmsapi20170525.Client(config);
}
public static void main(String[] args_) throws Exception {
java.util.List<String> args = java.util.Arrays.asList(args_);
com.aliyun.dysmsapi20170525.Client client = Sample.createClient("accessKeyId", "accessKeySecret");
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers("17607146571")
.setSignName("code")
.setTemplateCode("sms_12675377891")
.setTemplateParam("{'code':'123456'}");
// 复制代码运行请自行打印 API 的返回值
client.sendSms(sendSmsRequest);
}
}
我们要做的就是将官方的代码做些更改,更贴合实际的业务开发场景:
- 我们先在配置文件中定义我们要发短信的固定参数,在yml中进行如下配置;
dysms:
accessKeyId: LTAIWjSAN0910892
accessKeySecret: pYtZUs4CCZ57hww19277637OICJSN
signName: 大威天龙 #短信签名
templateCode: SMS_168581995 #这个模板可以有多个,可以根据项目需求定义枚举
这里注意项目中可能会有很多的短信模板,这些可以配置多个,另外短信签名是有可能是中文,用properties配置文件时可能会乱码(这个跟spring的默认加载编码有关系),为了方便推荐使用yml文件配置;
- 我们写个配置文件类,初始化一下这个Client
import com.aliyun.teaopenapi.models.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Auther: MR.rp
* @Date: 2021/8/3 14:31
* @Description:
*/
@Configuration
public class DysmsConfig {
@Value(value = "${dysms.accessKeyId}")
private String accessKeyId;
@Value(value = "${dysms.accessKeySecret}")
private String accessKeySecret;
@Bean
public com.aliyun.dysmsapi20170525.Client careateClient() throws Exception {
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new com.aliyun.dysmsapi20170525.Client(config);
}
}
- 编写短信调用工具类
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
/**
* @Auther: MR.rp
* @Date: 2021/8/3 14:37
* @Description:
*/
@Component
@Slf4j
public class DysmsUtil {
private static Client client;
private static String signName; //签名
public static String templateCode;// 短信验证码模板id
@Value("${dysms.templateCode}")
public void setMsgCode(String templateCode) {
DysmsUtil.templateCode= templateCode;
}
@Autowired
public DysmsUtil(Client client){
this.client = client;
}
@Value("${dysms.signName}")
public void setSIGN(String signName) {
DysmsUtil.signName= signName;
}
/**
* 单条手机发送信息
* @param phoneNums
* @param smsModelId
* @param template
*/
public static void sendMsg(String phoneNums, String templateCode, String template){
//这里为了测试只写单条手机号码的校验是否合法,在开发中如果是多个手机号可以先自己校验再传参
if(!phoneNums.matches("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$"))
log.warn("============ 手机号:"+phoneNums+"不合法,发送失败 ======");
return;
}
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers(phoneNums)
.setSignName(signName) //短信签名名称
.setTemplateCode(templateCode) //短信模板ID
.setTemplateParam(template); //变量值
try {
SendSmsResponse sendSmsResponse = client.sendSms(sendSmsRequest);
SendSmsResponseBody sendBody = sendSmsResponse.getBody();
if(sendBody.getMessage().equals("OK")){
log.info("========== 给:"+phoneNums+"发送短信["+template+"]成功!!! ==========");
}
//下面是查询信息的结果集,因为短信本身会有一定的延迟,所有在查询的时候可能会查不到或者让线程睡眠几秒再查询,这里只是贴出查询代码供大家参考
String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
String bizId = sendBody.bizId;
QuerySendDetailsRequest querySendDetailsRequest = new QuerySendDetailsRequest()
.setPhoneNumber(phoneNums)
.setSendDate(datetime)
.setBizId(bizId)
.setPageSize(10L) //分页
.setCurrentPage(1L);
QuerySendDetailsResponseBody body = client.querySendDetails(querySendDetailsRequest).getBody();
ObjectMapper objectMapper = new ObjectMapper();
String msg = objectMapper.writeValueAsString(body);
log.info("返回的body信息:"+msg);
String message = objectMapper.writeValueAsString(sendBody);
log.info("发送返回信息详情:"+message);
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage(),e);
}
}
/**
* 获取短信验证码
* @return 验证码
*/
public static String getCode() {
String code = null;
code = (int) ((Math.random() * 9 + 1) * 100000) + "";
log.info("验证码为["+code+"]");
return code;
}
}
我们在业务中调用测试一下:
@GetMapping("/getCode")
@ApiOperation(value = "获取验证码",notes = "获取验证码")
@Transactional
public ServerResponseVO getCode(@RequestParam("userTel")@ApiParam("手机号") String userTel,HttpSession session){
boolean matches = userTel.matches("^1(3\\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$");
if(!matches){
return ServerResponseVO.error("手机号码有误");
}
String code = DysmsUtil.getCode();
// session.setAttribute(userTel,code);
// session.setMaxInactiveInterval(300);
redisTemplate.opsForValue().set(userTel,code,300, TimeUnit.SECONDS);// redis存储
String jsonCode = "{'code':'"+code+"'}";
DysmsUtil.sendMsg(userTel,DysmsUtil.msgCode,jsonCode);
log.info("手机号:"+userTel +"获取验证码成功:["+code+"]" );
return ServerResponseVO.success("获取验证码成功");
}
看下日志:
怎么样,很简单吧?
- 在多种短信签名的情况下我们可以多配置几个短信的配置名称,在工具类中注入就可以了,你也可以定义为枚举,当调用时传入当前的枚举或注入的属性,就可以实现发送对应的短信了,这里也要注意传入占位参数时,官方支持的是json格式的哦,笔者之前在这里踩到了,一直发送不成功;
有兴趣小伙伴可以自己测试一下哦