SpringBoot2.x 集成腾讯云短信的详细流程

网友投稿 221 2023-01-02

SpringBoot2.x 集成腾讯云短信的详细流程

一、腾讯云短信简介

腾讯云短信(Short Message Service,SMS)沉淀腾讯十多年短信服务技术和经验,为QQ、微信等亿级平台和10万+客户提供快速灵活接入的高质量的国内短信与国际/港澳台短信服务。

国内短信验证秒级触达,99%到达率。

国际/港澳台短信覆盖全球200+国家/地区,稳定可靠。

单次短信的业务请求流程如下所示:

短信由签名和正文内容组成,发送短信前需要申请短信签名和正文内容模板。短信签名是位于短信正文前【】中的署名,用于标识公司或业务。短信签名需要审核通过后才可使用。短信模板即具体发送的短信正文内容,短信模板支持验证码模板、通知类短信模板和营销短信模板。短信内容可以通过模板参数实现个性化定制。短信模板申请前需要先申请短信签名,短信模板需要审核通过后才可使用。

二、准备工作

1.开通短信服务

如果没有腾讯云账号,需要注册腾讯云账号,并完成实名认证,可以个人认证和企业认证,不能进行企业认证的话也可以进行个人认证。然后进入腾讯云短信控制台,开通短信服务,开通短信和个人认证之后分别都会赠送包含100条短信的国内套餐包,用来测试足够:

2.创建签名

这里创建国内短信签名,创建完成后等到状态变为已通过就可以使用了:

3.创建正文模板

创建模板,创建完成之后状态变为已通过就可以使用了:

模板内容可以使用标准模板也可以自定义:

4.创建短信应用

在应用列表下可以创建短信应用,获取短信应用的SDKAppID:

点击应用可以查看应用信息:

5.腾讯云API密钥

在访问管理菜单的访问密钥下的API密钥管理中可以新建和查看API密钥,在请求腾讯云短信服务发送短信时需要传入该密钥:

三、集成腾讯云短信

通过Maven新建一个名为springboot-tencent-sms的项目。

1.引入依赖

org.springframework.boot

spring-boot-starter-web

com.tencentcloudapi

tencentcloud-sdk-java

3.1.297

org.springframework.boot

spring-boot-starter-data-redis

org.projectlombok

lombok

1.18.8

2.编写配置类

用于读取配置文件中的自定义腾讯云短信配置的配置类:

package com.rtxtitanv.config;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Configuration;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.config.SmsConfig

* @description 腾讯云短信配置类

* @date 2021/6/25 16:21

*/

@ConfigurationProperties(prefix = "tencent.sms")

@Configuration

@Data

public class SmsConfig {

/**

* 腾讯云API密钥的SecretId

*/

private String secretId;

/**

* 腾讯云API密钥的SecretKey

*/

private String secretKey;

/**

* 短信应用的SDKAppID

*/

private String appId;

/**

* 签名内容

*/

private String sign;

/**

* 模板ID

*/

private String templateId;

/**

* 过期时间

*/

private String expireTime;

/**

* redis存储的key的前缀

*/

private String phonePrefix;

}

Redis配置类:

package com.rtxtitanv.config;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.serializer.GenericJackson2jsonRedisSerializer;

import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.Resource;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.config.RedisConfig

* @description Redis配置类

* @date 2021/6/26 12:24

*/

@Configuration

public class RedisConfig {

@Resource

private RedisConnectionFactory redisConnectionFactory;

/**

* RedisTemplate实例

*

* @return RedisTemplate实例

*/

@Bean

public RedisTemplate redisTemplate() {

RedisTemplate redisTemplate = new RedisTemplate<>();

initRedisTemplate(redisTemplate, redisConnectionFactory);

return redisTemplate;

}

/**

* 设置数据存入redis的序列化方式

*

* @param redisTemplate RedisTemplate对象

* @param factory RedisConnectionFactory对象

*/

private void initRedisTemplate(RedisTemplate redisTemplate, RedisConnectionFactory factory) {

redisTemplate.setKeySerializer(new StringRedisSerializer());

redisTemplate.setValueSerializer(new StringRedisSerializer());

redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());

redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

redisTemplate.setConnectionFactory(factory);

}

}

