SpringBoot集成腾讯云短信服务
前言
可以说现在一个成熟的软件基本上都会具有发送短信验证码的场景;比如在这些场景中:
- 用户使用手机号进行注册
- 用户使用短信验证码登录
- 用户忘记密码,通过发送手机验证码,进行重置密码
- 修改手机号
- 修改密码
在以上场景中,我们就需要集成短信服务。现在的短信服务众多,例如:腾讯云、阿里云等。
在这篇文章中将使用SpringBoot集成腾讯云的短信服务。
开始集成
准备阶段
我们需要先注册一个腾讯云的账号,然后在腾讯云的产品里面找到短信
里面有相应的短信套餐可以选择,如果是新用户注册的话,会有一定的免费短信条数。
然后我们进入短信的控制台页面,我们先要创建一个短信签名,其中签名用途,签名类型和签名内容等根据自己的实际情况进行填写。
注意:签名内容为短信验证码【】中括号里面的内容,如:【xxx】1234为您的验证码,请于5分钟内输入。其签名内容就为 xxx。
填写完成之后,确定即可。在签名管理中就可以看到刚刚创建的短信签名。当显示的状态变为已通过后该签名就可以使用了。
接下来我们需要创建短信的模板。选择创建正文模板选项,根据实际情况进行填写。填写完成,确定即可。其中短信内容部分{1}{2}等变量参数为动态参数,需要我们在代码中请求腾讯云短信服务时携带。
创建完成模板状态显示已通过即可使用。
Coding阶段
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.junwei</groupId>
<artifactId>smsdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>smsdemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<qcloudsms.version>1.0.6</qcloudsms.version>
<lombok.versino>1.18.8</lombok.versino>
<httpclient.version>4.5.9</httpclient.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.github.qcloudsms</groupId>
<artifactId>qcloudsms</artifactId>
<version>${qcloudsms.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.versino}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
注意:需要使用redis缓存数据库
server:
port: 9016
spring:
application:
name: sms-service
redis:
host: 127.0.0.1
port: 6379
smsconfig:
appId: 腾讯云短信应用id
appkey: 腾讯云短信应用key
smsSign: 腾讯云创建的短信签名
templateid: 腾讯云短信模板id
invalidtime: 验证码失效时间
# redis存储前缀,根据不同类型做区分
phone-prefix: LOGIN,REGIST,FORGET_PASSWORD,UPDATE_MOBILE,UPDATE_PASSWORD,WX_UN_TYING,UPDATE_NEW_MOBILE
logging:
level:
root: info
短信签名和短信模板id在以上配置成功后就可以看到;腾讯云AppId和AppKey在这里:
Controller
@RestController
@RequestMapping("sms")
public class SmsController {
@Autowired
private SmsService smsService;
@PostMapping("send")
public Result send(@RequestBody SendSmsDto sendSmsDto) {
smsService.sendSmsCode(sendSmsDto);
return Result.success("");
}
@PostMapping("verify")
public Result verify(@RequestBody VerifyCodeDto verifyCodeDto) {
smsService.verifyCode(verifyCodeDto);
return Result.success("");
}
}
SmsConfig
@Configuration
public class SmsConfig {
/**
* 初始化主账号名称
**/
@Value("${smsconfig.appkey}")
private String APP_KEY;
/**
* 初始化应用ID
**/
@Value("${smsconfig.appId}")
private int APP_ID;
@Bean
public SmsSingleSender ssender() {
return new SmsSingleSender(APP_ID, APP_KEY);
}
}
ServiceImpl
@Service
@Slf4j
public class SmsServiceImpl implements SmsService {
@Autowired
private SmsSingleSender smsSingleSender;
@Autowired
private RedisUtil redisUtil;
/**
* 短信模板ID
**/
@Value("${smsconfig.templateid}")
private int TEMPLATE_ID;
/**
* 短信签名内容
*/
@Value("${smsconfig.smsSign}")
private String SMS_SIGN;
@Value("${smsconfig.invalidtime}")
private String INVALID_TIME;
@Value("${smsconfig.phone-prefix}")
private String PHONE_PREFIX;
@Override
public void sendSmsCode(SendSmsDto sendSmsDto) {
// 可以在发送验证码之前对当前手机号做一些验证,如该手机号是否注册过
// 为了防止短信轰炸可以根据业务需求在此做一些限制
String code = SmsUtil.getCode();
try {
ArrayList<String> params = new ArrayList<>();
params.add(code);
params.add(INVALID_TIME);
SmsSingleSenderResult senderResult = smsSingleSender
.sendWithParam("86", sendSmsDto.getMobile(),
TEMPLATE_ID, params, SMS_SIGN, "", "");
int statusCode = senderResult.result;
String statusMsg = senderResult.errMsg;
log.info("发送短信,腾讯云返回状态码:" + statusCode);
log.info("发送短信,腾讯云返回信息:" + statusMsg);
// 过于频繁
if (Constants.SEND_SMS_CODE_FREQUENT == statusCode) {
throw new SmsException(R.USER_LOGIN_ERROR3, "");
}
// 达到上限
if (Constants.SEND_SMS_CODE_UPPER == statusCode) {
throw new SmsException(R.USER_CODE_TOOMANY, "");
}
if (Constants.SEND_SMS_CODE_SUCCESS != statusCode) {
throw new SmsException(R.sms_send_error, "");
}
if (!redisUtil.setCacheObject(SmsUtil.map.get(sendSmsDto.getType()) + sendSmsDto.getMobile(),
code, 60 * Integer.parseInt(INVALID_TIME))) {
throw new SmsException(R.sms_send_error, "");
}
} catch (Exception e) {
throw new SmsException(R.sms_send_error, "");
}
}
@Override
public void verifyCode(VerifyCodeDto verifyCodeDto) {
String redisCode = (String) redisUtil.getCacheObject(SmsUtil.map
.get(verifyCodeDto.getType()) + verifyCodeDto.getMobile());
AssertUtil.isNull(redisCode, R.USER_LOGIN_ERROR4);
if (redisCode.equals(verifyCodeDto.getCode())) {
redisUtil.delete(SmsUtil.map.get(verifyCodeDto.getType()) + verifyCodeDto.getMobile());
} else {
throw new SmsException(R.USER_CODE_ERROR, "");
}
}
}
文章中只展示了关键部分代码,需要详细代码,请clone该仓库:SpringBoot集成腾讯云短信服务
功能测试阶段
这里使用Postman对接口进行测试。
首先测试的是短信验证码发送接口:
根据接口及参数设置,这里使用post请求方式,需要传入手机号和短信验证码类型两个参数。测试请求成功。
发送成功,手机接收到验证码:
接下来我们测试校验验证码接口:
根据接口及参数设置,这里使用post请求方式,需要传入手机号,接收到的短信验证码以及短信验证码的类型三个参数,验证成功。
至此短信服务已经整合完毕,可以在发送短信前或后根据自己的业务需求做一些相应的处理。
最后奉上详细的代码的git地址:https://gitee.com/junweiw/tx_send_sms.git