黑馬點評day01(基于Redis)

1.7 Redis代替session的業務流程
1.7.1、設計key的結構

首先我們要思考一下利用redis來存儲數據,那么到底使用哪種結構呢?由于存入的數據比較簡單,我們可以考慮使用String,或者是使用哈希,如下圖,如果使用String,同學們注意他的value,用多占用一點空間,如果使用哈希,則他的value中只會存儲他數據本身,如果不是特別在意內存,其實使用String就可以啦。

哈希表(Hash Table)

也叫散列表。

它是一種根據關鍵碼值(Key value)而直接進行訪問的數據結構。它通過一個哈希函數將關鍵碼映射到表中的一個位置來訪問記錄,以加快查找的速度。在理想情況下,不發生沖突時,可以實現常數時間復雜度的查找、插入和刪除等操作。

img

1.7.2、設計key的具體細節

所以我們可以使用String結構,就是一個簡單的key,value鍵值對的方式,但是關于key的處理,session他是每個用戶都有自己的session,但是redis的key是共享的,咱們就不能使用code了

在設計這個key的時候,我們之前講過需要滿足兩點

1、key要具有唯一性

2、key要方便攜帶

采用token作為key的原因

如果我們采用phone:手機號這個的數據來存儲當然是可以的,但是如果把這樣的敏感數據存儲到redis中并且從頁面中帶過來畢竟不太合適,所以我們在后臺生成一個隨機串token,然后讓前端帶來這個token就能完成我們的整體邏輯了

1.7.3、整體訪問流程

當注冊完成后,用戶去登錄會去校驗用戶提交的手機號和驗證碼,是否一致,如果一致,則根據手機號查詢用戶信息,不存在則新建,最后將用戶數據保存到redis,,并且生成token作為redis的key,當我們校驗用戶是否登錄時,會去攜帶著token進行訪問,從redis中取出token對應的value,判斷是否存在這個數據,如果沒有則攔截,如果存在則將其保存到threadLocal中,并且放行。

img

1.8 基于Redis實現短信登錄

這里具體邏輯就不分析了,之前咱們已經重點分析過這個邏輯啦。

DTO:數據傳輸對象data transfer Object

? 代碼——Redis實現短信登錄
@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);
}
1.9 解決狀態登錄刷新問題
1.9.1 初始方案思路總結:

在這個方案中,他確實可以使用對應路徑的攔截,同時刷新登錄token令牌的存活時間,但是現在這個攔截器他只是攔截需要被攔截的路徑,假設當前用戶訪問了一些不需要攔截的路徑,那么這個攔截器就不會生效,所以此時令牌刷新的動作實際上就不會執行,所以這個方案他是存在問題的

img

1.9.2 優化方案

既然之前的攔截器無法對不需要攔截的路徑生效,那么我們可以再添加一個攔截器(沒有什么是再加一層解決不了的),在第一個攔截器中攔截所有的路徑,把第二個攔截器做的事情放入到第一個攔截器中,同時刷新令牌,因為第一個攔截器有了threadLocal的數據,所以此時第二個攔截器只需要判斷攔截器中的user對象是否存在即可,完成整體刷新功能。

攔截器:

攔截器就是在請求流轉的過程中,在特定的節點(比如請求到達某個資源或方法之前、之后等)進行統一的、預先定義好的處理操作。

它可以對請求進行一些共性的操作和控制,比如驗證、轉換、添加額外信息等,就像一個關卡對經過的請求進行特定的“盤查”或“加工”,這種理解是比較準確的。

img

1.9.3 代碼
? 代碼——RefreshTokenInterceptor
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();}
}
? 代碼——LoginInterceptor
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;}
}

之后再在MVC的配置層加上攔截器的配置就好:

@Configuration
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// token刷新的攔截器//先對所有的操作都加一層刷新token的動作。這樣用戶即使是在-逛一些不需要驗證登錄身份的模塊(如首頁等),都會將token刷新,這樣只要用戶在操作,那么就一直有30min的過期時間等待耗盡registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);// 登錄攔截器// 這里僅僅將需要用戶進行身份驗證的模塊進行攔截處理。就是驗證用戶是否登錄。registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/shop/**","/voucher/**","/shop-type/**","/upload/**","/blog/hot","/user/code","/user/login").order(1);}
}

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

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