3.编写配置文件

spring:

redis:

host: 127.0.0.1

port: 6379

# 自定义腾讯云短信配置

tencent:

sms:

# 配置腾讯云API密钥的SecretId

secretId: 这里填腾讯云API密钥的SecretId

# 配置腾讯云API密钥的SecretKey

secretKey: 这里填腾讯云API密钥的SecretKey

# 配置短信应用的SDKAppID

appId: 这里填短信应用的SDKAppID

# 配置签名内容

sign: "这里填签名内容"

# 配置模板ID

templateId: 这里填模板ID

# 配置过期时间

expireTime: 5

# 配置redis存储的key的前缀

phonePrefix: REGIST

4.编写工具类

腾讯云短信工具类:

package com.rtxtitanv.util;

import com.rtxtitanv.config.SmsConfig;

import com.tencentcloudapi.common.Credential;

import com.tencentcloudapi.common.exception.TencentCloudSDKException;

import com.tencentcloudapi.common.profile.ClientProfile;

import com.tencentcloudapi.common.profile.HttpProfile;

import com.tencentcloudapi.sms.v20210111.SmsClient;

import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;

import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;

import com.tencentcloudapi.sms.v20210111.models.SendStatus;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.util.SmsUtil

* @description 腾讯云短信工具类

* @date 2021/6/25 16:21

*/

public class SmsUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(SmsUtil.class);

/**

* 发送短信

*

* @param smsConfig 腾讯云短信配置对象

* @param templateParams 模板参数

* @param phoneNumbers 手机号数组

* @return SendStatus[],短信发送状态

*/

public static SendStatus[] sendSms(SmsConfig smsConfig, String[] templateParams, String[] phoneNumbers) {

try {

// 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。

Credential cred = new Credential(smsConfig.getSecretId(), smsConfig.getSecretKey());

// 实例化一个http选项,可选,没有特殊需求可以跳过

HttpProfile httpProfile = new HttpProfile();

// SDK默认使用POST方法

httpProfile.setReqMethod("POST");

// SDK有默认的超时时间,非必要请不要进行调整

httpProfile.setConnTimeout(60);

// 非必要步骤:实例化一个客户端配置对象,可以指定超时时间等配置

ClientProfile clientProfile = new ClientProfile();

// SDK默认用TC3-HMAC-SHA256进行签名,非必要请不要修改这个字段

clientProfile.setSignMethod("HmacSHA256");

clientProfile.setHttpProfile(httpProfile);

// 实例化要请求产品(以sms为例)的client对象,第二个参数是地域信息,可以直接填写字符串ap-guangzhou,或者引用预设的常量

SmsClient smsClient = new SmsClient(cred, "ap-guangzhou", clientProfile);

// 实例化一个请求对象

SendSmsRequest req = new SendSmsRequest();

// 设置短信应用ID:短信SdkAppId在[短信控制台]添加应用后生成的实际SdkAppId

req.setSmsSdkAppId(smsConfig.getAppId());

// 设置短信签名内容:使用UTF-8编码,必须填写已审核通过的签名,签名信息可登录[短信控制台]查看

req.setSignName(smsConfig.getSign());

// 设置国际/港澳台短信SenderId:国内短信填空,默认未开通

req.setSenderId("");

// 设置模板ID:必须填写已审核通过的模板ID。模板ID可登录[短信控制台]查看

req.setTemplateId(smsConfig.getTemplateId());

// 设置下发手机号码,采用E.164标准,+[国家或地区码][手机号]

req.setPhoneNumberSet(phoneNumbers);

// 设置模板参数:若无模板参数,则设置为空

req.setTemplateParamSet(templateParams);

// 通过client对象调用SendSms方法发起请求。注意请求方法名与请求对象是对应的,返回的res是一个SendSmsResponse类的实例,与请求对象对应

SendSmsResponse res = smsClient.SendSms(req);

// 控制台打印日志输出json格式的字符串回包

LOGGER.info(SendSmsResponse.toJsonString(res));

return res.getSendStatusSet();

} catch (TencentCloudSDKException e) {

e.printStackTrace();

throw new RuntimeException(e.getMessage());

}

}

}

