大家春节好!我是程序员阿福,今天过年的日子祝大家在新的一年里健康平安、步步高升、虎年大吉大利、财源滚滚! 今天分享一篇简短一点的文章,希望在将来工作中需要的时候能够用得到,如果将来工作中需要实现短信验证码功能时可以打开我的公众号并翻到这篇文章再仔细参考我的实现思路,那么笔者分享这篇文章的用意也就达到了。
前言几乎每一个新项目中都会涉及到手机验证码的动能,用户登录采用手机验证码登录方式、用户忘记密码需要密码修改密码时以及用户进行支付确认时也需要用到手机验证码。可以说手机验证码在各种项目中用的非常多,因此在我们的项目中集成一个短信通知服务是非常有必要的。
笔者为啥选择了腾讯云短信服务?市面上的短信服务其实是非常多的,包括阿里云短信服务、七牛云短信服务一起其他各大短信服务厂商等等。一是因为笔者平时买的腾讯云产品比较多,包括我的云服务器也是买的腾讯云产品,对腾讯云的产品比较熟悉,用起来也容易上手;二是发现腾讯云的产品相比较阿里的产品要更便宜些,购买金额的门槛也要低一些,50元就可以购买1000条短信服务,而阿里的短信服务购买金额门槛要100元以上。对于个人开发者而言1000条短信服务以及足够了。最后就是发现腾讯云短信服务的SDK API简单易用,各个版本客户端语言的示例都非常详细,跟着示例一步一步来很容易就能实现自己的需求。下面废话不多说,直接介绍在我们的项目集成短信通知服务的详细步骤与演示代码。
腾讯云短信服务SDKSDK 3.0是云API 3.0平台的配套工具,您可以通过SDK使用所有 [短信 API](https://cloud.tencent.com/document/product/382/52077)。新版SDK实现了统一化,具有各个语言版本的SDK` 使用方法相同,接口调用方式相同,错误码相同以及返回包格式相同等优点。
前提条件已开通短信服务,具体操作请参见 国内短信快速入门。如需发送国内短信,需要先 购买国内短信套餐包。已准备依赖环境:JDK 7 及以上版本。已在访问管理控制台 >API密钥管理页面获取 SecretID 和 SecretKey。
SecretID 用于标识 API 调用者的身份。SecretKey 用于加密签名字符串和服务器端验证签名字符串的密钥,SecretKey 需妥善保管,避免泄露。 短信的调用地址为sms.tencentcloudapi.com。 相关资料
各个接口及其参数的详细介绍请参见 API 文档。下载 SDK 源码请访问 [Java SDK 源码]( 安装 SDK 通过Maven安装
Maven 是 Java 的依赖管理工具,支持您项目所需的依赖项,并将其安装到项目中。
1 访问 Maven 官网 下载对应系统 Maven 安装包进行安装
2 添加 Maven 依赖项,只需在 Maven pom.xml添加以下依赖项即可:
com.tencentcloudapi tencentcloud-sdk-java 3.1.270
注意事项:
1 版本号仅为示例,请在 Maven 仓库 获取最新的版本号并替换
2 Maven 仓库中显示的 4.0.11 是废弃版本,由于 Maven 索引更新问题尚未完全删除
通过源码包安装1 下载 源码压缩包
2 解压源码包到您项目中合适的位置
3 将 vendor 目录下的 jar 包放在 Java 可找到的路径中
4 引用方法可参考 示例代码
示例代码说明:所有示例代码仅作参考,无法直接编译和运行,需根据实际情况进行修改,您也可以根据实际需求使用 API 3.0 Explorer 自动化生成 Demo 代码。
每个接口都有一个对应的 Request 结构和一个 Response 结构。本文仅列举几个常用功能的示例代码,如下所示。
这里我们只展示发送短信的示例代码
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
//导入可选配置类
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
// 导入对应SMS模块的client
import com.tencentcloudapi.sms.v20210111.SmsClient;
// 导入要请求接口对应的request response类
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
public class SendSms
{
public static void main(String[] args)
{
try {
Credential cred = new Credential("secretId", "secretKey");
// 实例化一个http选项,可选,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
// 设置代理
// httpProfile.setProxyHost("真实代理ip");
// httpProfile.setProxyPort(真实代理端口);
httpProfile.setReqMethod("POST");
httpProfile.setConnTimeout(60);
httpProfile.setEndpoint("sms.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
SendSmsRequest req = new SendSmsRequest();
String sdkAppId = "1400009099";
req.setSmsSdkAppId(sdkAppId);
String signName = "签名内容";
req.setSignName(signName);
String senderid = "";
req.setSenderId(senderid);
String sessionContext = "xxx";
req.setSessionContext(sessionContext);
String extendCode = "";
req.setExtendCode(extendCode);
String templateId = "400000";
req.setTemplateId(templateId);
String[] phoneNumberSet = {"+8621212313123", "+8612345678902", "+8612345678903"};
req.setPhoneNumberSet(phoneNumberSet);
String[] templateParamSet = {"5678"};
req.setTemplateParamSet(templateParamSet);
SendSmsResponse res = client.SendSms(req);
// 输出json格式的字符串回包
System.out.println(SendSmsResponse.toJsonString(res));
// 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
System.out.println(res.getRequestId());
} catch (TencentCloudSDKException e) {
e.printStackTrace();
}
}
}
SpringBoot项目中集成短信服务
笔者的spring-boot项目用的是2.2.7.RELEASE版本,是之前作者【江南一点雨】开源的一个spring-boot项目叫blog-server。笔者在这个开源项目的基础上进行了二次开发。手机验证码一般具有一定的时效性,过期后就会失效。我们可以借助redis缓存来存储短信验证码,并设置过期时间。等到服务端需要对用户请求里带上的验证码进行核对时就直接从redis缓存里面取就行了,redis的客户端我们用的是jedis。因此我们在集成腾讯云短信服务SDK的同时还要集成redis服务。只需要在项目的pom.xml文件dependencies标签中加入下面三项依赖项即可:
创建短信签名和短信模板com.tencentcloudapi tencentcloud-sdk-java 3.1.222 org.springframework.boot spring-boot-starter-data-redis io.lettuce lettuce-core redis.clients jedis 3.1.0
登录腾讯云控制台后进入国内短信->短信签名管理页面
点击【创建签名】按钮创建短信签名,进入创建签名页面,选择签名用途、签名类型、证明类型、填写签名内容和申请说明,并上传证明。签名内容有一定的限制:长度为2~12字,由中英文、数字组成,内容不包含【】。
签名用途有两种:自用或他用,默认为自用;签名类型有4种,分别是网站、App、公众号和小程序,每种签名类型上传的证明类型与其签名类型一一对应。腾讯云控制台短信签名管理页面都有详细的提示,按照提示上传对应的证明类型截图即可;申请说明填写短信用途即可。填写好之后点击【确定】按钮,等待腾讯云后台审批通过之后才可使用,审批时间一般需要2个小时。
进入短信->正文模板管理点击【创建正文模板】按钮进入创建正文模板界面编辑正文模板
模板名称:自定义;短信类型:个人选择普通类型,营销类型需要企业认证的账户才可以启用;短信内容可以点击使用标准模板,选好后点击右边操作列下的蓝色字体【使用】即可;申请说明:根据申请用途自定义
填写好模板名称和短信内容及申请说明后点击确定会生成模板ID,在正文模板管理页面可以看到,这个模拟ID后面会用到,模板ID为短信模板ID列对应的数字。注意:短信模板需要在状态为已通过之后才可使用。
下面项目中笔者使用之前审核通过的短信签名和短信模板ID
blog.sms.secretId=<你的腾讯云secretId> blog.sms.secretKey=<你的腾讯云secretKey> blog.sms.appid=<你的腾讯云appid> blog.sms.signName=<短信签名内容> blog.sms.endpoint=sms.tencentcloudapi.com blog.sms.region=<服务器所在区域,广州为:ap-guangzhou>新建配置信息类SmsPropperties
@Configuration
@ConfigurationProperties(prefix = "blog.sms")
public class SmsProperty {
private String secretId;
private String secretKey;
private String appid;
private String signName;
private String endpoint;
private String region;
// 省略setter、getter方法
}
启用配置属性类需要在pom.xml文件中添加spring-boot-configuration-processor的依赖
org.springframework.boot spring-boot-configuration-processor true
同时在启动类上加上@EnableConfigurationProperties注解
@SpringBootApplication
@EnableScheduling//开启定时任务支持
@EnableConfigurationProperties
@MapperScan(basePackages={"org.sang.mapper"},annotationClass = Repository.class)
public class BlogserverApplication {
public static void main(String[] args) {
SpringApplication.run(BlogserverApplication.class, args);
}
}
配置短信发送SmsClient类bean
新建SmsConfig配置类添加SmsClient类bean, 参照发送短信SDK API完成
@Configuration
public class SmsConfig {
@Resource
private SmsProperty smsProperty;
@Bean
public SmsClient smsClient() {
Credential cred = new Credential(smsProperty.getSecretId(), smsProperty.getSecretKey());
// 实例化一个 http 选项,可选,无特殊需求时可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setReqMethod("POST");
httpProfile.setConnTimeout(60);
httpProfile.setEndpoint(smsProperty.getEndpoint());
ClientProfile clientProfile = new ClientProfile();
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
SmsClient client = new SmsClient(cred, smsProperty.getRegion(),clientProfile);
return client;
}
}
新建短信服务类
新建SmsService类,并在该类中完成生成随机码、参照SDK发送短信API文档组装发送短信请求参数,调用SmsClient类bean完成发送短信和RedisTemplate类bean完成手机验证码限时存储。
@Service
public class SmsService {
private static final Logger logger = LoggerFactory.getLogger(SmsService.class);
@Resource
private SmsProperty smsProperty;
@Resource
private SmsClient smsClient;
@Resource
private RedisTemplate redisTemplate;
public SendSmsResponse sendLoginVeryCodeMessage(String phoneNum) {
logger.info("secretId={}, secretKey={}", smsProperty.getSecretId(), smsProperty.getSecretKey());
SendSmsRequest req = new SendSmsRequest();
req.setSenderId(null);
req.setSessionContext(null);
// 因从配置属性中获取中文内容出现乱码改为在代码中把签名内容写死
req.setSign("阿福谈Java技术栈");
req.setSmsSdkAppid(smsProperty.getAppid());
req.setTemplateID(SmsEnum.PHONE_CODE_LOGIN.getTemplateId());
req.setPhoneNumberSet(new String[]{phoneNum});
String verifyCode = getCode();
String[] params = new String[]{verifyCode, "10"};
req.setTemplateParamSet(params);
logger.info("req={}", JSON.toJSONString(req));
try {
SendSmsResponse res = smsClient.SendSms(req);
if ("Ok".equals(res.getSendStatusSet()[0].getCode())) {
// 发送短信验证码成功则将验证码保存到redis缓存中
redisTemplate.opsForValue().set("loginVerifyCode:"+phoneNum, verifyCode, 10, TimeUnit.MINUTES);
}
return res;
} catch (TencentCloudSDKException e) {
logger.error("send message failed", e);
throw new RuntimeException("send message failed, caused by " + e.getMessage());
}
}
private String getCode() {
String numbers = "1234567890";
StringBuilder builder = new StringBuilder();
Random random = new Random();
for(int i=0; i<6; i++) {
int index = random.nextInt(10);
builder.append(numbers.charAt(index));
}
return builder.toString();
}
}
完成发送短信验证码控制器方法
在UserController类中添加发送短信验证码方法
@Resource
private SmsService smsService;
@RequestMapping(value="sendLoginVerifyCode", method = RequestMethod.POST)
@ApiOperation(value = "sendLoginVerifyCode", notes = "发送登录短信验证码")
@ApiImplicitParam(name="paramMap", value = "入参Map", required = true, paramType = "body", dataTypeClass=HashMap.class)
public RespBean
测试发送短信验证码效果
为方便测试,在启动项目测试发送短信验证码接口前我们需要在spring-security配置类WebSecurityConfig中放开对这个接口的拦截
@Override
protected void configure(HttpSecurity http) throws Exception {
// 配置跨域
http.cors().configurationSource(corsConfigurationSource());
// 禁用spring security框架的退出登录,使用自定义退出登录
http.logout().disable();
http.authorizeRequests()
.antMatchers("/user/reg").anonymous()
.antMatchers("/sendLoginVerifyCode").anonymous()
//......省略其他代码
}
启动项目后在postman中测试发送短信验证码接口
POST http://localhost:8081/blog/sendLoginVerifyCode
{
"phoneNumber": "+86-18682244076"
}
注意发送国内短信时,手机号码参数前需要加上+86代表地区为中国大陆
点击postman右上角的Send按钮响应信息如下, data中的code字段为OK代表发送成功
{
"status": 200,
"msg": "success",
"data": {
"code": "Ok",
"phoneNumber": "+8618682244076",
"fee": 1,
"message": "send success"
}
}
手机号码18682244076的手机上也收到了验证码信息:
好了,本文就分享到这里了。本文源码已上传到gitee代码仓库,仓库地址:
https://gitee.com/heshengfu1211/blogserver.git
更多有关实现短信功能的使用示例大家可以移步到腾讯云短信服务SDK中心
查看。最后祝所有读者朋友们都过个红红火火、开开心心的大年!
本文首发个人微信公众号【阿福谈Web编程】,欢迎CSDN上的读者加个微信公众号关注,让我们一起在技术的路上前行不孤独!
下面给腾讯云的新春钜惠活动产品做个推广,有需要购买相关腾讯云产品的朋友可以通过下面的链接下单
【腾讯云】代金券、域名提前享,更多爆品、新春好礼2月中旬开启,敬请期待!
【腾讯云】热门云产品首单特惠秒杀,1核2G云服务器首年38元
【腾讯云】境外1核2G服务器低至2折,半价续费券限量免费领取!
【腾讯云】星星海SA2云服务器,1核2G首年99元起,高性价比首选
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
【腾讯云】中小企业福利专场,多款刚需产品,满足企业通用场景需求,云服务器2.5折起
【腾讯云】云开发Cloudbase,一站式高效开发平台,新用户选购低至0元
【腾讯云】ElasticSearch新用户特惠,快速实现日志分析、应用搜索,首购低至4折
【腾讯云】腾讯云数据库性能卓越稳定可靠,为您解决数据库运维难题
【腾讯云】腾讯云图,像PPT一样简单的数据可视化工具。5元搞定数据可视化,模板丰富,拖拖拽拽就能做出好看的可视化大屏。
【腾讯云】视频通信爆款 9.9 元起, 提供电商、教育、社交娱乐等多行业多场景的一站式解决方案,最快 1 天布局火爆赛道
【腾讯云】即时通信 IM 首购 1 折特惠,仅需99.9元/月,支持直播电商、在线教育等多种热门应用场景
【腾讯云】9.9元体验2万分钟实时音视频通话,支持1对1或多人音视频通话,单房可支持300人同时在线,10万人同时观看;全平台互通高品质通话
【腾讯云】云数据库MySQL基础版1元体验,为中小企业量身打造,单节点架构,保证数据可靠性
【腾讯云】专业版APP加固特惠5折起,可享免费兼容性测试
【腾讯云】新客户首购 TPNS 特惠9.8元/万 DAU,新老客户低至6.5折,给您提供快速、稳定、安全、高效的用户促活利器



