今天在一个练习的业务中,需要将验证码根据邮箱名存入缓存,但是将生成的验证码放入缓存后,在SpringBoot项目中的RedisTamplale却始终获取不到存入的验证码。再此记录这个坑!
邮箱发送接口
@ApiOperation(value = "发送邮箱验证码")
@GetMapping(value = "sendEmail/{email}")
@CostTime
@PassToken
public Result<Object> sendCode(@PathVariable String email) {
log.info("邮箱码:{}",email);
String code = redisTemplate.opsForValue().get(email);
if (!StringUtils.isEmpty(code)) {
return Result.ok().message(email + ":" + code + "已存在,还未过期");
}
code = CodeGeneratorUtil.generateCode(6);
try {
boolean b = sendEmailUtil.sendEmail(email, code);
if (b) {
redisTemplate.opsForValue().set(email, code,Duration.ofMinutes(1));
return Result.ok().message("验证码发送成功!");
}
return Result.fail();
} catch (Exception e) {
throw new MyException(501, "邮箱不正确或为空!");
}
}
当前端根据邮箱发送验证码后,验证码会以邮箱名为key来存储验证码。
注册接口
/**
* 用户注册
*
* @param
* @return
*/
@ApiOperation(value = "用户注册调用接口")
@PostMapping(value = "/register")
@CostTime
@PassToken
public Result<Object> register(@RequestBody @Validated RegisterDto registerDto, BindingResult result) {
if (result.hasErrors()) {
return Result.fail().message("填写的信息不齐");
}
Customer customer = new Customer();
Customer one = customerService.getOne(new QueryWrapper<Customer>().eq("username", registerDto.getUsername()));
if (!StringUtils.isEmpty(one)) {
log.info("没走验证业务?");
return Result.fail().message("账号已存在,请重新注册");
}
//验证邮箱验证码
String code = registerDto.getCode();
log.info("前端输入的验证码{}", code);
String eml = registerDto.getEmail();
log.info("前端的对象为{},邮箱=》{}",registerDto,eml);
String s = redisTemplate.opsForValue().get(eml);
log.info("从redis中获取code->{}",s);
/*邮箱验证有点问题————————————————————————————————————————————————————————————————————————————*/
if (Objects.equals(s, code)) {
log.info("验证码正确{}", code);
//通过雪花算法设置cid
customer.setCid(CodeGeneratorUtil.snowflake());
customer.setCreateTime(LocalDateTime.now());
customer.setSex(true);
customer.setAvatar(registerDto.getAvatar());
customer.setUsername(registerDto.getUsername());
customer.setEmail(registerDto.getEmail());
customer.setRoleId(2);
customer.setBirth(LocalDate.now());
customer.setPassword(DigestUtil.md5Hex(registerDto.getPassword()));
boolean user = customerService.save(customer);
if (user) {
log.info("账号注册成功?");
return Result.ok().message("账号注册成功");
}
log.info("账号注册失败?");
return Result.fail().message("账号注册失败");
} else {
log.info("验证码错误?{}", s);
return Result.fail().message("验证码错误,请重新输入");
}
}
}
但是在获取value的时候一直为空,并且redis中根据邮箱key是可以获取到value值的。
2023-03-05 17:33:40.904 INFO 5132 --- [nio-8084-exec-2] com.yy.controller.CustomerController : 前端输入的验证码b65bea
2023-03-05 17:33:40.904 INFO 5132 --- [nio-8084-exec-2] com.yy.controller.CustomerController : 前端的对象为RegisterDto(username=young, password=123456, sex=null, code=b65bea, cid=0, email=1084708769@qq.com, birth=null, createTime=null, checkPass=123456),邮箱=》111111111@qq.com
2023-03-05 17:33:40.944 INFO 5132 --- [nio-8084-exec-2] com.yy.controller.CustomerController : 从redis中获取code->null
2023-03-05 17:33:40.944 INFO 5132 --- [nio-8084-exec-2] com.yy.controller.CustomerController : 验证码错误?null
2023-03-05 17:33:40.944 INFO 5132 --- [nio-8084-exec-2] com.yy.aspect.ServiceAspect : 调用的是服务层中的com.yy.controller.CustomerController类,其中的的register方法--执行时间为:45毫秒
2023-03-05 17:35:16.390 INFO 5132 --- [nio-8084-exec-4] com.yy.aspect.LogAspect : 目前的访问时间为:2023年03月05日 17:35:16--访问接口为:Result com.yy.controller.LoginController.sendCode(String)
通过各种测试,最后找到的原因是因为在依赖注入时,笔者采用的时@Resource注解来注入RedisTamplate的!!!
@Resource
private RedisTemplate<String, String> redisTemplate;
解决方式
将依赖注入的注解改为@Autowired就可以正常实现获取value的功能了。
/**
* 不能用Resource,否则获取不到存得值
*/
@Autowired
private RedisTemplate<String, String> redisTemplate;
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@16e4b8a6]
2023-03-05 17:39:26.894 INFO 5132 --- [io-8084-exec-10] com.yy.controller.CustomerController : 前端输入的验证码4de7d0
2023-03-05 17:39:26.894 INFO 5132 --- [io-8084-exec-10] com.yy.controller.CustomerController : 前端的对象为RegisterDto(username=young, password=123456, sex=null, code=4de7d0, cid=0, email=495063157@qq.com, birth=null, createTime=null, checkPass=123456),邮箱=》111111111@qq.com
2023-03-05 17:39:26.942 INFO 5132 --- [io-8084-exec-10] com.yy.controller.CustomerController : 从redis中获取code->4de7d0
2023-03-05 17:39:26.943 INFO 5132 --- [io-8084-exec-10] com.yy.controller.CustomerController : 验证码正确4de7d0
虽然spring官方不建议使用@Autowired来进行属性注入(造成注入对象与IOC容器的强耦合性),但是不得不说,在有些方面:比如以上这个例子,或者在微服务中注入OpenFeign接口(@Resource注入也可能失败)的时候确实比@Resource好使。
但是具体原因暂时没想明白,有考虑过注入作用的问题,但是显然不是,默认都是单例的。还在找原因ing……,欢迎大佬指正原因~