Redis工具类:

package com.rtxtitanv.util;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.concurrent.TimeUnit;

/**

* @author rtxtitanv

* @version 1.0.0

* @name comhttp://.rtxtitanv.util.RedisUtil

* @description Redis工具类

* @date 2021/6/26 12:24

*/

@Component

public class RedisUtil {

@Resource

private RedisTemplate redisTemplate;

/**

* 缓存基本对象

*

* @param key 键

* @param value 值

* @param expire 键的过期时间

*/

public void setCacheObject(String key, Object value, long expire) {

redisTemplate.opsForValue().set(key, value);

if (expire > 0) {

redisTemplate.expire(key, expire, TimeUnit.MINUTES);

}

}

/**

* 获取指定键的缓存对象

*

* @param key 键

* @return 缓存对象

*/

public Object getCacheObject(String key) {

return redisTemplate.opsForValue().get(key);

}

/**

* 判断键是否存在并且未过期

*

* @param key 键

* @return true,键存在并且未过期;false,键不存在或存在但过期

*/

public boolean hasKey(String key) {

return redisTemplate.hasKey(key) && getExpire(key) > 0 ? true : false;

}

/**

* 获取键的过期时间

*

* @param key 键

* @return 过期时间

*/

public long getExpire(String key) {

return redisTemplate.getExpire(key, TimeUnit.MINUTES);

}

/**

* 删除指定键的缓存

*

* @param key 键

*/

public void delete(String key) {

redisTemplate.delete(key);

}

/**

* 创建缓存的键

*

* @param prefix 前缀

* @param phoneNumber 手机号

* @return 键

*/

public static String createCacheKey(String prefix, String phoneNumber) {

return prefix + phoneNumber;

}

}

用于生成随机验证码的工具类:

package com.rtxtitanv.util;

import java.util.Random;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.util.RandomUtil

* @description Random工具类

* @date 2021/6/26 11:39

*/

public class RandomUtil {

private static final Random RANDOM = new Random();

/**

* 生成指定位数的随机数字字符串

*

* @param length 字符串长度

* @return 随机数字字符串

*/

public static String randomNumbers(int length) {

StringBuilder randomNumbers = new StringBuilder();

for (int i = 0; i < length; i++) {

randomNumbers.append(RANDOM.nextInt(10));

}

return randomNumbers.toString();

}

}

5.Controller层

package com.rtxtitanv.controller;

import com.rtxtitanv.service.SmsService;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**

* @author rtxtitanv

* @version 1.0.0

* @name comhyUmQeYhu.rtxtitanv.controller.SmsController

* @description SmsController

* @date 2021/6/25 16:20

*/

@RequestMapping("/sms")

@RestController

public class SmsController {

@Resource

private SmsService smsService;

@PostMapping("/send")

public String sendSmsCode(@RequestParam(value = "phoneNumber") String phoneNumber) {

return smsService.sendSmsCode(phoneNumber);

}

@PostMapping("/verify")

public String verifySmsCode(@RequestParam(value = "phoneNumber") String phoneNumber,

@RequestParam(value = "smsCode") String smsCode) {

return smsService.verifySmsCode(phoneNumber, smsCode);

}

}

6.Service层

package com.rtxtitanv.service;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.service.SmsService

* @description SmsService

* @date 2021/6/25 16:20

*/

