SpringBoot2.x 集成騰訊云短信的詳細流程
一、騰訊云短信簡介
騰訊云短信(Short Message Service,SMS)沉淀騰訊十多年短信服務(wù)技術(shù)和經(jīng)驗,為QQ、微信等億級平臺和10萬+客戶提供快速靈活接入的高質(zhì)量的國內(nèi)短信與國際/港澳臺短信服務(wù)。
- 國內(nèi)短信驗證秒級觸達,99%到達率。
- 國際/港澳臺短信覆蓋全球200+國家/地區(qū),穩(wěn)定可靠。
單次短信的業(yè)務(wù)請求流程如下所示:

短信由簽名和正文內(nèi)容組成,發(fā)送短信前需要申請短信簽名和正文內(nèi)容模板。短信簽名是位于短信正文前【】中的署名,用于標識公司或業(yè)務(wù)。短信簽名需要審核通過后才可使用。短信模板即具體發(fā)送的短信正文內(nèi)容,短信模板支持驗證碼模板、通知類短信模板和營銷短信模板。短信內(nèi)容可以通過模板參數(shù)實現(xiàn)個性化定制。短信模板申請前需要先申請短信簽名,短信模板需要審核通過后才可使用。
二、準備工作
1.開通短信服務(wù)
如果沒有騰訊云賬號,需要注冊騰訊云賬號,并完成實名認證,可以個人認證和企業(yè)認證,不能進行企業(yè)認證的話也可以進行個人認證。然后進入騰訊云短信控制臺,開通短信服務(wù),開通短信和個人認證之后分別都會贈送包含100條短信的國內(nèi)套餐包,用來測試足夠:

2.創(chuàng)建簽名
這里創(chuàng)建國內(nèi)短信簽名,創(chuàng)建完成后等到狀態(tài)變?yōu)橐淹ㄟ^就可以使用了:

創(chuàng)建簽名時簽名類型可以選網(wǎng)站、APP、公眾號和小程序,可以根據(jù)需要創(chuàng)建:

3.創(chuàng)建正文模板
創(chuàng)建模板,創(chuàng)建完成之后狀態(tài)變?yōu)橐淹ㄟ^就可以使用了:

模板內(nèi)容可以使用標準模板也可以自定義:

4.創(chuàng)建短信應(yīng)用
在應(yīng)用列表下可以創(chuàng)建短信應(yīng)用,獲取短信應(yīng)用的SDKAppID:

點擊應(yīng)用可以查看應(yīng)用信息:

5.騰訊云API密鑰
在訪問管理菜單的訪問密鑰下的API密鑰管理中可以新建和查看API密鑰,在請求騰訊云短信服務(wù)發(fā)送短信時需要傳入該密鑰:

三、集成騰訊云短信
通過Maven新建一個名為springboot-tencent-sms的項目。
1.引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 騰訊云 Java SDK 依賴 -->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.297</version>
</dependency>
<!-- Spring Data Redis 起步依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
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;
/**
* 短信應(yīng)用的SDKAppID
*/
private String appId;
/**
* 簽名內(nèi)容
*/
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<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}
/**
* 設(shè)置數(shù)據(jù)存入redis的序列化方式
*
* @param redisTemplate RedisTemplate對象
* @param factory RedisConnectionFactory對象
*/
private void initRedisTemplate(RedisTemplate<String, Object> 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
# 配置短信應(yīng)用的SDKAppID
appId: 這里填短信應(yīng)用的SDKAppID
# 配置簽名內(nèi)容
sign: "這里填簽名內(nèi)容"
# 配置模板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);
/**
* 發(fā)送短信
*
* @param smsConfig 騰訊云短信配置對象
* @param templateParams 模板參數(shù)
* @param phoneNumbers 手機號數(shù)組
* @return SendStatus[],短信發(fā)送狀態(tài)
*/
public static SendStatus[] sendSms(SmsConfig smsConfig, String[] templateParams, String[] phoneNumbers) {
try {
// 實例化一個認證對象,入?yún)⑿枰獋魅腧v訊云賬戶密鑰對secretId,secretKey。
Credential cred = new Credential(smsConfig.getSecretId(), smsConfig.getSecretKey());
// 實例化一個http選項,可選,沒有特殊需求可以跳過
HttpProfile httpProfile = new HttpProfile();
// SDK默認使用POST方法
httpProfile.setReqMethod("POST");
// SDK有默認的超時時間,非必要請不要進行調(diào)整
httpProfile.setConnTimeout(60);
// 非必要步驟:實例化一個客戶端配置對象,可以指定超時時間等配置
ClientProfile clientProfile = new ClientProfile();
// SDK默認用TC3-HMAC-SHA256進行簽名,非必要請不要修改這個字段
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
// 實例化要請求產(chǎn)品(以sms為例)的client對象,第二個參數(shù)是地域信息,可以直接填寫字符串a(chǎn)p-guangzhou,或者引用預(yù)設(shè)的常量
SmsClient smsClient = new SmsClient(cred, "ap-guangzhou", clientProfile);
// 實例化一個請求對象
SendSmsRequest req = new SendSmsRequest();
// 設(shè)置短信應(yīng)用ID:短信SdkAppId在[短信控制臺]添加應(yīng)用后生成的實際SdkAppId
req.setSmsSdkAppId(smsConfig.getAppId());
// 設(shè)置短信簽名內(nèi)容:使用UTF-8編碼,必須填寫已審核通過的簽名,簽名信息可登錄[短信控制臺]查看
req.setSignName(smsConfig.getSign());
// 設(shè)置國際/港澳臺短信SenderId:國內(nèi)短信填空,默認未開通
req.setSenderId("");
// 設(shè)置模板ID:必須填寫已審核通過的模板ID。模板ID可登錄[短信控制臺]查看
req.setTemplateId(smsConfig.getTemplateId());
// 設(shè)置下發(fā)手機號碼,采用E.164標準,+[國家或地區(qū)碼][手機號]
req.setPhoneNumberSet(phoneNumbers);
// 設(shè)置模板參數(shù):若無模板參數(shù),則設(shè)置為空
req.setTemplateParamSet(templateParams);
// 通過client對象調(diào)用SendSms方法發(fā)起請求。注意請求方法名與請求對象是對應(yīng)的,返回的res是一個SendSmsResponse類的實例,與請求對象對應(yīng)
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 com.rtxtitanv.util.RedisUtil
* @description Redis工具類
* @date 2021/6/26 12:24
*/
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> 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);
}
/**
* 創(chuàng)建緩存的鍵
*
* @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();
/**
* 生成指定位數(shù)的隨機數(shù)字字符串
*
* @param length 字符串長度
* @return 隨機數(shù)字字符串
*/
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 com.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 {
/**
* 發(fā)送短信驗證碼
*
* @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實現(xiàn)類
* @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) {
// 下發(fā)手機號碼,采用e.164標準,+[國家或地區(qū)碼][手機號]
String[] phoneNumbers = {"+86" + phoneNumber};
// 生成6位隨機數(shù)字字符串
String smsCode = RandomUtil.randomNumbers(6);
// 模板參數(shù):若無模板參數(shù),則設(shè)置為空(參數(shù)1為隨機驗證碼,參數(shù)2為有效時間)
String[] templateParams = {smsCode, smsConfig.getExpireTime()};
// 發(fā)送短信驗證碼
SendStatus[] sendStatuses = SmsUtil.sendSms(smsConfig, templateParams, phoneNumbers);
if ("Ok".equals(sendStatuses[0].getCode())) {
// 創(chuàng)建緩存的key
String key = RedisUtil.createCacheKey(smsConfig.getPhonePrefix(), phoneNumber);
// 將驗證碼緩存到redis并設(shè)置過期時間
redisUtil.setCacheObject(key, smsCode, Long.parseLong(smsConfig.getExpireTime()));
return "驗證碼發(fā)送成功";
} else {
return "驗證碼發(fā)送失?。? + sendStatuses[0].getMessage();
}
}
@Override
public String verifySmsCode(String phoneNumber, String smsCode) {
// 創(chuàng)建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.發(fā)送短信驗證碼
發(fā)送如下POST請求以請求騰訊云短信服務(wù)向指定手機號發(fā)送短信驗證碼,請求地址為http://localhost:8080/sms/send:

Redis客戶端查看發(fā)現(xiàn)驗證碼已經(jīng)存到了Redis中:

手機上也成功收到了驗證碼,說明發(fā)送短信成功:

2.驗證短信驗證碼
發(fā)送如下POST請求驗證短信驗證碼,請求地址為http://localhost:8080/sms/verify,這里將驗證碼參數(shù)smscode設(shè)為不同于之前發(fā)送到手機的驗證碼來模擬驗證碼輸入錯誤:

再次發(fā)送如下POST請求驗證短信驗證碼,這里輸入正確的驗證碼:

Redis客戶端刷新發(fā)現(xiàn)驗證碼緩存已經(jīng)刪除:

再次發(fā)送如下POST請求驗證短信驗證碼,發(fā)現(xiàn)驗證碼已失效,滿足短信驗證碼驗證成功后就失效的業(yè)務(wù)需求:

代碼示例
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
到此這篇關(guān)于SpringBoot2.x 集成騰訊云短信的文章就介紹到這了,更多相關(guān)SpringBoot騰訊云短信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java timezone設(shè)置和mybatis連接數(shù)據(jù)庫時區(qū)設(shè)置方式
這篇文章主要介紹了Java timezone設(shè)置和mybatis連接數(shù)據(jù)庫時區(qū)設(shè)置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Java KindEditor粘貼圖片自動上傳到服務(wù)器功能實現(xiàn)
這篇文章主要介紹了Java KindEditor粘貼圖片自動上傳到服務(wù)器功能實現(xiàn),本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04
Java實現(xiàn)國產(chǎn)加密算法SM4的示例詳解
這篇文章主要為大家詳細介紹了Java如何實現(xiàn)國產(chǎn)加密算法SM4(ECB和CBC兩種模式),文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-01-01
Springboot開發(fā)之利用Docker和Kubernetes部署微服務(wù)
這篇文章主要介紹了如何將Spring Boot開發(fā)的微服務(wù)通過Docker容器化,并使用Kubernetes進行部署和管理,幫助讀者掌握現(xiàn)代云原生應(yīng)用的完整開發(fā)部署流程,有需要的可以了解下2025-03-03
Java 關(guān)鍵字 volatile 的理解與正確使用
本文主要介紹 volatile 的使用準則,以及使用過程中需注意的地方,感興趣的朋友一起看看吧2017-06-06
利用Java8 Optional類優(yōu)雅如何地解決空指針問題
這篇文章主要給大家介紹了關(guān)于如何利用Java8 Optional類優(yōu)雅解決空指針問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2020-11-11
Triple協(xié)議支持Java異?;貍髟O(shè)計實現(xiàn)詳解
這篇文章主要為大家介紹了Triple協(xié)議支持Java異常回傳設(shè)計實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
Java中將 int[] 數(shù)組 轉(zhuǎn)換為 List分享
這篇文章主要介紹了Java中將 int[] 數(shù)組 轉(zhuǎn)換為 List分享的相關(guān)資料,需要的朋友可以參考下2022-12-12
Mybatis-Plus使用saveOrUpdate及問題解決方法
本文主要介紹了Mybatis-Plus使用saveOrUpdate及問題解決方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2023-01-01

