第一步:引入依赖
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--阿里云短信服务-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-ecs</artifactId>
<version>4.17.6</version>
</dependency>
第二步:在yml中配置redis以及阿里云短信服务秘钥
spring:
redis:
# tw:database1,2 联调1,开发2
database: 10
host: 127.0.0.1
port: 6379
timeout: 60000
jedis:
pool:
max-idle: 8
max-wait: -1
min-idle: 0
aliyyun:
sms:
access-key: ******************* //替换自己的
access-secret: **************** //替换自己的
第三部:开始编写代码(需要两个接口一个获取验证码的接口,一个登录校验验证码的接口)
第一个接口如下:
controller
/**
* description : 发送短信验证码
*
*/
@PostMapping(value = "/genRandom", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public CommonResponse genRandom(@RequestBody SmsLogin smsLogin, HttpServletRequest request) throws Exception {
String clientIp = IpUtil.getClientIP(request);
Map genRandom = smsService.genRandom(smsLogin, clientIp);
return new CommonResponse(genRandom);
}
service
/**
* description : 发送短信验证码
*
*/
Map genRandom(SmsLogin smsLogin,String clientIp) throws Exception;
/**
* description : 发送短信验证码
*
*/
public Map genRandom(SmsLogin smsLogin,String clientIp) throws Exception {
//入参校验
ValidationResponseEnum.PHONE_NUMBER.assertNotEmpty(smsLogin.getPhoneNumber());
if (!isMobile(smsLogin.getPhoneNumber())) {
throw new BaseException(1001,"手机号码格式错误,请更换后重试");
}
//发送参数
AliyunSms aliyunSms = this.aliyunSMS(smsLogin.getPhoneNumber());
// 发送验证码
return this.sendAliyunMsg(aliyunSms,clientIp);
}
/**
* description : 发送短信验证码-发送参数
*
*/
private AliyunSms aliyunSMS(String phoneNumber) {
AliyunSms aliyun = new AliyunSms();
// 签名
aliyun.setSignName(AliyunConstant.ALIYUN_SMS_SIGNNAME);
// 模板编码
aliyun.setTemplateCode(AliyunConstant.ALIYUN_SMS_TEMPLATECODE);
// 失效时间
aliyun.setTimeout(AliyunConstant.ALIYUN_SMS_TIMEOUT);
// 验证码长度
aliyun.setVerifySize(AliyunConstant.ALIYUN_SMS_VERIFY_SIZE);
// 手机号
aliyun.setPhoneNumber(phoneNumber);
return aliyun;
}
/**
* description : 发送短信验证码-阿里云发送
*
*/
public Map sendAliyunMsg(AliyunSms aliyunSms,String clientIp) throws Exception {
//检查同一IP10分钟内发送次数是否超限制
String countKey = "ip_count:" + clientIp;
if (redisTemplate.opsForValue().get(countKey)== null) {
//首次发送
redisTemplate.opsForValue().set(countKey, "1", 10, TimeUnit.MINUTES);
}else{
//获取发送次数
Integer count = Integer.valueOf(redisTemplate.opsForValue().get(countKey));
if (count != null && count >= 3) {
throw new BaseException (1005,"频繁发送,请10分钟后重试");
}
count++;
// 增加发送次数
// redisTemplate.opsForValue().increment(String.valueOf(count), 1);
redisTemplate.opsForValue().set(countKey, String.valueOf(count), 10, TimeUnit.MINUTES);
}
// 存储返回结果
Map<String, Object> result = new HashMap<>();
// 使用工具类生成六位的数字验证码
String code = BaseUtil.getRandomCode(aliyunSms.getVerifySize());
// 将redisTemplate模板对象的key的序列化方式修改为new StringRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 将PhoneNumber当做key,将code当做value存进redis中,时间为10分钟
redisTemplate.opsForValue().set(aliyunSms.getPhoneNumber(), code, 10, TimeUnit.MINUTES);
// 获取信息发送成功与否的标志
boolean flag = this.send(aliyunSms,code);
// 根据信息是否发送成功,返回不同的内容
if (flag){
result.put("message", "验证码发送成功");
} else {
result.put("message", "验证码发送失败");
}
// 向前端返回信息
return result;
}
/**
* description : 发送短信验证码-阿里云发送
*
*/
public boolean send(AliyunSms aliyunSms,String code) {
// 连接阿里云
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", AccessKeyID, AccessKeySecret);
IAcsClient client = new DefaultAcsClient(profile);
// 构建请求
CommonRequest request = new CommonRequest();
// 请求方式
request.setSysMethod(MethodType.POST);
// 官方需要的和短信请求相关的信息
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
// 生成装有短信验证码的map
Map<String,Object> messageMap = new HashMap<>();
messageMap.put("code", code);
// 填写请求参数
request.putQueryParameter("PhoneNumbers", aliyunSms.getPhoneNumber());
// 签名名称
request.putQueryParameter("SignName", aliyunSms.getSignName());
//模板CODE
request.putQueryParameter("TemplateCode", aliyunSms.getTemplateCode());
// 短信模板变量对应的实际值
request.putQueryParameter("TemplateParam", JSONObject.toJSONString(messageMap));
try {
// 发送请求并接受返回值
CommonResponse response = client.getCommonResponse(request);
// 把json格式字符串变成Json对象
JSONObject jsonObject = JSON.parseObject(response.getData());
// 请求状态码,返回OK代表请求成功,来自官方文档
String resCode = jsonObject.getString("Code");
return "OK".equals(resCode);
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
e.printStackTrace();
}
return false;
}
}
3.1 其中实体以及常量类如下:
1.存储用户信息表
@Data
@TableName(value = "XXXXX")
public class SmsLogin {
/**
* ID
*/
@TableId(type = IdType.ASSIGN_ID)
private String Id;
/**
* 手机号码
*/
private String phoneNumber;
/**
* 验证码
*/
private String verifyCode;
/**
* 登录时间
*/
private String creationTime;
}
2.发送参数实体
@Data
public class AliyunSms {
/**
* 签名
*/
private String signName;
/**
* 模板编码
*/
private String templateCode;
/**
* 失效时间
*/
private Integer timeout;
/**
* 验证码长度
*/
private Integer verifySize;
/**
* 手机号码
*/
private String phoneNumber;
}
3.常量实体
public class AliyunConstant {
/**
* 签名
*/
public static final String ALIYUN_SMS_SIGNNAME = "中科知道";
/**
* 长度
*/
public static final Integer ALIYUN_SMS_VERIFY_SIZE = 6;
/**
* 登录
*/
public static final String ALIYUN_SMS_TEMPLATECODE = "SMS_461560323";
/**
* 失效时间
*/
public static final Integer ALIYUN_SMS_TIMEOUT = 60;
}
第二个接口为校验验证码登录接口
controller
/**
* description: 验证码校验-登录
*
*/
@PostMapping(value = "/insertCheck", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Map insertCheck(@RequestBody SmsLogin smsLogin) throws Exception {
return smsService.insertCheck(smsLogin);
}
service
/**
* description: 验证码校验-登录
*
*/
Map insertCheck(SmsLogin smsLogin) throws Exception;
/**
* description: 验证码校验-登录
*
*/
public Map insertCheck(SmsLogin smsLogin) throws Exception {
Map<String, Object> map = new HashMap<>();
//入参校验
if (StringUtils.isBlank(smsLogin.getPhoneNumber())|| StringUtils.isBlank(smsLogin.getVerifyCode())) {
throw new BaseException(1002,"注册失败,缺少必要参数");
}
//验证码校验
// 获取redis中的验证码
String code = redisTemplate.opsForValue().get(smsLogin.getPhoneNumber());
if (!StringUtils.isNotNull(code) || !code.equals(smsLogin.getVerifyCode())) {
throw new BaseException(1003,"验证码错误");
}
//数据入库
SmsLogin sms = new SmsLogin();
sms.setPhoneNumber(smsLogin.getPhoneNumber());
sms.setVerifyCode(code);
sms.setCreationTime(TimeUtil.currentDate());
try {
smsLoginMapper.insert(sms);
map.put("code", 200);
map.put("message", "您已成功登录");
map.put("id", sms.getId());
map.put("phoneNumber", sms.getPhoneNumber());
} catch (Exception e) {
throw new BaseException(1004,"登录失败");
}
return map;
}