【SpringBoot篇】詳解基于Redis實現短信登錄的操作

文章目錄

  • 🥰前言
  • 🛸StringRedisTemplate
    • 🌹使用StringRedisTemplate
      • ?常用的方法
  • 🛸為什么我們要使用Redis代替Session進行登錄操作
    • 🎆具體使用
      • ?編寫攔截器
      • ?配置攔截器
      • 🌺基于Redis實現發送手機驗證碼操作
        • 🎈總體思路
        • 🎈具體步驟
      • 🎍基于Redis實現短信登錄并注冊的操作
        • 🎈總體思路
        • 🎈具體步驟

在這里插入圖片描述

🥰前言

使用 Redis 進行登錄適用于以下情況:

  • 分布式系統:
    當系統需要支持多個節點的分布式部署時,使用 Redis 存儲登錄信息能夠更好地支持多節點間的共享和同步,確保用戶的登錄狀態能夠在整個系統中得到有效的傳遞和管理。
  • 高并發訪問:
    面對大規模的并發訪問,使用 Redis 可以提供更好的性能表現。Redis 是一個基于內存的高性能 Key-Value 數據庫,能夠更快速地讀取和寫入數據,因此適用于需要處理大量并發請求的場景。
  • 靈活的數據結構需求:
    如果系統需要根據業務需求選擇最佳的數據結構,并且對存儲和操作登錄信息有更多的靈活性,那么使用 Redis 將會是一個不錯的選擇。Redis 支持多種數據類型的存儲和操作,包括字符串、哈希表、列表、集合和有序集合等,能夠滿足不同的業務需求。
  • 需要持久化支持:
    如果系統需要對登錄信息進行持久化存儲,以防止數據丟失,Redis 的持久化功能可以很好地滿足這一需求。

總的來說,使用 Redis 進行登錄適用于需要支持分布式部署、面對高并發訪問、有靈活的數據結構需求以及需要持久化支持的系統場景。通過合理地利用 Redis 的特性,可以更好地滿足上述情況下的需求,提高系統的可擴展性、性能和穩定性。

雖然 Spring Boot 應用通常是單體應用,但是在實際運行中,我們也經常會遇到多個實例同時運行的情況,這時候就需要使用 Redis 進行分布式 Session 管理。

🛸StringRedisTemplate

StringRedisTemplate是Spring Data Redis提供的一個類,它是一個具體的對象,用于操作Redis數據庫中的字符串類型數據。

StringRedisTemplate封裝了Redis的操作,并提供了一系列方法來對Redis中的字符串進行讀取、寫入和刪除操作。它是RedisTemplate的一個子類,專門用于處理字符串類型的數據。

🌹使用StringRedisTemplate

首先引入依賴,引入StringRedisTemplate的依賴

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

?常用的方法

StringRedisTemplate提供了多個方法來操作Redis中的字符串類型數據。下面是一些常用的方法:

  • opsForValue().set(key, value):將一個字符串類型的值value存儲到Redis中,并指定鍵key。
  • opsForValue().get(key):根據鍵key獲取對應的字符串類型的值。
  • opsForValue().increment(key, delta):將鍵key所對應的值增加delta,delta可以為負數。
  • opsForValue().size(key):獲取值的長度。

🛸為什么我們要使用Redis代替Session進行登錄操作

集群session存在共享問題,會導致數據丟失

  • 保存相同的數據,大家互相copy,會有內存空間的浪費
  • 我們copy數據的時候,是需要有一定的時間的,會有延遲,如果在這個延遲之內,如果有人來訪問,仍然會造成數據不一致的情況
    請添加圖片描述
    如果我們使用Redis的話。
  • Redis是在tomcat外面的存儲,如果任意一臺tomcat都能訪問到Redis,可以實現數據共享,儲存在Redis里面的數據,任何tomcat都可以看到,使用就不存在數據丟失的問題
  • Redis讀寫延遲非常低,方便進行內存存儲
  • Redis是key-value結構

在這里插入圖片描述

🎆具體使用

?編寫攔截器

在這里插入圖片描述

RefreshTokenInterceptor.java
在這里插入圖片描述

在攔截器中配置攔截操作

package com.hmdp.utils;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.hmdp.dto.UserDTO;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;import static com.hmdp.utils.RedisConstants.LOGIN_USER_KEY;
import static com.hmdp.utils.RedisConstants.LOGIN_USER_TTL;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();}
}

在這里插入圖片描述

刷新token的目的

用戶每訪問一次,這個token就會刷新一次,主要用戶一直在操作,這個token就不會消失


