bootstrap.yml
#微服务启动参数
spring:
redis:
host: 192.168.200.129
port: 6379 #端口号
password: password # 密码
application:
name: user-service
main:
allow-bean-definition-overriding: true # Spring Boot 2.1 需要设定
cloud:
sentinel:
transport:
dashboard: 192.168.200.129:8858 #sentinel控制台地址
nacos:
discovery: #配置注册中心
server-addr: 192.168.200.129:8848
namespace: public
group: ${group.name}
config: #配置中心
server-addr: 192.168.200.129:8848
namespace: public
group: ${group.name}
file-extension: properties
shared-configs:
- dataId: mp-config.properties
group: ${group.name}
- dataId: spring-druid-config.properties
group: ${group.name}
- dataId: feign-config.properties
group: ${group.name}
- dataId: ribbon-config.properties
group: ${group.name}
profiles: # 激活配置环境
active: dev
# 组名称
group:
name: xc-group
# 日志文件配置路径
logging:
config: classpath:log4j2-dev.xml
SmsUitl(发短信的工具类)
package com.xuecheng.common.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class SmsUtil {
/**
* 发送短信验证码
*
* @param phone 手机号码
* @return 是否发送成功 成功:返回验证码 失败:返回null;
*/
public static String sendVerificationCode(String phone) {
// 创建DefaultAcsClient实例并传递Profile对象
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tEPVSc57i7Z4wzvAuxg", "zkzRKsdgNm1Km0Szb6dmBhIgvMiD1t");
IAcsClient client = new DefaultAcsClient(profile);
// 创建SendSmsRequest请求对象并设置请求参数
SendSmsRequest request = new SendSmsRequest();
request.setSignName("传智教育"); // 短信签名
request.setTemplateCode("SMS_461140079"); // 短信模板code
request.setPhoneNumbers(phone); // 测试号的号码(其它号码需要添加测试号先)
//短信模板
Map<String, Object> map = new HashMap<>();
String verifyCode = RandomStringUtils.random(6, "123456789"); // 获取六位验证码
map.put("code", verifyCode);
request.setTemplateParam(JSONObject.toJSONString(map)); // 发送短信信息内容(因为这里是验证码,格式为:{"code":"4-6位数字"})
try {
SendSmsResponse response = client.getAcsResponse(request); // 发送短信请求,获取响应
log.info(JSON.toJSONString(response)); // 打印响应信息
boolean isOk = response.getCode() != null && response.getCode().equals("OK");// 判断短信是否发送成功
if (isOk) {
return verifyCode;
}
//
// //todo
return verifyCode;
} catch (ServerException e) { // 服务端异常
e.printStackTrace(); // 打印异常信息
} catch (ClientException e) { // 客户端异常
log.error("ErrCode:" + e.getErrCode()); // 打印错误码
log.error("ErrMsg:" + e.getErrMsg()); // 打印错误信息
log.error("RequestId:" + e.getRequestId()); // 打印请求ID
}
return null; // 默认返回短信发送失败
}
}
RandomStringUtil(随机字符串工具)
package com.xuecheng.common.util;
import java.util.Random;
/**
* 随机字符串工具
*
* @author scq
*
*/
public class RandomStringUtil {
/**
* 获取指定长度随机字符串
*
* @param length
* @return
*/
public static String getRandomString(int length) {
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(3);
long result = 0;
switch (number) {
case 0:
result = Math.round(Math.random() * 25 + 65);
sb.append(String.valueOf((char) result));
break;
case 1:
result = Math.round(Math.random() * 25 + 97);
sb.append(String.valueOf((char) result));
break;
case 2:
sb.append(String.valueOf(new Random().nextInt(10)));
break;
}
}
return sb.toString();
}
/**
* 测试验证
*
* @param args
*/
//public static void main(String[] args) {
// System.out.println(RandomStringUtil.getRandomString(5));
// String str2 = RandomStringUtils.random(12,"123456789");
// System.out.println(str2);
//}
}
RedisTemplate(实例化:在config中或者启动类)
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//创建RedisTemplate实例
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
//设置Redis连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置键的序列化器为 字符串redis序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置值的序列化器为 JSON序列化器
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//设置哈希键的序列化器为 字符串redis序列化器
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//设置哈希值的序列化器为 JSON序列化器
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
//完成序列化的初始化
redisTemplate.afterPropertiesSet();
//返回实例
return redisTemplate;
}
Smscontroller
package com.shanjupay.user.controller;
import com.shanjupay.user.api.SmsService;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.exception.BusinessException;
import com.xuecheng.common.util.PhoneUtil;
import com.xuecheng.common.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Api(value = "短信通知相关", tags = "短信验证码发送校验")
@RestController
@RequestMapping("/sms")
@Slf4j
public class SmsController {
@Resource
private SmsService smsService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@ApiOperation("发送短信验证码")
@ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String", paramType = "query")
@GetMapping("/sendMessage")
public RestResponse sendMessage(@RequestParam String phone) {
//判断手机号是否为空
if (StringUtils.isAnyBlank(phone)) {
//手机号为空
throw new BusinessException(CommonErrorCode.E_100112);//手机号为空
}
//校验手机号格式
if (!PhoneUtil.isMatches(phone)) {
//校验手机号格式
throw new BusinessException(CommonErrorCode.E_100109);//手机号格式不正确
}
//从Redis中获取短信验证码
String verifyCode = redisTemplate.opsForValue().get(phone);
//如果redis中有,则短信验证码已发送,并且有效,直接再次返回该验证码
if (!StringUtil.isBlank(verifyCode)) {
throw new BusinessException(CommonErrorCode.E_100117);//验证码已发送,请查看短信或检查是否被拦截,或检查手机号码是否正确!
}
//如果Redis 中没有查到则调用业务实现类去生成并发送
smsService.sendMessage(phone);
return RestResponse.success("短信发送成功");
}
@ApiOperation("校验短信验证码")
@ApiImplicitParams({
@ApiImplicitParam(name = "phone", value = "手机号", required = true, dataType = "String", paramType = "query"),
@ApiImplicitParam(name = "verifyCode", value = "验证码", required = true, dataType = "String", paramType = "query")
})
@GetMapping("/verify")
public RestResponse sendMessage(String phone, String verifyCode) {
smsService.verificationMessageCode(phone, verifyCode);
return RestResponse.success("短信验证成功");
}
}
SmsService
package com.shanjupay.user.api;
import java.util.Map;
/**
* 短信服务
*/
public interface SmsService {
/**
* 发送短信验证码
* @param phone
* @return
*/
Boolean sendMessage(String phone);
/**
* 校验手机验证码
* @param phone
* @param verifyCode
*/
Map verificationMessageCode(String phone, String verifyCode);
}
SmsServiceImpl
package com.shanjupay.user.service;
import com.shanjupay.user.api.SmsService;
import com.shanjupay.user.mapper.AccountMapper;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.exception.BusinessException;
import com.xuecheng.common.util.SmsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @Description:
* @Version: V1.0
*/
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private AccountMapper accountMapper;
@Override
public Boolean sendMessage(String phone) {
String verifyCode = SmsUtil.sendVerificationCode(phone);
if (!StringUtils.isBlank(verifyCode)) {
redisTemplate.opsForValue().set(phone, verifyCode, 60, TimeUnit.SECONDS);
return true;
}
return false;
}
/**
* 校验验证码
*
* @param phone
* @param verifyCode
* @return
*/
@Override
public Map verificationMessageCode(String phone, String verifyCode) {
//2校验手机号在数据库中是否存在
int mobileCount = accountMapper.selectAccountByMobile(phone);
log.info("mobileCount{}", mobileCount);
if (mobileCount < 1) {
throw new BusinessException(CommonErrorCode.E_100119);//没有该用户,请注册后重新登录!
}
//2.获取Redis中的验证码
String redisPhoneCode = redisTemplate.opsForValue().get(phone);
//3.用户一直没有校验导致Redis超时销毁
if (StringUtils.isBlank(redisPhoneCode)) {
throw new BusinessException(CommonErrorCode.E_100120);//验证码已过期,请重新获取. 或检查有没有点击'获取验证码'按钮.
}
//校验验证码
if (!redisPhoneCode.equals(verifyCode)) {
//验证码错误
throw new BusinessException(CommonErrorCode.E_100102);//验证码错误
}
Map<String, Object> map = new HashMap<>();
map.put("手机号:", phone);
map.put("验证码:", verifyCode);
return map;
}
}