redis——对项目的一些优化方案
這是我們之前項(xiàng)目的業(yè)務(wù)流程,做一下簡(jiǎn)單介紹。
登錄:
用戶(hù)輸入賬號(hào)、密碼、驗(yàn)證碼。我們先判斷用戶(hù)輸入的驗(yàn)證碼是不是我們session存的驗(yàn)證碼,然后去查賬號(hào)密碼是否正確。
如果登錄成功,發(fā)送給用戶(hù)一張憑證(ticket)。
登錄后
之后的每次請(qǐng)求,用戶(hù)攜帶ticket,服務(wù)器得到后,根據(jù)ticket去login_ticket表中查找登錄信息,并且根據(jù)登錄信息再查user表獲得更多的用戶(hù)信息。
使用Redis存儲(chǔ)驗(yàn)證碼
- 驗(yàn)證碼需要頻繁的訪(fǎng)問(wèn)與刷新,對(duì)性能要求較高。
- 驗(yàn)證碼不需永久保存,通常在很短的時(shí)間后就會(huì)失效。
- 分布式部署時(shí),存在Session共享的問(wèn)題。
我們重構(gòu)思路:進(jìn)入登錄頁(yè)面會(huì)訪(fǎng)問(wèn)驗(yàn)證碼方法,此方法會(huì)自動(dòng)生成一個(gè)驗(yàn)證碼和圖片,將驗(yàn)證碼和圖片輸出給瀏覽器,并且下發(fā)一個(gè)cookies,這個(gè)cookies里面存的是一段隨機(jī)數(shù),這段隨機(jī)數(shù)作為key存在redis里面(之前是存session),value就是驗(yàn)證碼,并設(shè)置一個(gè)過(guò)期時(shí)間;
//驗(yàn)證碼@RequestMapping(path = "/kaptcha", method = RequestMethod.GET)public void getKaptcha(HttpServletResponse response/*, HttpSession session*/) {// 生成驗(yàn)證碼String text = kaptchaProducer.createText();BufferedImage image = kaptchaProducer.createImage(text);// 將驗(yàn)證碼存入session//session.setAttribute("kaptcha", text);//驗(yàn)證碼的歸屬String owner= CommunityUtil.generateUUID();Cookie cookie=new Cookie("kaptchaOwner",owner);cookie.setMaxAge(60);cookie.setPath(contextPath);response.addCookie(cookie);//存入redisString 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("響應(yīng)驗(yàn)證碼失敗:" + 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){// 檢查驗(yàn)證碼//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", "驗(yàn)證碼不正確!");return "/site/login";}// 檢查賬號(hào),密碼int expiredSeconds = rememberme ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;Map<String, Object> map = userService.login(username, password, expiredSeconds);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存儲(chǔ)登錄憑證
- 處理每次請(qǐng)求時(shí),都要查詢(xún)用戶(hù)的登錄憑證,訪(fǎng)問(wèn)的頻率非常高。
登錄時(shí)不存MySQL里,存redis里
public Map<String,Object> login(String username,String password,int expiredSeconds){Map<String,Object> map=new HashMap<>();// 生成登錄憑證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);...}查找
退出時(shí)也是改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緩存用戶(hù)信息
- 處理每次請(qǐng)求時(shí),都要根據(jù)憑證查詢(xún)用戶(hù)信息,訪(fǎng)問(wèn)的頻率非常高。
緩存用戶(hù)信息:因?yàn)闀?huì)經(jīng)常根據(jù)userid來(lái)查詢(xún)user對(duì)象,所以使用redis來(lái)緩存提高服務(wù)器性能。使用redis的String類(lèi)型,存入user對(duì)象,會(huì)自動(dòng)將整個(gè)對(duì)象轉(zhuǎn)換成json字符串,同時(shí)設(shè)置過(guò)期時(shí)間;
取值:優(yōu)先從redis中取,取不到的時(shí)候從mysql中取,并將數(shù)據(jù)初始化到redis中
更新:更新的時(shí)候先更新mysql中的值,然后清除緩存數(shù)據(jù);
// 1.優(yōu)先從緩存中取值private User getCache(int userId) {String redisKey = RedisKeyUtil.getUserKey(userId);return (User) redisTemplate.opsForValue().get(redisKey);}// 2.取不到時(shí)初始化緩存數(shù)據(jù)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.數(shù)據(jù)變更時(shí)清除緩存數(shù)據(jù)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;}?
總結(jié)
以上是生活随笔為你收集整理的redis——对项目的一些优化方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 单调队列优化的背包问题
- 下一篇: leetcode322 零钱兑换