相關文章

Python爬蟲實戰:獲取優美圖庫各類高清圖片,為用戶提供設計素材

一、引言 在互聯網時代,高清壁紙資源豐富多樣,而優美圖庫作為一個提供大量精美壁紙的網站,吸引了眾多用戶。通過 Python 爬蟲技術,可以自動化地從該網站獲取所需的壁紙資源,為用戶節省時間和精力。然而,網站通常會采取反爬措施來防止數據被惡意抓取,因此需要在爬蟲程序…

Go反射-通過反射調用結構體的方法(帶入參)

使用反射前&#xff0c;我們需要提前做好映射配置 papckage_struct_relationship.go package reflectcommonimport (api "template/api" )// 包名到包對象的映射 var structMap map[string]func() interface{}{"template/api": func() interface{} { re…

Git_.gitignore文件簡介及使用

.gitignore 這個文件的作用就是告訴Git哪些文件不需要添加到版本管理中。實際項目中&#xff0c;很多文件都是不需要版本管理的&#xff0c;比如Python的.pyc文件&#xff0c;Git會根據這個文件里配置的這些規則來判斷是否將文件添加到版本控制中。 注意&#xff0c;直接新建文…

HarmonyOS ArkUI安全控件開發指南:粘貼、保存與位置控件的實現與隱私保護實踐

目錄 安全控件1. 粘貼控件1.1 約束與限制1.2 開發步驟 2. 保存控件2.1 約束與限制2.2 開發步驟 3. 位置控件3.1 約束與限制3.2 開發步驟 安全控件 安全控件是系統提供的一組系統實現的ArkUI組件&#xff0c;其中保存控件在用戶首次使用時&#xff0c;會彈出通知彈窗&#xff0…

C++筆記之接口`Interface`

C++筆記之接口Interface code review! 一個簡潔簡短的 C++ 接口實現示例: #include <iostream>// 1. 定義接口(抽象類) class Shape {public:

動態圖表 -- eg1

問題&#xff1a; 前端vue&#xff0c;后端springboot&#xff0c;實現動態表格樣式&#xff0c;&#xff08;表格List<Student>&#xff0c;Student類有年級&#xff0c;班級&#xff0c;文理科分類&#xff0c;姓名&#xff0c;學號&#xff0c;等屬性。先根據年級分類…

C++學習之shell高級和正則表達式

目錄 1.正則表達式 2.C中使用正則 3.復習 4.sort命令 5.uniq命令 6.wc命令 7.grep命令 8.find命令 9.xargs命令 10.sed命令 11.awk命令 12.crontab 1.正則表達式 1 管道 使用| 將多個命令拼接在一起 原理&#xff0c;就是將前一個命令的標準輸出作為后一個…

【Vue】 實現TodoList案例(待辦事項)

目錄 組件化編碼流程&#xff08;通用&#xff09; 1.實現靜態組件&#xff1a;抽取組件&#xff0c;使用組件實現靜態頁面效果 2.展示動態數據&#xff1a; 1. 常規 HTML 屬性 3.交互——從綁定事件監聽開始 什么時候要用 event&#xff1a; 什么時候不需要用 event&am…

【Bootstrap V4系列】學習入門教程之 組件-卡片(Card)

Bootstrap V4系列 學習入門教程之 組件-卡片&#xff08;Card&#xff09; 卡片&#xff08;Card&#xff09;一、Example二、Content types 內容類型2.1 Body 主體2.2 Titles, text, and links 標題、文本和鏈接2.3 Images 圖片2.4 List groups 列表組2.5 Kitchen sink 洗滌槽…

java學習之數據結構:四、樹(代碼補充)

這部分主要是用代碼實現有序二叉樹、樹遍歷、刪除節點 目錄 1.構建有序二叉樹 1.1原理 1.2插入實現 2.廣度優先遍歷--隊列實現 3.深度優先遍歷--遞歸實現 3.1先序遍歷 3.2中序遍歷 3.3后序遍歷 4.刪除 4.1刪除葉子節點 4.2刪除有一棵子樹的節點 4.3刪除有兩棵子樹的節…

架構進階:什么是數據架構,如何理解數據架構?(華為)

