黑馬點評-短信登錄業務

原理

模型如下

nginx

nginx基于七層模型走的事HTTP協議,可以實現基于Lua直接繞開tomcat訪問redis,也可以作為靜態資源服務器,輕松扛下上萬并發, 負載均衡到下游tomcat服務器,打散流量。

我們都知道一臺4核8G的tomcat,在優化和處理簡單業務的加持下,大不了就處理1000左右的并發。

經過nginx的負載均衡分流后,利用集群支撐起整個項目,同時nginx在部署了前端項目后,更是可以做到動靜分離,進一步降低tomcat服務的壓力,這些功能都得靠nginx起作用,所以nginx是整個項目中重要的一環。

數據存儲

在tomcat支撐起并發流量后,我們如果讓tomcat直接去訪問Mysql,根據經驗Mysql企業級服務器只要上點并發,一般是16或32 核心cpu,32 或64G內存,像企業級mysql加上固態硬盤能夠支撐的并發,大概就是4000起~7000左右。

所以我們在高并發場景下,會選擇使用mysql集群,同時為了進一步降低Mysql的壓力,同時增加訪問的性能,我們也會加入Redis,同時使用Redis集群使得Redis對外提供更好的服務。

登錄流程

首先用戶點發送驗證碼->驗證碼存入session

用戶點登錄或注冊->檢查+處理用戶信息->用戶信息存入session

用戶請求(攜帶cookie)->cookie中攜帶者JsessionId到后臺,后臺通過JsessionId從session中拿到用戶信息->檢查用戶是否存在來攔截

攔截功能

        //1.獲取sessionHttpSession session = request.getSession();//2.獲取session中的用戶Object user = session.getAttribute("user");//3.判斷用戶是否存在if(user == null){//4.不存在,攔截,返回401狀態碼response.setStatus(401);return false;}//5.存在,保存用戶信息到ThreadlocalUserHolder.saveUser((User)user);//6.放行return true;//攔截器registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot","/user/code","/user/login").order(1);// token刷新的攔截器registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);

Tomcat原理

當用戶發起請求時,會訪問我們像tomcat注冊的端口,任何程序想要運行,都需要有一個線程對當前端口號進行監聽,tomcat也不例外。當監聽線程知道用戶想要和tomcat連接連接時,那會由監聽線程創建socket連接,socket都是成對出現的,用戶通過socket互相傳遞數據。

當tomcat端的socket接受到數據后,此時監聽線程會從tomcat的線程池中取出一個線程執行用戶請求。

我們的服務部署到tomcat后,線程會找到用戶想要訪問的工程,然后用這個線程轉發到工程中的controller,service,dao中,并且訪問對應的DB。

在用戶執行完請求后,再統一返回,再找到tomcat端的socket,再將數據寫回到用戶端的socket,完成請求和響應。

隱藏敏感信息

核心思路就是寫一個UserDto對象,這個UserDto對象就沒有敏感信息了,我們在返回前,將有用戶敏感信息的User對象轉化成沒有敏感信息的UserDto對象

    public static void saveUser(UserDTO user){tl.set(user);}public static UserDTO getUser(){return tl.get();}public static void removeUser(){tl.remove();}//保存用戶信息到session中session.setAttribute("user", BeanUtils.copyProperties(user,UserDTO.class));//存在,保存用戶信息到ThreadlocalUserHolder.saveUser((UserDTO) user);

Redis代替session

由于在第二臺服務器上,沒有第一臺服務器存放的session

早期的方案是session拷貝,就是說雖然每個tomcat上都有不同的session,但是每當任意一臺服務器的session修改時,都會同步給其他的Tomcat服務器的session

這樣會造成每臺服務器中都有完整的一份session數據,服務器壓力過大,下面用redis優化

session是每個用戶都有自己的session,但是redis的key是共享的,因此可以解決session共享問題

在設計這個key的時候,需要滿足key具有唯一性且方便攜帶,選擇在后臺生成一個隨機串token

@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {// 1.校驗手機號String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合,返回錯誤信息return Result.fail("手機號格式錯誤!");}// 3.從redis獲取驗證碼并校驗String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if (cacheCode == null || !cacheCode.equals(code)) {// 不一致,報錯return Result.fail("驗證碼錯誤");}// 4.一致,根據手機號查詢用戶 select * from tb_user where phone = ?User user = query().eq("phone", phone).one();// 5.判斷用戶是否存在if (user == null) {// 6.不存在,創建新用戶并保存user = createUserWithPhone(phone);}// 7.保存用戶信息到 redis中// 7.1.隨機生成token,作為登錄令牌String token = UUID.randomUUID().toString(true);// 7.2.將User對象轉為HashMap存儲UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));// 7.3.存儲String tokenKey = LOGIN_USER_KEY + token;stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);// 7.4.設置token有效期stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.返回tokenreturn Result.ok(token);
}

登錄狀態刷新

由于攔截器綁定了刷新登錄token令牌的存活時間,如果當前用戶訪問了一些不需要攔截的路徑,那么這個攔截器就不會生效,所以此時令牌刷新的動作實際上就不會執行。

