4.23使用redis来优化登录模块

主要优化以下三个方面:
在这里插入图片描述

一、redis存储验证码

1.打开RedisKeyUtil

private static final String PREFIX_KAPTCHA = "kaptcha";//定义前缀,验证码叫 kaptcha
  // 获取登录验证码
    public static String getKaptchaKey(String owner) {//以字符串临时标识用户,很快会过期
        return PREFIX_KAPTCHA + SPLIT + owner;//要识别出验证码属于哪个用户,不能靠userid,因为验证码 是辅助用户登录的,显示验证码的时候还没有登录
    }

2.验证码是在登录功能里用到的,在logincontroller中使用

  @RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
    public void getKaptcha(HttpServletResponse response/*, HttpSession session*/) {//原来是把验证码传到session中,现在将其注释掉

        // 生成验证码
        String text = kaptchaProducer.createText();
        BufferedImage image = kaptchaProducer.createImage(text);

        // 将验证码存入session
        // session.setAttribute("kaptcha", text);

        // 验证码的归属(为了实现将验证码存入Redis,需要构造key,而key需要验证码的归属)
        String kaptchaOwner = CommunityUtil.generateUUID();//创建随机字符串并存入cookie
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
        cookie.setMaxAge(60);//设置cookie的失效时间 60s
        cookie.setPath(contextPath);//有效路径,整个项目下都有效
        response.addCookie(cookie);//添加到客户端

        // 将验证码存入Redis
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
        redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);//text是验证码的文本,60后面的TimeUnit.SECONDS 是其单位秒。存入了redis

        // 将突图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
            logger.error("响应验证码失败:" + e.getMessage());
        }
    }
@RequestMapping(path = "/login", method = RequestMethod.POST)
public String login(String username, String password, String code, boolean rememberme,
                    Model model, /*HttpSession session, */HttpServletResponse response,//因为从redis中取,所以要注释掉/*HttpSession session, */
                    @CookieValue("kaptchaOwner") String kaptchaOwner) {//声明变量String kaptchaOwner,用来接收值 kaptchaOwner
    // 检查验证码
    // String kaptcha = (String) session.getAttribute("kaptcha");
    String kaptcha = null;//默认kaptcha为null

    if (StringUtils.isNotBlank(kaptchaOwner)) {//判断key不为空,即数据没有失效
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);//redis 的key 需要kaptchaOwner,kaptchaOwner要从Cookie中取
        kaptcha = (String) redisTemplate.opsForValue().get(redisKey);//根据redisKey,从redis中取值,将object强制转型为String
    }

    if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)) {
        model.addAttribute("codeMsg", "验证码不正确!");
        return "/site/login";
    }

3.测试:
在首页的登录页面
在这里插入图片描述
可以登录成功,说明优化后正确

二、使用redis存储登录凭证

1.在RedisKeyUtil中

private static final String PREFIX_TICKET = "ticket";
private static final String PREFIX_USER = "user";
// 登录的凭证
public static String getTicketKey(String ticket) {
    return PREFIX_TICKET + SPLIT + ticket;
}

2.通过废除掉LoginTicketMapper
在这里插入图片描述
3.重构
在userservice中,

        // 生成登录凭证
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        loginTicket.setTicket(CommunityUtil.generateUUID());
        loginTicket.setStatus(0);
        loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
//        loginTicketMapper.insertLoginTicket(loginTicket);

        String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
        redisTemplate.opsForValue().set(redisKey, loginTicket);//每个redisKey,对应一个loginTicket,这样redis 可以把对象序列化一个字符串

        map.put("ticket", loginTicket.getTicket());
        return map;
    }
    public LoginTicket findLoginTicket(String ticket) {
//        return loginTicketMapper.selectByTicket(ticket);
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        return (LoginTicket) redisTemplate.opsForValue().get(redisKey);
    }

测试:
在这里插入图片描述
可以登录成功,且可以正常
登录凭证是不会删的,只是会修改状态

三、使用redis缓存用户信息

缓存 表示过一会儿要把数据给删掉。

因为user表还在,所以这里只是临时 存一下,
在这里插入图片描述
该方法访问非常频繁。
每个user都缓存到redis里面
在userservice中,更改:

    public User findUserById(int id) {
//        return userMapper.selectById(id);
        User user = getCache(id);
        if (user == null) {
            user = initCache(id);
        }
        return user;
    }

在激活方法中添加一句:

public int activation(int userId, String code) {
    User user = userMapper.selectById(userId);
    if (user.getStatus() == 1) {
        return ACTIVATION_REPEAT;
    } else if (user.getActivationCode().equals(code)) {
        userMapper.updateStatus(userId, 1);
        clearCache(userId);//清理缓存
        return ACTIVATION_SUCCESS;
    } else {
        return ACTIVATION_FAILURE;
    }
}

其中,getCache为

    // 1.优先从缓存中取值
    private User getCache(int userId) {//从缓存中取到User
        String redisKey = RedisKeyUtil.getUserKey(userId);
        return (User) redisTemplate.opsForValue().get(redisKey);
    }

    // 2.取不到时初始化缓存数据,取到则直接返回
    private User initCache(int userId) {
        User user = userMapper.selectById(userId);//从mysql中查到数据
        String redisKey = RedisKeyUtil.getUserKey(userId);//得到user的key
        redisTemplate.opsForValue().set(redisKey, user, 3600, TimeUnit.SECONDS);//过期时间3600s
        return user;
    }

    // 3.数据变更时清除缓存数据
    private void clearCache(int userId) {
        String redisKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.delete(redisKey);
    }

}

在RedisKeyUtil中添加

// 用户
public static String getUserKey(int userId) {
    return PREFIX_USER + SPLIT + userId;
}

在user services中

    public int updateHeader(int userId, String headerUrl) {
//        return userMapper.updateHeader(userId, headerUrl);
        int rows = userMapper.updateHeader(userId, headerUrl);//更新并返回 更新的行数
        clearCache(userId);//更新以后,清除缓存
        return rows;
    }

测试:

将来会使用 一个小工具来测试性能到底优化了多少。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值