腾讯短信+Springboot+Redis 实现短信验证注册

使用redis做缓存实现用户的注册功能:

  • 异步请求发送短信,给 发送短信的按钮 绑定异步事件
    • 调用发送短信逻辑发送短信
      • 缓存 key1:验证码
      • 缓存 key2:短信发送时刻的时间
  • 用户提交表单 包含用户的基本信息+验证码
    • 取出用户的验证码去redis中查找
      • 若不存在返回异常
      • 未过期,直接退出发短信的方法
      • 存在根据key1取出验证码,和用户提交的比对,相同继续注册,否则返回异常

主要调用腾讯短信的接口实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package com.sms.Utils;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import com.sms.properties.SmsRepository;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
* 发送短信的工具类
* @Author: Changwu
* @Date: 2019/5/25 14:00
*/
@Component
@EnableConfigurationProperties(SmsRepository.class)
public class SendSms {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
SmsRepository smsRepository;
@Autowired
StringRedisTemplate stringRedisTemplate;
private String msg;
/**
* 发送短信
* 查看redis缓存中是否存在未过期的验证码信息,
* 如果存在直接返回,拒绝发送验证码,
* 否则重新发送
* @param photoNumber
* @return 发送的验证码
*/
public String sendSms(String photoNumber){
String key=smsRepository.getPREFIX()+photoNumber;
String lastTime = stringRedisTemplate.opsForValue().get(key);
// 判断发送的时长
if (lastTime!=null){
Long aLong = Long.valueOf(lastTime);
logger.info("lastTime==="+aLong);
if (System.currentTimeMillis()-aLong<smsRepository.getExpireTime()){
logger.warn("手机号{},发送短信频率过高被拒绝..."+photoNumber);
return null;
}
}
// 生成随机数
this.msg=createRodom();
// 发送短信
String errmsg = send(photoNumber,msg);
if (!errmsg.equals("OK")){
this.msg=errmsg;
throw new RuntimeException("故意整出来的异常");
}
// 把发送短信的时间写入缓存
stringRedisTemplate.opsForValue().set(key,String.valueOf(System.currentTimeMillis()),smsRepository.getExpireTime()/1000, TimeUnit.SECONDS);

return msg;
}

/**
* 发送
* @param phone
* @param msg
*/
public String send(String phone,String msg){
SmsSingleSenderResult result =null;
try {
String time = String.valueOf(smsRepository.getExpireTime()/60000);
// 模板需要的两个参数 , 验证码+过期时间
String[] params = {msg,time};
SmsSingleSender ssender = new SmsSingleSender(smsRepository.getAppid(), smsRepository.getAppkey());
// 单发短信
result = ssender.sendWithParam(
"86", // 国家码,如 86 为中国
phone, // 不带国家码的手机号
smsRepository.getTemplateId(), // 模板Id 指定信息内容
params, // 参数内容
smsRepository.getSmsSign(), // 签名, 如果为空,会使用默认的签名
"", // 扩展码,可填空
""); // 服务端原样返回的参数,可填空
} catch (HTTPException e) {
// HTTP响应码错误
e.printStackTrace();
} catch (JSONException e) {
// json解析错误
e.printStackTrace();
} catch (IOException e) {
// 网络IO错误
e.printStackTrace();
}
// 保存验证码到redis
stringRedisTemplate.opsForValue().set(phone,msg,5,TimeUnit.SECONDS);
return result.errMsg;
}

// 创建六位随机数
public String createRodom(){
Random random = new Random();
String result="";
for (int i=0;i<6;i++)
{
result+=random.nextInt(10);
}
return result;
}
}

配置类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* @Author: Changwu
* @Date: 2019/5/25 15:39
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@ToString
@ConfigurationProperties(prefix = "sms")
public class SmsRepository {

// 短信应用SDK AppID // 1400开头
private int appid ;

// 短信应用SDK AppKey
private String appkey ;

// 短信模板ID,需要在短信应用中申请
private int templateId ; // NOTE: 这里的模板ID`7839`只是一个示例,真实的模板ID需要在短信控制台中申请

// NOTE: 这里的签名"腾讯云"只是一个示例,真实的签名需要在短信控制台中申请,另外签名参数使用的是`签名内容`,而不是`签名ID`
private String smsSign;

// 缓存的前缀
private String PREFIX;

// 过期时间
private int expireTime;

}

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 9999
spring:
redis:
host: 192.168.43.150

# 短信配置
sms:
appid: XXX #短信应用SDK AppID
appkey: XXX #短信应用SDK AppKey
templateId: 329108 # 短信模板ID,需要在短信应用中申请
smsSign: LFJHelper # 签名--自定义
expireTime: 60000 # 过期时间,默认六十秒
PREFIX: PHOTO_SMS # 缓存进redis的key