之前介绍过阿里云短信服务,传送门:阿里云短信服务——短信发送验证码,但是由于阿里云现在短信调用门槛较高,申请有很多限制(我申请好几次都没有通过),所以只能使用测试账号给固定的手机号发送验证码,自己写项目用起来很难受,于是转向了腾讯云的短信服务,当然腾讯云通用也有门槛,你需要符合以下要求:
有自己的网站(该网站在腾讯云已显示备案,一般个人博客即可),如图:
这是唯一一个有点门槛的需求,如果你有个人博客并且自己的网站和域名也备案完成就可以使用了。(同样的条件阿里云没有给我通过审批,因为我的网站好久不用挂了,就临时用wordpress搭了一个特别简单的博客,阿里云取消审批的原因就是因为网站没有对应需求);
如果这些你符合的话推荐使用腾讯云,申请门槛相对较低,但是如果都不符合那还是使用阿里云测试账号学习吧。
腾讯云步骤写的其实比较清楚了,如图:
所以一步一步来就行了;
创建签名:
这里注意签名类型一定是备案网站的名称,不然审批不通过;
然后创建模板就很简单了,用腾讯云默认模板审批会快一点:
审核通过后就可以使用腾讯云短信sdk发送短信了;
这里推荐先看一下腾讯云文档,写的挺清楚的:
腾讯云短信java sdk官方文档
配置完成还可以在云api上进行测试,这和阿里云的测试一样非常友好:
云 api传送门
文档写的确实很详细,其实到这你就可以把对应的代码复制下来直接使用了,下面我演示一下我的使用方法;
先引入sdk依赖:
<dependency>
<groupId>com.tencentcloudapigroupId>
<artifactId>tencentcloud-sdk-java-commonartifactId>
<version>LATESTversion>
dependency>
<dependency>
<groupId>com.tencentcloudapigroupId>
<artifactId>tencentcloud-sdk-java-smsartifactId>
<version>LATESTversion>
dependency>
然后在application.yml文件中配置所需要的参数:
region我这里可选南京和广州;
sercretId和secretKey获取:https://console.cloud.tencent.com/cam/capi
endpoint:指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com(用默认就可以)
smsSdkAppId获取:https://console.cloud.tencent.com/smsv2/app-manage
signName获取:https://console.cloud.tencent.com/smsv2/csms-sign
templateId获取:https://console.cloud.tencent.com/smsv2/csms-template
expiredTime是我自定义的第二个模板参数
创建TencentSmsConstant实体类读取配置文件信息:
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 腾讯云短信验证码服务常量
*/
@Component
public class TencentSmsConstant implements InitializingBean {
@Value("${tencent.sms.region}")
private String region;
@Value("${tencent.sms.secret_id}")
private String secretId;
@Value("${tencent.sms.secret_key}")
private String secretKey;
@Value("${tencent.sms.endpoint}")
private String endpoint;
@Value("${tencent.sms.sms_sdk_app_id}")
private String smsSdkAppId;
@Value("${tencent.sms.sign_name}")
private String signName;
@Value("${tencent.sms.template_id}")
private String templateId;
@Value("${tencent.sms.expired_time}")
private String expiredTime;
public static String REGION;
public static String SECRET_ID;
public static String SECRET_KEY;
public static String ENDPOINT;
public static String SMS_SDK_APP_ID;
public static String SIGN_NAME;
public static String TEMPLATE_ID;
public static String EXPIRED_TIME;
@Override
public void afterPropertiesSet() throws Exception {
REGION = region;
SECRET_ID = secretId;
SECRET_KEY = secretKey;
ENDPOINT = endpoint;
SMS_SDK_APP_ID = smsSdkAppId;
SIGN_NAME = signName;
TEMPLATE_ID = templateId;
EXPIRED_TIME = expiredTime;
}
}
编写controller:
@PostMapping("/tencent/code/{phone}")
public BaseResponse<String> tencentSendMessageToPhone(@PathVariable String phone) {
// 校验信息
this.verifyPhoneInfo(phone);
// 如果redis没有该手机号验证码,则获取验证码并发送短信
String verifyCode = RandomUtils.getSixBitRandom(); // 获取六位验证码
Boolean isSend = smsService.tencentSendMessageToPhone(verifyCode, phone); // 调用tencent短信发送sdk
// 判断发送结果并处理(存入redis)
this.afterMessageSending(isSend, phone, verifyCode);
return ResultUtils.success("短信发送成功");
}
/**
* 校验发送验证码手机号信息
* @param phone 手机号
*/
private void verifyPhoneInfo(String phone) {
if (StringUtils.isAnyBlank(phone)) {
throw new BusinessException(StatusCode.NULL_ERROR, "手机号为空");
}
// 校验手机号
RegExpUtil.regExpVerify(RegExpUtil.phoneRegExp, phone, "手机号格式错误");
// 从redis中查看有没有该手机号的验证码
String verifyCode = (String) redisTemplate.opsForValue().get(RedisKey.SMS_LOGIN_CODE + phone);
if (!StringUtils.isAnyBlank(verifyCode)) {
throw new BusinessException(StatusCode.SUCCESS, "验证码已发送=>" + verifyCode);
}
}
/**
* 判断发送结果并处理
* @param isSend 发送结果
* @param phone 发送手机号
* @param verifyCode 验证码
*/
private void afterMessageSending(Boolean isSend, String phone, String verifyCode) {
if (isSend) { // 如果发送成功,则将对应手机号验证码存入redis中,设置规定时间内有效
redisTemplate.opsForValue().set(
RedisKey.SMS_LOGIN_CODE + phone,
verifyCode,
MESSAGE_EXPIRED_TIME,
TimeUnit.MINUTES);
} else {
throw new BusinessException(StatusCode.SYSTEM_ERROR, "短信发送失败");
}
}
controller逻辑可以参考阿里云短信的那篇文章,这里都一样,当然这里省略了60秒内可以重复发送、发送频率限制等操作,这些网上都可以搜到,一般也是用redis实现的;
✨service层具体调用sdk方法:
这里才是调用sdk的关键逻辑代码
public Boolean tencentSendMessageToPhone(String verifyCode, String phone) {
try{
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
Credential cred = new Credential(TencentSmsConstant.SECRET_ID, TencentSmsConstant.SECRET_KEY);
// 实例化一个http选项
HttpProfile httpProfile = new HttpProfile();
// 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com
httpProfile.setEndpoint(TencentSmsConstant.ENDPOINT);
// 实例化一个client选项
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
SmsClient client = new SmsClient(cred, TencentSmsConstant.REGION, clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
com.tencentcloudapi.sms.v20210111.models.SendSmsRequest req =
new com.tencentcloudapi.sms.v20210111.models.SendSmsRequest();
// 设置发送短信的手机号(可以一次多个:{"18539344270", "13073775668"})
String[] phoneNumberSet1 = {phone};
req.setPhoneNumberSet(phoneNumberSet1);
// 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId
req.setSmsSdkAppId(TencentSmsConstant.SMS_SDK_APP_ID);
// 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名
req.setSignName(TencentSmsConstant.SIGN_NAME);
// 模板 ID: 必须填写已审核通过的模板 ID
req.setTemplateId(TencentSmsConstant.TEMPLATE_ID);
// 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空
// 我这里设置第一个参数为验证码,第二个为验证码超时时间
String[] templateParamSet1 = {verifyCode, TencentSmsConstant.EXPIRED_TIME};
req.setTemplateParamSet(templateParamSet1);
// 返回的resp是一个SendSmsResponse的实例,与请求对象对应
com.tencentcloudapi.sms.v20210111.models.SendSmsResponse resp = client.SendSms(req);
// 输出json格式的字符串回包
log.info(com.tencentcloudapi.sms.v20210111.models.SendSmsResponse.toJsonString(resp));
// 因为该需求是给一个手机号发送,发送结果是每个手机号的信息发送响应封装类(SendStatus)的数组,所以只需要该数组第一个参数即可
return resp.getSendStatusSet()[0].getCode().equals(TENCENT_SMS_SUCCESS_CODE);
} catch (TencentCloudSDKException e) {
log.info(e.toString());
}
return false;
}
注释比较清楚了,就不多说了。
测试一下:
redis中存储:
发送的短信:
测试功能完成。
最近做验证码登录时又重新回顾了一下这些内容,也发现了之前我忽略的一些细节,比如频率限制等,后期如果有机会再补上;
对于腾讯云和阿里云两个短信平台的测试都需要充点钱才能发短信,几块钱就行,腾讯云能免费领100次短信,当然短信平台不止这两家,还有很多可以使用,感兴趣可以自行搜索;