redis——對項目的一些優化方案
這是我們之前項目的業務流程,做一下簡單介紹。
登錄:
用戶輸入賬號、密碼、驗證碼。我們先判斷用戶輸入的驗證碼是不是我們session存的驗證碼,然后去查賬號密碼是否正確。
如果登錄成功,發送給用戶一張憑證(ticket)。
登錄后
之后的每次請求,用戶攜帶ticket,服務器得到后,根據ticket去login_ticket表中查找登錄信息,并且根據登錄信息再查user表獲得更多的用戶信息。
使用Redis存儲驗證碼
- 驗證碼需要頻繁的訪問與刷新,對性能要求較高。
- 驗證碼不需永久保存,通常在很短的時間后就會失效。
- 分布式部署時,存在Session共享的問題。
我們重構思路:進入登錄頁面會訪問驗證碼方法,此方法會自動生成一個驗證碼和圖片,將驗證碼和圖片輸出給瀏覽器,并且下發一個cookies,這個cookies里面存的是一段隨機數,這段隨機數作為key存在Redis里面(之前是存session),value就是驗證碼,并設置一個過期時間;
//驗證碼
@RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse response/*, HttpSession session*/) {
// 生成驗證碼
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
// 將驗證碼存入session
//session.setAttribute("kaptcha", text);
//驗證碼的歸屬
String owner= CommunityUtil.generateUUID();
Cookie cookie=new Cookie("kaptchaOwner",owner);
cookie.setMaxAge(60);
cookie.setPath(contextPath);
response.addCookie(cookie);
//存入redis
String redisKey= RedisKeyUtil.getKaptchaKey(owner);
redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);
// 將圖片輸出給瀏覽器
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,
@CookieValue("kaptchaOwner") String kaptchaOwner){
// 檢查驗證碼
//String kaptcha = (String) session.getAttribute("kaptcha");
String kaptcha=null;
if(StringUtils.isNotBlank(kaptchaOwner)){
String redisKey=RedisKeyUtil.getKaptchaKey(kaptchaOwner);
kaptcha=(String) redisTemplate.opsForValue().get(redisKey);
}
if(StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
model.addAttribute("codeMsg", "驗證碼不正確!");
return "/site/login";
}
// 檢查賬號,密碼
int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;
Map
if (map.containsKey("ticket")) {
Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
cookie.setPath(contextPath);
cookie.setMaxAge(expiredSeconds);
response.addCookie(cookie);
return "redirect:/index";
} else {
...
}
}
使用Redis存儲登錄憑證
- 處理每次請求時,都要查詢用戶的登錄憑證,訪問的頻率非常高。
登錄時不存MySQL里,存redis里
public Map
Map
// 生成登錄憑證
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);
...
}
查找
退出時也是改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緩存用戶信息
- 處理每次請求時,都要根據憑證查詢用戶信息,訪問的頻率非常高。
緩存用戶信息:因為會經常根據userid來查詢user對象,所以使用redis來緩存提高服務器性能。使用redis的String類型,存入user對象,會自動將整個對象轉換成json字符串,同時設置過期時間;
取值:優先從redis中取,取不到的時候從mysql中取,并將數據初始化到redis中
更新:更新的時候先更新mysql中的值,然后清除緩存數據;
// 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);
}
public User findUserById(int id) {
// return userMapper.selectById(id);
User user = getCache(id);
if (user == null) {
user = initCache(id);
}
return user;
}
public int updateHeader(int userId, String headerUrl) {
//return userMapper.updateHeader(userId, headerUrl);
int rows=userMapper.updateHeader(userId, headerUrl);
clearCache(userId);
return rows;
}
Redis
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。