但是如果僅僅攔截的是需要登錄的路徑,用戶 訪問 不需要登錄 的路徑 的時候(比如首頁),這個攔截器就不生效,此時token就不會刷新,這樣子,過了token的有效期后,盡管用戶還在訪問,用戶的登錄狀態卻消失了,這樣肯定不太合理

那么我們就需要在原來的攔截器基礎上再加上一個攔截器
請添加圖片描述

LoginInterceptor.java
在這里插入圖片描述

在攔截器中配置攔截操作

package com.hmdp.utils;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;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;}
}

在這里插入圖片描述

?配置攔截器

我們上面編寫了攔截器,我們還需要配置攔截器,使這個攔截器生效

MvcConfig.java
這里是引用

package com.hmdp.config;import com.hmdp.utils.LoginInterceptor;
import com.hmdp.utils.RefreshTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource;@Configuration
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 登錄攔截器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);}
}

在這里插入圖片描述

🌺基于Redis實現發送手機驗證碼操作

🎈總體思路

在這里插入圖片描述

🎈具體步驟

我們首先引入上面說的依賴,然后在application.yml文件(或yaml文件)中進行配置,如下
在這里插入圖片描述

下面我們編寫發送手機驗證碼的核心代碼

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic Result sendCode(String phone, HttpSession session) {// 1.校驗手機號if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合,返回錯誤信息return Result.fail("手機號格式錯誤!");}// 3.符合,生成驗證碼String code = RandomUtil.randomNumbers(6);// 4.保存驗證碼到 redisstringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);// 5.發送驗證碼log.debug("發送短信驗證碼成功,驗證碼:{}", code);// 返回okreturn Result.ok();}
}

在這里插入圖片描述

上面代碼里面的RegexUtils.isPhoneInvalid(phone)這段代碼是什么用法

在這里插入圖片描述

stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);這段代碼有什么用

這段代碼的作用是將一個驗證碼(即code)存儲到Redis中,并設置了過期時間為LOGIN_CODE_TTL分鐘。以便在一定時間后自動刪除該鍵值對。

🎍基于Redis實現短信登錄并注冊的操作

🎈總體思路

在這里插入圖片描述

🎈具體步驟

我們首先引入上面說的依賴,并且在application.yml文件(或yaml文件)中進行配置(同上)
然后我們來編寫核心代碼

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic 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);}private User createUserWithPhone(String phone) {// 1.創建用戶User user = new User();user.setPhone(phone);user.setNickName(USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));// 2.保存用戶save(user);return user;}}

在這里插入圖片描述
User user = query().eq(“phone”, phone).one();這段代碼使用了mybatisplus,相當于select * from tb_user where phone = ?

為什么要使用HashMap進行存儲

在這段代碼中,使用HashMap進行存儲是為了將用戶對象轉換成鍵值對形式,便于統一保存到Redis中,并且可以方便地進行序列化和反序列化操作。具體來說:

  • 便于存儲和讀取:將用戶對象轉為HashMap后,可以方便地通過stringRedisTemplate.opsForHash().putAll()方法一次性將整個用戶對象存儲到Redis的Hash數據結構中,而不需要對用戶對象的每個字段分別進行存儲。
  • 數據結構清晰:使用HashMap可以清晰地表示用戶對象的各個字段和對應的數值,便于管理和維護。
  • 方便序列化和反序列化:HashMap作為Java中的常用數據結構,可以方便地進行序列化(將數據轉換為字節序列)反序列化(將字節序列轉換為數據)操作,便于在存儲到Redis或者從Redis中讀取時進行數據格式的轉換。

總之,使用HashMap進行存儲能夠簡化代碼邏輯,提高數據存儲和讀取的效率,并且方便進行數據結構的轉換和管理。

Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
這段代碼為什么要這樣寫,這些參數有什么用

其中,beanToMap是一個方法,用于將Java對象(Bean)轉換為Map類型的數據結構。

在這段代碼中,BeanUtil.beanToMap()方法被使用,它是一個工具類方法,可以通過反射機制將Java對象的屬性和對應的值轉換為鍵值對形式,并存儲到一個Map對象中。

具體來說,beanToMap方法接收三個參數:

  • userDTO:表示要轉換的源對象,即需要將其轉換為Map的對象。

  • new HashMap<>():表示用于存儲轉換結果的目標HashMap對象,這里使用了一個新的空HashMap,用于接收轉換后的鍵值對數據。

  • CopyOptions.create().setIgnoreNullValue(true):這是使用BeanUtil進行對象轉換時的配置選項。setIgnoreNullValue(true)表示忽略源對象中值為null的屬性,不將其放入目標Map中。

  • .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()):這個配置項表示對轉換過程中的字段值進行編輯處理。在這里,它的作用是將字段值轉換為字符串類型,確保最終存儲到Map中的值都是字符串類型。

