java面试题:如何用Redis实现分布式session?

先说一下整个redis 实现共享session 的业务流程:

  • ·在发送验证码的时候将手机号和对应验证码以key value 形式存储到redis中
  • ·在对比验证码是否一致时,需要从redis里面取出手机号对应的code
  • ·会使用UUID 创建一个登录令牌token
  • ·将User对象转为 HashMap,并与token令牌一起以hash 键值对形式存储
  • ·设置一个token的有效期并返回给前端
  • 设置一个新的拦截器,用于刷新token,由于LoginInterceptor没有交给Spring进行管理,因此 StringRedis Template 不能通过@Resource自动注入。需要在配置文件中进行构造器注入。
     

 

public Result sendCode(String phone,HttpSession session) {
//校验手机号
//如果不符合就返回错误信息
if RegexUtils.isPhoneInvalid(phone)) {
return Result.failC"手机号格式错误");
}
//符合就发送验证码//胡图工具类的使用
String code = RandomUtil.randomNumbers(6);
//保存验证码到redis设置一个验证码有效时长key-手机号value-验证码stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY
+phone, code, LOGIN_CODE_TTL,TimeUnit.MINUTES);
//发送验证码,返回ok(这里假装发一下验证码,实际上要不调用云平台的服务log.debug("短信验证码为:"+ code);
return Result.ok();
}
 public Result login(LoginFormDTO loginForm, HttpSession session) {
 //校验⼿机号
     String phone = loginForm.getPhone();
     if (RegexUtils.isPhoneInvalid(phone)) {
         return Result.fail("⼿机号格式错误");
     }
 //从redis⾥获取并校验验证码
     String cashCode =
stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);//找到key对
应的value
     String code = loginForm.getCode();
     if (cashCode == null || !cashCode.equals(code)) {
         return Result.fail("验证码错误");
     }
     User user = query().eq("phone", phone).one();//⽤mybatis-plus的框
架查询
     if (user == null) {//⽤户不存在就创建出来
         user = createUserWithPhone(phone);
     }
 //保存在redis中
 //随机⽣成⼀个token作为登录的令牌
     String token= UUID.randomUUID().toString(true);
 //将User对象转为HashMap存储
     UserDTO userDTO =BeanUtil.copyProperties(user,UserDTO.class);
//⽤户脱敏
     Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new
HashMap<>(),
     CopyOptions.create()
         .setIgnoreNullValue(true)
         .setFieldValueEditor((fieldName, fieldValue) ->
                fieldValue.toString()));
     String tokenKey=LOGIN_USER_KEY+token;
 //⽤哈希结构存储 多个字段有多个属性 可以存好⼏个键值对
     stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);
 //设置token的有效期
 
    stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);//30分钟
 //返回token
     return Result.ok(token);
 }
public class RefreshTokenInterceptor implements HandlerInterceptor {
 private StringRedisTemplate stringRedisTemplate;
 public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
     this.stringRedisTemplate = stringRedisTemplate;
 }
 @Override
 public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
 // 1.获取请求头中的token
     String token = request.getHeader("authorization");
     if (StrUtil.isBlank(token)) {
         return true;
     }
 // 2.基于TOKEN获取redis中的⽤户
     String key = LOGIN_USER_KEY + token;
     Map<Object, Object> userMap =
    stringRedisTemplate.opsForHash().entries(key);
 // 3.判断⽤户是否存在
     if (userMap.isEmpty()) {
         return true;
     }
 // 5.将查询到的hash数据转为UserDTO
     UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
 // 6.存在,保存⽤户信息到 ThreadLocal
     UserHolder.saveUser(userDTO);
 // 7.刷新token有效期
     stringRedisTemplate.expire(key, LOGIN_USER_TTL,TimeUnit.MINUTES);
 // 8.放⾏
     return true;
 }

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值