1.前端点击按钮发送短信验证码(需要校验参数)
sendSmsCode(event) {
//1.判断手机号不为空
if (!this.formParams.mobile) {
$.alert("手机号不能为空");
return;
}
//2.判断图片验证码不为空
if (!this.formParams.imageCode) {
$.alert("图片验证码不能为空");
return;
}
//3.获取按钮,禁用按钮
var sendBtn = $(event.target);
sendBtn.attr("disabled", true);
var param = {
mobile: this.formParams.mobile,
imageCode: this.formParams.imageCode,
imageCodeKey: sessionStorage.getItem("registerImageCodeKey")
};
//4.发送ajax请求
this.$http.post("/common/verifycode/sendSmsCode", param).then(res => {
var ajaxResult = res.data;
if (ajaxResult.success) {
$.alert("手机验证码已经发送到您的手机,请在3分钟内使用");
//4.1.发送成:倒计时
var time = 10;
var interval = window.setInterval(function () {
//每一条倒计时减一
time = time - 1;
//把倒计时时间搞到按钮上
sendBtn.html(time + "秒后重发");
//4.2.倒计时完成恢复按钮
if (time <= 0) {
sendBtn.html("重新发送");
sendBtn.attr("disabled", false);
//清除定时器
window.clearInterval(interval);
}
}, 1000);
} else {
//4.3.发送失败:提示,恢复按钮
sendBtn.attr("disabled", false);
$.alert("发送失败:" + ajaxResult.message);
}
}).catch(error => {
//4.3.发送失败:提示,恢复按钮
sendBtn.attr("disabled", false);
$.alert("发送失败:" + error.message);
})
}
2.后端接收请求,校验参数,生成验证码,通过短信发送给用户
controller接收请求
@PostMapping(value="/sendSmsCode")
public JSONResult getSmsCode(@RequestBody @Validated SMSParamDto param){
verifycodeService.getSmsCode(param);
return JSONResult.success();
}
service
/**
* 判断参数,判断条件
* 校验图形验证码
* 校验手机验证码,有就使用上一次的,没有就新发送一个
* 发送短信
* 将短信信息存到数据库
* @param param
*/
void getSmsCode(SMSParamDto param);
具体步骤
1.判断参数(SMSParamDto中判断了),判断条件
2.校验图形验证码
3.校验手机验证码,有就使用上一次的,没有就新发送一个
4.发送短信(我这里直接打印在控制台,实际情况需要调用短信接口发送短信)
5.将短信信息存到数据库
6.手机验证码发送成功,删除图形验证码
dto
@Data
public class SMSParamDto {
@NotEmpty(message = "手机号不能为空")
private String mobile;
@NotEmpty(message = "图形验证码不能为空")
private String imageCode;
@NotEmpty(message = "无效请求")
private String imageCodeKey;
}
constants(抽了一个常量类)
public class AllConstants {
// 基本常量
public class BaseConstants{
// 一分钟的毫秒数
public static final int MILLISECOND_ONE_MINS = 60000;
// 一分钟的秒数
public static final int SECOND_ONE_MINS = 60;
}
}
impl
需要注入
@Autowired
private RedisTemplate<Object,Object> redisTemplate;
@Autowired
private IMessageSmsService smsService;
@Autowired
private SMSVerifycodeProperties smsProperties;
@Autowired
private IBlockService blockService;
@Override
public void getSmsCode(SMSParamDto param) {
// 1.校验图形验证码
String imageCode = (String) redisTemplate.opsForValue().get(param.getImageCodeKey());
if (imageCode == null){
throw new GolbalException("图形验证码已过期");
}
if (!imageCode.equalsIgnoreCase(param.getImageCode())){
throw new GolbalException("图形验证码错误");
}
// 判断手机号是否被拉黑
Block phone = findBlockByPhone(param.getMobile());
if (phone != null){
throw new GolbalException("您已经被禁用发送短信验证码,请联系管理员!");
}
// 2.校验手机验证码,有就使用上一次的,没有就新发送一个
// String smsKey = String.format(AllConstants.PrefixConstants.KEY_SMS_PREFIX + param.getMobile());
String smsKey = "register:" + param.getMobile();
SMSLog2Redis lastSMSLog2Redis = (SMSLog2Redis) redisTemplate.opsForValue().get(smsKey);
Date now = new Date();
String smsCode = null;
if (lastSMSLog2Redis != null){
// 2.1有验证码,判断手机验证码的发送时间,手机小于60s报错,大于60s且验证码未被使用,就使用之前的验证码
if (now.getTime() - lastSMSLog2Redis.getSendTime().getTime() < AllConstants.BaseConstants.MILLISECOND_ONE_MINS){
// 抛异常
throw new GolbalException("操作频繁,请稍后重试!");
}
// 使用之前的验证码
smsCode = lastSMSLog2Redis.getCode();
}else {
// 2.2没有验证码,生成新的验证码(随机字符串)
smsCode = StrUtils.getRandomString(smsProperties.getLength());
}
// 3.将验证码存到redis key(手机号+业务键)- value(验证码,时间)
SMSLog2Redis smsLog2Redis = new SMSLog2Redis(smsCode, now);
redisTemplate.opsForValue().set(smsKey,smsLog2Redis,smsProperties.getExpire(),TimeUnit.MINUTES);
// 4.发送短信
String content = "您的验证码为:" + smsCode + ",请在" + smsProperties.getExpire()/AllConstants.BaseConstants.SECOND_ONE_MINS + "分钟内使用!";
log.info(content);
// 5.将短信信息存到数据库
smsService.save(content,param.getMobile(),"注册短信验证码");
// 6.手机验证码发送成功,删除图形验证码
redisTemplate.delete(param.getImageCodeKey());
}
private Block findBlockByPhone(String mobile) {
return blockService.findByPhone(mobile);
}
抽出了一个方法
private Block findBlockByPhone(String mobile) {
return blockService.findByPhone(mobile);
}
service
Block findByPhone(String phone);
impl
public Block findByPhone(String phone){
Wrapper<Block> query = new EntityWrapper<>();
query.eq("phone",phone);
return super.selectOne(query);
}