以前所做的短信服务存储都是基于MySQL数据库 + 定时器来实现的,感觉的有点浪费资源,于是把短信服务基于redis重构了
Redis依赖和Reids工具类:https://blog.csdn.net/weixin_46136492/article/details/112919388
1、Maven依赖
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
</dependencies>
2、在resources下创建third.properties
# 短信验证码
sms.getAccessKeyId=***
sms.getAccessSecret=***
# 中文获取的时候,必须设置为utf8格式,不然会乱码
sms.getSignName=***
sms.getTemplateCode=***
3、配置SmsDemo
@Component
// 设置UTF-8编码,不然会中文乱码
@PropertySource(value = "classpath:third.properties", encoding = "UTF-8")
public class SmsDemo {
@Value("${sms.getAccessKeyId}")
private String getAccessKeyId;
@Value("${sms.getAccessSecret}")
private String getAccessSecret;
@Value("${sms.getSignName}")
private String getSignName;
@Value("${sms.getTemplateCode}")
private String getTemplateCode;
public String getGetAccessKeyId() {
return getAccessKeyId;
}
public void setGetAccessKeyId(String getAccessKeyId) {
this.getAccessKeyId = getAccessKeyId;
}
public String getGetAccessSecret() {
return getAccessSecret;
}
public void setGetAccessSecret(String getAccessSecret) {
this.getAccessSecret = getAccessSecret;
}
public String getGetSignName() {
return getSignName;
}
public void setGetSignName(String getSignName) {
this.getSignName = getSignName;
}
public String getGetTemplateCode() {
return getTemplateCode;
}
public void setGetTemplateCode(String getTemplateCode) {
this.getTemplateCode = getTemplateCode;
}
@Override
public String toString() {
return "SmsDemo{" +
"getAccessKeyId='" + getAccessKeyId + '\'' +
", getAccessSecret='" + getAccessSecret + '\'' +
", getSignName='" + getSignName + '\'' +
", getTemplateCode='" + getTemplateCode + '\'' +
'}';
}
/**
* 简要说明:发送手机验证码
*
* @param phone [需要发送验证的手机号码]
* @param code [短信码]
* @return boolean [成功true,失败false]
*/
public boolean create(String phone, String code) {
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", "cn-hangzhou");
request.putQueryParameter("PhoneNumbers", phone);
request.putQueryParameter("SignName", getSignName);
request.putQueryParameter("TemplateCode", getTemplateCode);
request.putQueryParameter("TemplateParam", "{\"code\":" + code + "}");
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", getAccessKeyId, getAccessSecret);
IAcsClient client = new DefaultAcsClient(profile);
String res = null;
try {
res = client.getCommonResponse(request).getData();
} catch (ClientException e) {
e.printStackTrace();
}
return res != null && res.contains("OK");
}
}
4、NoteController前端控制器
/**
* @author: FSL
* @introduce: 短信类验证 前端控制器
* @date: 2021/1/20 16:19
*/
@RestController
@RequestMapping("/system/note")
@ResponseBody
public class NoteController extends BaseController {
@Resource
private NoteService noteService;
/**
* 简要说明:发送验证码
*
* @param phone [手机号]
* @return String
*/
@PostMapping("/create")
public String create(@RequestParam(value = "phone") @Size(min = 11, max = 11) String phone) {
return noteService.create(phone);
}
/**
* 简要说明:获取手机号验证码
*
* @param phone [手机号]
* @return String
*/
@PostMapping("/getCode")
public String getCode(@RequestParam(value = "phone") @Size(min = 11, max = 11) String phone,
@RequestParam(value = "code") @Size(min = 6, max = 6) String code
) {
return noteService.isCode(phone, code) ? "true" : noteService.isCode(phone);
}
}
5、NoteService服务实现类
/**
* @author: FSL
* @introduce: 短信类验证 服务实现类
* @date: 2021/1/20 17:45
*/
@Service
public class NoteService {
@Resource
private RedisUtil redisUtil;
@Resource
private SmsDemo smsDemo;
private final int lockNum = 5; // 锁定次数
private final int time = 15 * 60; // 锁定时间,单位秒
/**
* 简要说明:短信错误校验key
*
* @param phone [手机号]
* @return java.lang.String
*/
public String getCodeError(String phone) {
return "SMS_CODE_ERROR" + phone;
}
/**
* 简要说明:发送验证码
*
* @param phone [手机号]
* @return java.lang.String
*/
public String create(String phone) {
String code = "123456"; // 一般为4位或者6位的随机数
String r;
if (isPhone(phone)) {
r = "当前手机号已锁定,15分钟后自动解锁"; // 这里的锁定时间可以根据key的剩余时间动态获取
} else {
String smsKey = "SMS_CODE " + phone;
redisUtil.setString(smsKey, code, time);
r = smsDemo.create(phone, code) ? "发送成功" : "发送失败";
}
return r;
}
/**
* 简要说明:判断手机号是否已被锁定
*
* @param phone [手机号]
* @return boolean
*/
public boolean isPhone(String phone) {
String errorKey = getCodeError(phone);
String string = redisUtil.getString(errorKey);
if (string == null) {
return false;
}
int anInt = Integer.parseInt(redisUtil.getString(errorKey));
return anInt == lockNum;
}
/**
* 简要说明:判断手机号是否已被锁定
*
* @param phone [手机号]
* @return String
*/
public String isCode(String phone) {
if (isPhone(phone)) {
return "当前手机号已锁定,15分钟后自动解锁";
}
String errorKey = getCodeError(phone);
int anInt = 0;
if (redisUtil.getString(errorKey) != null) {
anInt = Integer.parseInt(redisUtil.getString(errorKey));
}
int lockError = anInt + 1;
redisUtil.setString(errorKey, String.valueOf(lockError), time);
if (lockError == lockNum) {
return "当前手机号已锁定,15分钟后自动解锁";
}
return "你已经连续输错验证码" + lockError + "次,如果再输错" + (lockNum - lockError) + "次,系统自动锁定该手机号,请慎重";
}
/**
* 简要说明:校验验证码是否正确
*
* @param phone [手机号]
* @param code [手机验证码]
* @return boolean
*/
public boolean isCode(String phone, String code) {
String smsKey = "SMS_CODE" + phone;
boolean exists = redisUtil.exists(smsKey);
String codeRedis = redisUtil.getString(smsKey);
if (exists && code.equals(codeRedis)) {
redisUtil.delString(getCodeError(phone));
return true;
}
return false;
}
}