數據架構是企業架構的重要組成部分,DAMA、IBM 及國內大廠對其定義各有側重。它包含數據資產目錄、數據標準、數據模型和數據分布四個組件。數據資產目錄可梳理企業數據資產,數據標準統一數據含義和規則,數據模型反映業務對象關聯關系,數據分布呈現數據流動情況。數據架構是…

Unity SpriteEditor(精靈圖片編輯器)

&#x1f3c6; 個人愚見&#xff0c;沒事寫寫筆記 &#x1f3c6;《博客內容》&#xff1a;Unity3D開發內容 &#x1f3c6;&#x1f389;歡迎 &#x1f44d;點贊?評論?收藏 &#x1f50e;SpriteEditor&#xff1a; 精靈圖片編輯器 &#x1f4cc;用于編輯2D游戲開發中使用的Sp…

【網絡原理】從零開始深入理解HTTP的報文格式(一)

本篇博客給大家帶來的是網絡HTTP協議的知識點, 重點介紹HTTP的報文格式. &#x1f40e;文章專欄: JavaEE初階 &#x1f680;若有問題 評論區見 ? 歡迎大家點贊 評論 收藏 分享 如果你不知道分享給誰,那就分享給薯條. 你們的支持是我不斷創作的動力 . 王子,公主請閱&#x1f68…

ElasticSearch深入解析(九):Object、Nested、Flattened類型

文章目錄 一、Object 類型&#xff1a;默認的嵌套對象處理方式核心原理典型場景關鍵限制 二、Nested 類型&#xff1a;解決嵌套數組的關聯查詢核心原理典型場景使用示例注意事項 三、Join 類型&#xff1a;跨文檔的父子關聯核心原理典型場景使用示例注意事項 四、Flattened 類型…

36、C#中的?法聲明參數關鍵字params,ref,out的意義及?法

在C#中&#xff0c;params、ref 和 out 是方法聲明中用于修飾參數的關鍵字&#xff0c;它們各自有不同的用途和語義。以下是它們的詳細說明和用法&#xff1a; 1、 params 關鍵字 意義 params 允許方法接受可變數量的參數&#xff0c;這些參數會被編譯為一個數組。適用于參數…

【大模型實戰篇】華為信創環境采用vllm部署QwQ-32B模型

1. 背景 本文分享在華為昇騰機器上部署QwQ-32B模型的實踐。 首先華為自己是提供了一套在信創機器&#xff08;NPU&#xff09;上部署模型的方案【1】&#xff0c;但是部署之后&#xff0c;測試發現會有輸出截斷的現象。QwQ-32B本身是支持128k的最大上下文長度&#xff0c;定位…

前端面經-VUE3篇(二)--vue3基礎知識(二)計算屬性(computed)、監聽屬性(Watch)

一、計算屬性(computed) 計算屬性&#xff08;Computed Properties&#xff09;是 Vue 中一種特殊的響應式數據&#xff0c;它能基于已有的響應式數據動態計算出新的數據。 計算屬性有以下特性&#xff1a; 自動緩存&#xff1a;只有當它依賴的響應式數據發生變化時&#xff…

[預備知識] 5. 優化理論(一)

優化理論 梯度下降&#xff08;Gradient Descent&#xff09; 數學原理與可視化 梯度下降是優化領域的基石算法&#xff0c;其核心思想是沿負梯度方向迭代更新參數。數學表達式為&#xff1a; θ t 1 θ t ? α ? θ J ( θ t ) \theta_{t1} \theta_t - \alpha \nabla…

大模型微調Fine-tuning:從概念到實踐的全面解析

目錄 引言 一、什么是大模型微調&#xff1f; 1.1 預訓練與微調的區別 1.2 微調的技術演進 二、為什么需要微調&#xff1f; 2.1 解決大模型的固有局限 2.2 微調的優勢 三、主流微調方法 3.1 全參數微調 3.2 參數高效微調&#xff08;PEFT&#xff09; 四、微調實踐指…

Docker 使用下 (二)

Docker 使用下 &#xff08;二&#xff09; 文章目錄 Docker 使用下 &#xff08;二&#xff09;前言一、初識Docker1.1 、Docker概述1.2 、Docker的歷史1.3 、Docker解決了什么問題1.4 、Docker 的優點1.5 、Docker的架構圖 二、鏡像三、容器四、數據卷4.1、數據卷的概念4.2 、…