一、业务需求:
1、后端随机生成短信验证码,并在服务器端保存一定时间(redis);
2、将短信验证码发给用户;
3、用户输入短信验证码提交后,在后端与之前生成的短信验证码作比较,如果相同说明验证成功,否则验证失败。
二、操作流程:
建工程——》改POM——》写YML——》业务类
1、添加依赖:
org.springframework.boot
spring-boot-starter-data-redis
com.aliyun
aliyun-java-sdk-core
4.0.6
com.aliyun
aliyun-java-sdk-dysmsapi
1.1.0
javax.mail
mail
1.4.7
2、写YML:
server:
port: 8081
spring:
application:
name: demo
datasource:
type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
druid:
test-while-idle: false #关闭空闲检测
redis:
host: 127.0.0.1 # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: # Redis服务器连接密码
jedis:
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 500 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
lettuce:
shutdown-timeout: 0ms
mybatis:
mapperLocations: classpath:mapper/*.xml
三、通用工具类:
1、Redis通用工具类:
@Component public final class RedisUtil { @Autowired private RedisTemplateredisTemplate; // =============================common============================ /** * 指定缓存失效时间 * @param key 键 * @param time 时间(秒) */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判断key是否存在 * @param key 键 * @return true 存在 false不存在 */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除缓存 * @param key 传入一个值 */ @SuppressWarnings("unchecked") public void del(String key) { redisTemplate.delete(key); } /** * 删除缓存 * @param keys 传入多个值 */ @SuppressWarnings("unchecked") public void del(Collection ,>keys) { redisTemplate.delete(keys); } // ============================String============================= /** * 普通缓存获取 * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * @param key 键 * @param value 值 * @return true成功 false失败 */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 递增 * @param key 键 * @param delta 要增加几(大于0) */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * @param key 键 * @param delta 要减少几(小于0) */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * @param key 键 不能为null * @param item 项 不能为null */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * @param key 键 * @return 对应的多个键值 */ public Map,>
2、随机数工具类:
public class RandomUtil {
//随机生成六位数验证码
public static String getCode() {
Random random = new Random();
String result = "";
for (int i = 0; i < 6; i++) {
result += random.nextInt(10);
}
return result;
}
}
3、发送信息工具类:
public class SentMessageUtil {
/**
* 发送短信信息
* */
//产品名称:云通信短信API产品,开发者无需替换
static final String product = "Dysmsapi";
//产品域名,开发者无需替换
static final String domain = "dysmsapi.aliyuncs.com";
// TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
static final String accessKeyId = "自己的AccessKeyId";
static final String accessKeySecret = "自己的accesskeySecret";
public static boolean sendMessage(String id, String code) {
//可自助调整超时时间
System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
System.setProperty("sun.net.client.defaultReadTimeout", "10000");
//初始化acsClient,暂不支持region化
IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
try {
DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
IAcsClient acsClient = new DefaultAcsClient(profile);
//组装请求对象-具体描述见控制台-文档部分内容
SendSmsRequest request = new SendSmsRequest();
//必填:待发送手机号
request.setPhoneNumbers(id);
//必填:短信签名-可在短信控制台中找到
request.setSignName("替换成自己的短信签名");
//必填:短信模板-可在短信控制台中找到
request.setTemplateCode("替换成自己的短信模板编号");
//可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
request.setTemplateParam(code);
SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
if( sendSmsResponse.getCode().equals("OK")) {
return true;
}else {
return false;
}
} catch (ClientException e) {
e.printStackTrace();
}
return false;
}
/**
* 发送邮件信息
* */
public static boolean sendMail(String id, String code) {
Properties properties = new Properties();
// 连接协议
properties.put("mail.transport.protocol", "smtp");
// 主机名
properties.put("mail.smtp.host", "smtp.qq.com");
// 端口号
properties.put("mail.smtp.port", 465);
properties.put("mail.smtp.auth", "true");
// 设置是否使用ssl安全连接 ---一般都使用
properties.put("mail.smtp.ssl.enable", "true");
// 设置是否显示debug信息 true 会在控制台显示相关信息
properties.put("mail.debug", "true");
// 得到回话对象
Session session = Session.getInstance(properties);
// 获取邮件对象
Message message = new MimeMessage(session);
try {
// 设置发件人邮箱地址
message.setFrom(new InternetAddress("发件人xxx@qq.com"));
// 设置收件人邮箱地址:单个/多个
//message.setRecipients(Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("xxx@qq.com"),new InternetAddress("xxx@qq.com"),new InternetAddress("xxx@qq.com")});
message.setRecipient(Message.RecipientType.TO, new InternetAddress(id));
// 设置邮件标题
message.setSubject("验证信息测试");
// 设置邮件内容
message.setText("验证码为:" + code + ",验证码有效期5分钟,请及时验证");
// 得到邮差对象
Transport transport = session.getTransport();
// 连接自己的邮箱账户
// 密码为QQ邮箱开通的stmp服务后得到的客户端授权码
transport.connect("发件人xxx@qq.com", "rbg");
// 发送邮件
transport.sendMessage(message, message.getAllRecipients());
transport.close();
return true;
} catch (MessagingException e) {
e.printStackTrace();
}
return false;
}
}
4、Redis配置类:
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* RedisTemplate内部的序列化配置器默认采用JDK序列化器
* 使用默认序列化配置器查看数据时会导致数据乱码,需重新定义RedisTemplate序列化方案
* 修改存储对象的序列化问题
*/
@Bean
@SuppressWarnings("all")
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
/**
* CacheManager:
* 管理多种缓存,包含内存, appfabric, redis, couchbase, windows azure cache, memorycache等
* 提供了额外的功能,如缓存同步、并发更新、事件、性能计数器等
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
四、发送验证码功能:
1、请求体:
@Data
public class MessageResourceVO {
private String id;
private String code;
private Boolean way;
}
2、控制类:
/**
* 功能一:发送验证码
*
* http://localhost:8081/v1/sent-code
* */
@PostMapping("/sent-code")
public Response sentCode(
@RequestBody MessageResourceVO messageResourceVO) {
return Response.success(sendService.sentCode(messageResourceVO));
}
3、业务类:
@Autowired
private RedisUtil redisUtil;
@Override
public Object sentCode(MessageResourceVO messageResourceVO) {
//设置redis的key:USER:+号码
String userId = "USER:" + messageResourceVO.getId();
//设置redis的value:随机生成的六位数验证码
String code = RandomUtil.getCode();
//设置验证码的失效时间:5min-->300s
redisUtil.set(userId,code,300);
//判断key是否存在
if (redisUtil.hasKey(userId)) {
boolean isSuccess = false;
if (messageResourceVO.getWay()) {
//发送短信验证码
isSuccess = SentMessageUtil.sendMessage(messageResourceVO.getId(), code);
} else {
//发送邮件验证码
isSuccess = SentMessageUtil.sendMail(messageResourceVO.getId(), code);
}
if (isSuccess) {
return "success";
} else {
return "fail";
}
} else {
return "redis连接失败";
}
}
五、验证信息功能:
1、请求体:
@Data
public class MessageResourceVO {
private String id;
private String code;
private Boolean way;
}
2、控制类:
/**
* 功能二:验证信息
*
* http://localhost:8081/v1/verify-code
* */
@PostMapping("/verify-code")
public Response verifyCode(
@RequestBody MessageResourceVO messageResourceVO) {
return Response.success(sendService.verifyCode(messageResourceVO));
}
3、业务类:
@Autowired
private RedisUtil redisUtil;
@Override
public Object verifyCode(MessageResourceVO messageResourceVO) {
//设置redis的key:USER:+号码
String userId = "USER:" + messageResourceVO.getId();
//获取Redis缓存值
String realCode = redisUtil.get(userId).toString();
if(realCode != null && realCode.equals(messageResourceVO.getCode())){
return "success";
}else {
return "fail";
}
}
六、参考:
1、发送邮件参考
4、 阿里云短信服务参考
搜索
复制
Original: https://www.cnblogs.com/Iven-L/p/16587484.html
Author: 爱文(Iven)
Title: 6、发送验证码功能(Redis)
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/575697/
转载文章受原作者版权保护。转载请注明原作者出处!