當前方案如下:

解決方案:添加一個攔截器,在第一個攔截器中攔截所有的路徑,把第二個攔截器做的事情放入到第一個攔截器中,同時刷新令牌,因為第一個攔截器有了threadLocal的數據,所以此時第二個攔截器只需要判斷攔截器中的user對象是否存在即可。

// 第一個攔截器
public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.獲取請求頭中的tokenString token = request.getHeader("authorization");if (StrUtil.isBlank(token)) {return true;}// 2.基于TOKEN獲取redis中的用戶String key  = LOGIN_USER_KEY + token;Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);// 3.判斷用戶是否存在if (userMap.isEmpty()) {return true;}// 5.將查詢到的hash數據轉為UserDTOUserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// 6.存在,保存用戶信息到 ThreadLocalUserHolder.saveUser(userDTO);// 7.刷新token有效期stringRedisTemplate.expire(key, LOGIN_USER_TTL, TimeUnit.MINUTES);// 8.放行return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 移除用戶UserHolder.removeUser();}
}// 第二個攔截器
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 1.判斷是否需要攔截(ThreadLocal中是否有用戶)if (UserHolder.getUser() == null) {// 沒有,需要攔截,設置狀態碼response.setStatus(401);// 攔截return false;}// 有用戶,則放行return true;}
}

總結

這節主要分析了項目的整體架構,redis部分處理了短信驗證碼和登錄狀態驗證(代替session)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718385.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡問題排查必備利器:Pingmesh

背景 當今的數字化世界離不開無處不在的網絡連接。無論是日常生活中的社交媒體、電子商務&#xff0c;還是企業級應用程序和云服務&#xff0c;我們對網絡的依賴程度越來越高。然而&#xff0c;網絡的可靠性和性能往往是一個復雜的問題&#xff0c;尤其是在具有大規模分布式架…

21.Prometheus的查詢數據類API

平凡也就兩個字: 懶和惰; 成功也就兩個字: 苦和勤; 優秀也就兩個字: 你和我。 跟著我從0學習JAVA、spring全家桶和linux運維等知識,帶你從懵懂少年走向人生巔峰,迎娶白富美! 關注微信公眾號【 IT特靠譜 】,每天都會分享技術心得~ 1.數據查詢類API 1.1.API前綴路徑說明 …

lanqiao:42點

題解&#xff1a; 1.首先&#xff0c;把字符轉成數字。 2.創建二維數組存放枚舉的結果&#xff0c;第一行一個數字13&#xff1b;第二行4個數字&#xff0c;分別是13和1的加減乘除&#xff1b;第三行16個數字&#xff0c;分別是第二行的每個數和12加減乘除的結果&#xff1b;…

基于SpringBoot的在線拍賣系統

目錄 1、 前言介紹 2、主要技術 3、系統流程和邏輯 4、系統結構設計 5、數據庫設計表 6、運行截圖(部分) 6.1管理員功能模塊 6.2用戶功能模塊 6.3前臺首頁功能模塊 7、源碼獲取 基于SpringBoot的在線拍賣系統錄像 1、 前言介紹 隨著社會的發展&#xff0c;社會的各行…

安卓玩機工具推薦----ADB狀態讀寫分區 備份分區 恢復分區 查看分區號 工具操作解析

在以往玩機過程中。很多機型備份分區 備份固件需要借助adb手動指令或者第三方手機軟件或者特定的一些工具來操作。有些朋友需要查看當前機型分區名稱和對應的分區號。此類操作我前面的博文專門說過對應的adb指令。但有些界面化的工具比較方便簡單。 相關分區同類博文&#xff…

【C++】每周一題——2024.3.3(手滑再再寫一篇)

題目 Cpp 【問題描述】 求N個字符串的最長公共子串&#xff0c;2 < N&#xff1c;&#xff1d;20&#xff0c;字符串長度不超過255。 例如&#xff1a;N&#xff1d;3&#xff0c;由鍵盤依次輸入三個字符串為 What is local bus? Name some local buses. local bus is a h…

SpringBoot源碼解讀與原理分析(三十七)SpringBoot整合WebMvc(二)DispatcherServlet的工作全流程

文章目錄 前言12.4 DispatcherServlet的工作全流程12.4.1 DispatcherServlet#service12.4.2 processRequest12.4.3 doService12.4.3.1 isIncludeRequest的判斷12.4.3.2 FlashMapManager的設計 12.4.4 doDispatch12.4.4.1 處理文件上傳請求12.4.4.2 獲取可用的Handler&#xff0…

sscanf 函數的用法

sscanf 函數是 C 語言標準庫 <stdio.h> 中的一個函數&#xff0c;用于按照指定的格式從一個字符串中讀取輸入。它的用法類似于 scanf 函數&#xff0c;但是 sscanf 從字符串中讀取輸入&#xff0c;而不是從標準輸入&#xff08;鍵盤&#xff09;中讀取輸入。 以下是 ssc…

優優嗨聚集團:美團代運營服務,商家增長的新引擎

