一、优化三个模块及原因:
A.存储验证码:
①验证码需要频繁刷新和访问
②验证码不需要永久保存,通常在一段时间内失效
③分布式部署的session共享问题
B.存储登录凭证
①每次处理请求时,都要查询用户的登录凭证,访问频率高
C.缓存用户信息
①每次处理请求时,都要根据凭证 查询用户信息,访问频率高
二、存储验证码流程
A.生成验证码
B.验证码分别存入Redis和cookie中
①Redis存储需要key和value。定义PREFIX_KAPTCHA + SPLIT + owner为Rediskey,不能使用userId,因为此时用户没有登录,只能使用临时owner。
private static final String PREFIX_KAPTCHA = "kaptcha";
// 登录验证码
// 不能用userId,因为此时用户没有登录,owner是用户的临时凭证
public static String getUserKey(String owner) {
return PREFIX_KAPTCHA + SPLIT + owner;
}
②验证码归属owner要发给客户端由客户端保存,加入cookie中,并设置失效时间,将cookie加入response中
// 生成验证码
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 将验证码存入session
// session.setAttribute("kaptcha", text);
// 验证码的归属
String kaptchaOwner = CommunityUtil.generateUUID();
Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addCookie(cookie);
// 将验证码存储到redis里
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
redisTemplate.opsForValue().set(redisKey, text, 60, TimeUnit.SECONDS);
C.登录时,从Redis中根据key查询验证码,再与输入 验证码做比较
// String kaptcha = (String) session.getAttribute("kaptcha");
// 检查验证码
String kaptcha = null;
if(StringUtils.isNotBlank(kaptchaOwner)) {
String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
}
三、Redis存用户登录凭证
与存储验证码流程类似:
A.定义RedisKey:
private static final String PREFIX_TICKET = "ticket";
// 登录的凭证
public static String getTicketKey(String ticket) {
return PREFIX_TICKET + SPLIT + ticket;
}
B.重构login方法:将用户登录凭证存入Redis,使用String存储。
String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
// redis 会把这个对象序列化成json格式的字符串
redisTemplate.opsForValue().set(redisKey, loginTicket);
C.重构logout方法:先获取RedisKey,在根据RedisKey从Redis中获取登录凭证,将 登录状态改为1,再存入Redis。
public void logout(String ticket) {
// loginTicketMapper.updateStatus(ticket, 1);
String redisKey = RedisKeyUtil.getTicketKey(ticket);
LoginTicket loginTicket = (LoginTicket) redisTemplate.opsForValue().get(redisKey);
loginTicket.setStatus(1);
redisTemplate.opsForValue().set(redisKey, loginTicket);
}
四、Redis缓存用户信息
缓存用户信息主要有以下几件事:
1.在查询数据时,优先尝试从缓存中取值,有可能取得到,有可能取不到,如果取不到就需要进行初始化。
2.有些地方其他操作更新了状态或者数据,要对缓存更新。两种方法:
①更新缓存
②删除缓存,等下一次查询时重新加载缓存。
一般使用删除的方式,因为在做更新操作时可能会造成并发问题。
// 1.优先从缓存中取值
private User getCache(int userId) {
String redisKey = RedisKeyUtil.getUserKey(userId);
return (User) redisTemplate.opsForValue().get(redisKey);
}
// 2.取不到时初始化缓存数据
private User initCache(int userId) {
User user = userMapper.selectById(userId);
String redisKey = RedisKeyUtil.getUserKey(userId);
redisTemplate.opsForValue().set(redisKey, user, 3600, TimeUnit.SECONDS);
return user;
}
// 3.数据变更时清除缓存数据
private void clearCache(int userId) {
String redisKey = RedisKeyUtil.getUserKey(userId);
redisTemplate.delete(redisKey);
}
- findUserById
public User findUserById(int id){
// return userMapper.selectById(id);
User user = getCache(id);
if(user == null) {
user = initCache(id);
}
return user;
}