綜合起來,這段代碼的目的是將UserDTO對象轉換為Map類型,同時忽略空值屬性,并確保所有屬性值都被轉換為字符串類型。這樣做的原因可能是為了在存儲到Redis中時,確保數據的統一性和一致性,便于后續從Redis中讀取并進行處理。

在技術的道路上,我們不斷探索、不斷前行,不斷面對挑戰、不斷突破自我。科技的發展改變著世界,而我們作為技術人員,也在這個過程中書寫著自己的篇章。讓我們攜手并進,共同努力,開創美好的未來!愿我們在科技的征途上不斷奮進,創造出更加美好、更加智能的明天!

在這里插入圖片描述

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

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

相關文章

EarCMS 前臺任意文件上傳漏洞復現

0x01 產品簡介 EarCMS是一個APP內測分發系統的平臺。 0x02 漏洞概述 EarCMS前臺put_upload.php中,存在pw參數硬編碼問題,同時sql語句pdo使用錯誤,沒有有效過濾sql語句,可以控制文件名和后綴,導致可以任意文件上傳。 0x03 復現環境 FOFA:app="EearCMS" 0x0…

Flutter實現自定義二級列表

在Flutter開發中&#xff0c;其實系統已經給我們提供了一個可靠的二級列表展開的API&#xff08;ExpansionPanelList&#xff09;&#xff0c;我們先看系統的二級列表展開效果&#xff0c;一次只能展開一個&#xff0c;用ExpansionPanelList.radio實現 由此可見&#xff0c;已經…

容器化升級對服務有哪些影響?

容器技術是近幾年計算機領域的熱門技術&#xff0c;特別是隨著各種云服務的發展&#xff0c;越來越多的服務運行在以 Docker 為代表的容器之內。 本文我們就來分享一下容器化技術相關的知識。 容器化技術簡介 相比傳統虛擬化技術&#xff0c;容器技術是一種更加輕量級的操作…

分治法求最大子列和

給定N個整數的序列{ A1, A2, …, AN}&#xff0c;其中可能有正數也可能有負數&#xff0c;找出其中連續的一個子數列&#xff08;不允許空序列&#xff09;&#xff0c;使它們的和盡可能大&#xff0c;如果是負數&#xff0c;則返回0。使用下列函數&#xff0c;完成分治法求最大…

CorelDRAW軟件2024版本好用嗎?有哪些功能優勢

CorelDRAW是一款綜合性強大的專業平面設計軟件&#xff0c;其功能覆蓋了矢量圖形設計、高級文字編輯、精細繪圖以及多頁文檔和頁面設計。該軟件不僅適用于廣告設計、包裝設計&#xff0c;還廣泛應用于出版、網頁設計和多媒體制作等多個領域。下面就給大家介紹一下CorelDRAW這款…

0012Java安卓程序設計-ssm記賬app

文章目錄 **摘要**目 錄系統設計5.1 APP端&#xff08;用戶功能&#xff09;5.2后端管理員功能模塊開發環境 編程技術交流、源碼分享、模板分享、網課分享 企鵝&#x1f427;裙&#xff1a;776871563 摘要 網絡的廣泛應用給生活帶來了十分的便利。所以把記賬管理與現在網絡相…

arkts編譯報錯-arkts-limited-stdlib錯誤【Bug已完美解決-鴻蒙開發】

文章目錄 項目場景:問題描述原因分析:解決方案:適配指導案例此Bug解決方案總結項目場景: arkts編譯報錯-arkts-limited-stdlib錯誤。 我用Deveco studio4.0 beta2開發應用,報arkts-limited-stdlib錯誤 報錯內容為: ERROR: ArKTS:ERROR File: D:/prRevivw/3792lapplica…

[Verilog]用Verilog實現串并轉換/并串裝換

用Verilog實現串并轉換/并串裝換 摘要 一、串并轉換模塊 串轉并就是將低3位信號和輸入信號一起賦值。因為經過轉換后&#xff0c;碼元速率會將為原來四分之一&#xff0c;所以設置4分頻時鐘&#xff0c;將其輸出。而并轉串就是不斷右移&#xff0c;取高位輸出。 module serial…

Android 11.0 systemui鎖屏頁面時鐘顯示樣式的定制功能實現

1.前言 在11.0的系統ROM定制化開發中,在進行systemui的相關開發中,當開機完成后在鎖屏頁面就會顯示時間日期的功能,由于 開發產品的需求要求時間顯示周幾上午下午接下來就需要對鎖屏顯示時間日期的相關布局進行分析,然后實現相關功能 效果圖如圖: 2.systemui鎖屏頁面時鐘顯…