在當今數字化時代&#xff0c;線上平臺已成為商家拓展業務、提升品牌影響力的重要渠道。美團作為國內領先的本地生活服務平臺&#xff0c;擁有龐大的用戶群體和豐富的商業資源。然而&#xff0c;對于許多商家而言&#xff0c;如何在美團平臺上進行有效運營&#xff0c;實現業務…

Redis做分布式鎖如何處理超時時間?

在使用Redis實現分布式鎖時&#xff0c;處理超時時間是非常重要的&#xff0c;以確保在獲取鎖的客戶端在一定時間內未能完成任務時&#xff0c;鎖能夠自動釋放&#xff0c;避免造成死鎖或長時間的阻塞。下面是一種處理超時時間的方法&#xff1a; 獲取鎖時設置超時時間&#xf…

雙線服務器有哪些安全防御措施?

雙線服務器的出現給企業帶來了更廣泛的業務發展&#xff0c;用戶不再是固定的群體&#xff0c;而是有了一定的選擇性&#xff0c;服務器的性能與可靠性進行了增強&#xff0c;使網絡的運行速度變得更加流暢&#xff0c;給用戶帶來了良好的體驗感。 今天我們主要就來聊一聊雙線服…

【IOS】啟動報錯Cannot launch ‘/private/var/containers/Bundle/Application/....‘

問題 IOS項目啟動報錯Cannot launch ‘/private/var/containers/Bundle/Application/***.app’: Sending qLaunchSuccess packet failed 或者類似報錯問題 無法啟動launch的 解決 問題定位 我是在操作期間更換了應用的簽名證書 也就是Signing & Capablities -> Sign…

【LeetCode:232. 用棧實現隊列 + 棧 | 隊列】

&#x1f680; 算法題 &#x1f680; &#x1f332; 算法刷題專欄 | 面試必備算法 | 面試高頻算法 &#x1f340; &#x1f332; 越難的東西,越要努力堅持&#xff0c;因為它具有很高的價值&#xff0c;算法就是這樣? &#x1f332; 作者簡介&#xff1a;碩風和煒&#xff0c;…

力扣74. 搜索二維矩陣(二分查找)

Problem: 74. 搜索二維矩陣 文章目錄 題目描述思路復雜度Code 題目描述 思路 思路1&#xff1a;映射為一維數組二分查找 1.由于題目矩陣中的元素整體是升序的&#xff0c;我們可以將其放置在一個大小為 m n m \times n mn的一維數組array中進行二分查找 2.對應的映射關系是ar…

NACOS在Windows和Linux下的安裝教程

目錄 1、Windows安裝 1.1、下載安裝包 1.2、解壓 1.3、端口配置 1.4、啟動 1.5、訪問 2、Linux安裝 2.1、安裝JDK 2.2、上傳安裝包 2.3、解壓 2.4、端口配置 2.5、啟動 3、Nacos的依賴 1、Windows安裝 開發階段采用單機安裝即可。 1.1、下載安裝包 在Nacos的Git…

Vue+SpringBoot打造圖書借閱系統

目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、功能模塊2.1 登陸注冊模塊2.2 圖書管理模塊2.3 圖書評論模塊2.4 圖書預定模塊2.5 圖書資訊模塊 三、系統設計3.1 系統結構設計3.1.1登陸注冊模塊的結構設計3.1.2圖書管理模塊的結構設計3.1.3圖書評論模塊的結構設計3.1.4圖書預定模塊…

clickhouse 隨心所欲的聚合模型-AggregatingMergeTree

clickhouse 強大的 MergeTree 系列引擎令人信服&#xff0c;其 ReplacingMergeTree、SummingMergeTree 在數據唯一性和匯總場景中表現非凡。但你是否還有保留最小(大)、平均等預聚合需求&#xff0c;甚至在一個模型中既有唯一性語意也有匯總、最小、最大、平均值語意該如何處理…

Spring-靜態代理VS動態代理/實現代理ProxyFactory

文章目錄 靜態代理VS動態代理Spring實現代理ProxyFactory 工作中遇到問題整理動態代理異常com.sun.proxy.$Proxy0 cannot be cast to 靜態代理VS動態代理 靜態代理VS動態代理 參考URL: https://blog.csdn.net/qq_25881443/article/details/103245938 【java項目實戰】代理模式…

【C語言】剖析qsort函數的實現原理

主頁&#xff1a;17_Kevin-CSDN博客 專欄&#xff1a;《C語言》 本文將從回調函數&#xff0c;qsort函數的應用&#xff0c;qsort函數的實現原理三個方面進行講解&#xff0c;請自行跳轉至相對位置進行閱讀~ 目錄 回調函數 qsort函數的應用 qsort函數實現原理 回調函數 什…

mysql主從庫Slave_SQL_Running: No問題經驗分享

最近在創建mysql主從庫的時候&#xff0c;遇到一個問題。執行 mysql> SHOW SLAVE STATUS\G結果顯示 Slave_IO_Running: Yes Slave_SQL_Running: No 很是苦惱&#xff0c;查詢了很久沒有解決 執行 mysql> SELECT * FROM performance_schema.replication_applier_status_…