public interface SmsService {

/**

* 发送短信验证码

*

* @param phoneNumber 手机号

* @return

*/

String sendSmsCode(String phoneNumber);

/**

* 验证短信验证码

*

* @param phoneNumber 手机号

* @param smsCode 短信验证码

* @return

*/

String verifySmsCode(String phoneNumber, String smsCode);

}

package com.rtxtitanv.service.impl;

import com.rtxtitanv.config.SmsConfig;

import com.rtxtitanv.service.SmsService;

import com.rtxtitanv.util.RandomUtil;

import com.rtxtitanv.util.RedisUtil;

import com.rtxtitanv.util.SmsUtil;

import com.tencentcloudapi.sms.v20210111.models.SendStatus;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**

* @author rtxtitanv

* @version 1.0.0

* @name com.rtxtitanv.service.impl.SmsServiceImpl

* @description SmsService实现类

* @date 2021/6/25 16:20

*/

@Service

public class SmsServiceImpl implements SmsService {

@Resource

private SmsConfig smsConfig;

@Resource

private RedisUtil redisUtil;

@Override

public String sendSmsCode(String phoneNumber) {

// 下发手机号码,采用e.164标准,+[国家或地区码][手机号]

String[] phoneNumbers = {"+86" + phoneNumber};

// 生成6位随机数字字符串

String smsCode = RandomUtil.randomNumbers(6);

// 模板参数:若无模板参数,则设置为空(参数1为随机验证码,参数2为有效时间)

String[] templateParams = {smsCode, smsConfig.getExpireTime()};

// 发送短信验证码

SendStatus[] sendStatuses = SmsUtil.sendSms(smsConfig, templateParams, phoneNumbers);

if ("Ok".equals(sendStatuses[0].getCode())) {

// 创建缓存的key

String key = RedisUtil.createCacheKey(smsConfig.getPhonePrefix(), phoneNumber);

// 将验证码缓存到redis并设置过期时间

redisUtil.setCacheObject(key, smsCode, Long.parseLong(smsConfig.getExpireTime()));

return "验证码发送成功";

} else {

return "验证码发送失败:" + sendStatuses[0].getMessage();

}

}

@Override

public String verifySmsCode(String phoneNumber, String smsCode) {

// 创建key

String key = RedisUtil.createCacheKey(smsConfig.getPhonePrefix(), phoneNumber);

// 判断指定key是否存在并且未过期

if (redisUtil.hasKey(key)) {

// 验证输入的验证码是否正确

if (smsCode.equals(redisUtil.getCacheObject(key))) {

// 验证成功后删除验证码缓存

redisUtil.delete(key);

return "验证成功";

} else {

return "验证码错误";

}

} else {

return "验证码已失效";

}

}

}

四、腾讯云短信测试

运行项目,使用Postman进行接口测试。

1.发送短信验证码

发送如下POST请求以请求腾讯云短信服务向指定手机号发送短信验证码,请求地址为http://localhost:8080/sms/send:

Redis客户端查看发现验证码已经存到了Redis中:

手机上也成功收到了验证码,说明发送短信成功:

2.验证短信验证码

发送如下POST请求验证短信验证码,请求地址为http://localhost:8080/sms/verify,这里将验证码参数smscode设为不同于之前发送到手机的验证码来模拟验证码输入错误:

再次发送如下POST请求验证短信验证码,这里输入正确的验证码:

Redis客户端刷新发现验证码缓存已经删除:

再次发送如下POST请求验证短信验证码,发现验证码已失效,满足短信验证码验证成功后就失效的业务需求:

代码示例

github:https://github.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-tencent-sms

Gitee:https://gitee.com/RtxTitanV/springboot-learning/tree/master/springboot2.x-learning/springboot-tencent-sms

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:天气预报网站的api接口(天气预报网站的api接口是什么)
下一篇:SpringBoot搭建全局异常拦截
相关文章

 发表评论

暂时没有评论,来抢沙发吧~