重构
1、使用Redis存储验证码
- 验证码需要频繁的访问和刷新,对性能的要求较高
- 验证码无需永久保存,通常在很短的时间后就失效
- 分布式部署时,存在session共享的问题
2、使用Redis存储登录凭证 - 处理每次请求时,都要查询用户的登录凭证,访问的频率非常高
3、使用Redis缓存用户信息 - 处理每次请求时,都要根据凭证查询用户信息,访问的频率非常高
1、Redis存储验证码
1.新增rediskey
/**
* 登录验证码
* @param owner 临时登录凭证
* @return
*/
public static String getKaptchaKey(String owner){
return PREFIX_KAPTCHA + SPLIT + owner;
}2.controller中将原先从session中获取验证码,改为从redis中获取
当用户没登陆的时候,向客户端发放一个cookie,再将这个cookie的值存入到数据库中,
当点击登录的时候,通过cooike从redis中获取获取验证码
@RequestMapping(value = "/kaptcha", method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response /*HttpSession session*/) {
//生成验证码
//此前已经将Producer注入到Spring容器里了
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
//Ed---0.2
//设置验证码的归属
String kaptchaOwner = CommunityUtil.generateUUID();
Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addCookie(cookie);
//将验证码存入Redis
String kaptchaKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(kaptchaKey, text, 60, TimeUnit.SECONDS);
//将图片输出给浏览器
response.setContentType("image/png");
ServletOutputStream os = null;
try {
os = response.getOutputStream();
ImageIO.write(image, "png", os);
} catch (IOException e) {
logger.error("相应验证码失败" + e.getMessage());
}
}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(String username, String password, String code, boolean rememberme,
Model model, HttpSession session, HttpServletResponse response, @CookieValue("kaptchaOwner") String kaptchaOwner) {
String kaptcha = null;
if (StringUtils.isNotBlank(kaptchaOwner)) {
String kaptchaKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(kaptchaKey);
}
if (StringUtils.isBlank(code) || StringUtils.isBlank(kaptcha) || !kaptcha.equalsIgnoreCase(code)) {
model.addAttribute("codeMsg", "验证码不正确");
return "/site/login";
}
//检查账号,密码
int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
Map<String, Object> map = userService.login(username, password, expiredSeconds);
if (map.containsKey("ticket")) {
//登录成功,发放cookie
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
cookie.setPath(contextPath);
cookie.setMaxAge(expiredSeconds);
response.addCookie(cookie);
return "redirect:/index";
} else {
model.addAttribute("usernameMsg", map.get("usernameMsg"));
model.addAttribute("passwordMsg", map.get("passwordMsg"));
return "/site/login";
}
}2、Redis存储登录凭证
/**
* 登录的凭证
* @param ticket
* @return
*/
public static String getTicketKey(String ticket){
return PREFIX_TICKET + SPLIT + ticket;
}将原来的插入到MySQL中更改为插入到Redis中,提高效率
登出时,将状态设置为1
要获取ticket时,直接从Redis中获取
![图片说明]
(https://uploadfiles.nowcoder.com/images/20200426/725155193_1587884300913_240F9BF75D686739BC3D04DE4F9BCC23 "图片标题")
3.使用Redis缓存用户信息
缓存策略:
优先从缓存中取值,取不到就初始化,数据变更时清楚缓存
//1.优先从缓存中取值
public User getCache(int userId) {
String userKey = RedisKeyUtil.getUserKey(userId);
User user = (User) redisTemplate.opsForValue().get(userKey);
return user;
}
//2.取不到时初始化缓存数据
public User initCache(int userId) {
String userKey = RedisKeyUtil.getUserKey(userId);
User user = userMapper.selectById(userId);
redisTemplate.opsForValue().set(userKey, user, 3600, TimeUnit.SECONDS);
return user;
}
//3.数据变更时清楚缓存数据
public void clearCache(int userId) {
String userKey = RedisKeyUtil.getUserKey(userId);
redisTemplate.delete(userKey);
}
京公网安备 11010502036488号