mysql原理--B+樹索引

1.沒有索引的查找 1.1.在一個頁中的查找 (1). 以主鍵為搜索條件 可以在 頁目錄 中使用二分法快速定位到對應的槽&#xff0c;然后再遍歷該槽對應分組中的記錄即可快速找到指定的記錄。 (2). 以其他列作為搜索條件 這種情況下只能從 最小記錄 開始依次遍歷單鏈表中的每條記錄&am…

值得收藏的練習打字網站

本文對一些好用的練習打字的網站進行了匯總整理&#xff0c;方便大家使用 一&#xff1a;程序猿練習打字&#xff1a; 1.Typing Practice for Programmers http://Typing.io 是程序員的打字導師。它的練習課程基于開源代碼&#xff0c;讓你在不斷的練習中提升自己的碼字速度…

Python:核心知識點整理大全15-筆記

目錄 ?編輯 7.3.2 刪除包含特定值的所有列表元素 pets.py 7.3.3 使用用戶輸入來填充字典 mountain_poll.py 7.4 小結 第8章 函 數 8.1 定義函數 greeter.py 8.1.1 向函數傳遞信息 8.1.2 實參和形參 8.2.1 位置實參 2. 位置實參的順序很重要 8.2.2 關鍵字實參 往…

Ansible通過kubernetes.core.k8s_info和kubernetes.core.k8s訪問OCP

文章目錄 環境OCPClient&#xff08;Ansible控制節點&#xff09; 步驟準備工作在client端配置ssh免密登錄OCP端在client端安裝Ansible kubernetes.core.k8s_info第1次嘗試在OCP端安裝python和pip3在OCP端安裝kubernetes在OCP端安裝PyYAML第2次嘗試在OCP端配置config文件第3次嘗…

計算機循環神經網絡(RNN)

計算機循環神經網絡&#xff08;RNN&#xff09; 一、引言 循環神經網絡&#xff08;RNN&#xff09;是一種常見的深度學習模型&#xff0c;適用于處理序列數據&#xff0c;如文本、語音、時間序列等。RNN通過捕捉序列數據中的時間依賴關系和上下文信息&#xff0c;能夠解決很…

react Hooks之useId

當我們在編寫React組件時&#xff0c;有時需要為元素生成唯一的ID。這種情況經常出現在表單元素、標簽和用于無障礙性的目的上。React提供了一個名為useId的自定義Hook&#xff0c;它可以幫助我們生成唯一的ID。 1、作用&#xff1a; 用于生成一個唯一的 ID。這個 ID 可以用于…

CLIP的升級版Alpha-CLIP:區域感知創新與精細控制

為了增強CLIP在圖像理解和編輯方面的能力&#xff0c;上海交通大學、復旦大學、香港中文大學、上海人工智能實驗室、澳門大學以及MThreads Inc.等知名機構共同合作推出了Alpha-CLIP。這一創新性的突破旨在克服CLIP的局限性&#xff0c;通過賦予其識別特定區域&#xff08;由點、…

Could not resolve all dependencies for configuration ‘:app:androidApis‘.

android studio出現Could not resolve all dependencies for configuration ‘:app:androidApis’. 試過很多種方法&#xff0c;但是都不好使&#xff0c;不管怎么樣都是提示如下報錯&#xff1a; Using insecure protocols with repositories, without explicit opt-in, is un…

丹麥市場開發攻略,帶你走進童話王國

說起安徒生&#xff0c;大家多多少少都知道&#xff0c;因為小時候讀的安徒生童話書真的太有名了&#xff0c;但是大家可能不知道安徒生是丹麥的。丹麥是高度發達的國家&#xff0c;奉行自由貿易政策&#xff0c;市場潛力是非常不錯的&#xff0c;而且中國是丹麥非常重要的貿易…

Python部分基礎知識入門學習,十分鐘快速上手

文章目錄 一、基礎語法二、變量類型三、運算符四、條件語句關于Python技術儲備一、Python所有方向的學習路線二、Python基礎學習視頻三、精品Python學習書籍四、Python工具包項目源碼合集①Python工具包②Python實戰案例③Python小游戲源碼五、面試資料六、Python兼職渠道 一、…

這家消金公司業務調整,暫停合作產品貸款服務

來源 | 鐳射財經&#xff08;leishecaijing&#xff09; 曾為金美信重要的線上自營渠道之一&#xff0c;錢多美宣告謝幕。 「鐳射財經」注意到&#xff0c;金美信消費金融近期發布一則關于錢多美的業務調整公告&#xff0c;提及2023年12月15日起&#xff0c;旗下“錢多美App”…