SpringBoot ThreadLocal 全局動態變量設置

需求說明:

現有一個游戲后臺管理系統,該系統可管理多個大區的數據,但是需要使用大區id實現數據隔離,并且提供了大區選擇功能,先擇大區后展示對應的數據。需要實現一下幾點:
1.前端請求時,area_id是必傳的
1.數據隔離,包括查詢及增刪改:使用mybatis攔截器實現
2.多個用戶同時操作互不影響
3.非前端調用場景的處理:定時任務、mq

1.前端決定area_id

為了解決多個用戶可以互不影響的使用不同的area_id,因此采用前端傳遞area_id的方式。前端的area_id可以放在緩存中,調用接口時將數據塞入頭部中傳給接口,實現了不同瀏覽器之間area_id互不影響的方式

ThreadLocal叫做線程變量,意思是ThreadLocal中填充的變量屬于當前線程,該變量對其他線程而言是隔離的,也就是說該變量是當前線程獨有的變量。ThreadLocal為變量在每個線程中都創建了一個副本,那么每個線程可以訪問自己內部的副本變量。
簡單來說就是,一個ThreadLocal在一個線程中是共享的,在不同線程之間又是隔離的,即每個線程都只能看到自己線程的值

2.ThreadLocal

接口接收到頭部中的area_id后,將其設置到ThreadLocal中,以保證在整個請求的線程中都可以獲取到該值。
并且為了防止內存泄漏及數據錯亂問題,需要在請求結束時清除ThreadLocal。

3.請求攔截器

使用攔截器實現一下幾個步驟:
(1)校驗頭部area_id,保證請求時改參數必傳
(2)對頭部area_id的獲取、ThreadLocal設置、ThreadLocal清除,這樣可以保證每次請求時都會使用頭部中area_id

package org.jeecg.modules.game.config.area;import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 游戲區id攔截器* @author: sxd* @date: 2025-02-06 13:56**/
@Component
public class AreaIdInterceptor implements HandlerInterceptor {@Autowiredprivate AreaIdHolder areaIdHolder;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String areaId = request.getHeader(CommonConstant.GAME_AREA_ID);if (StringUtils.isEmpty(areaId)) {throw new JeecgBootException("請先指定游戲大區");}areaIdHolder.setAreaId(Long.parseLong(areaId));return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 清理ThreadLocal,防止內存泄露areaIdHolder.remove();}}
package org.jeecg.modules.game.config.area;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 注冊攔截器* @author: sxd* @date: 2025-02-06 14:14**/
@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate AreaIdInterceptor areaIdInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(areaIdInterceptor).addPathPatterns("/**").excludePathPatterns("/game/area/areaSave", "/game/area/areaServerTree", "/game/common/changeArea");}
}
package org.jeecg.modules.game.config.area;import org.springframework.stereotype.Component;/*** @author: sxd* @date: 2025-02-06 14:18**/
@Component
public class AreaIdHolder {private static final ThreadLocal<Long> areaIdHolder = new ThreadLocal<>();public void setAreaId(Long gameId) {areaIdHolder.set(gameId);}public Long getAreaId() {return areaIdHolder.get();}public void remove() {areaIdHolder.remove();}
}

4.mybatis攔截器

mybatis plus配置:目的是在指定的數據表操作中,在條件中自動追加條件,即area_id
同時ignoreTable方法中設置無需攔截的數據表。并檢測當area_id不存在時,不進行攔截處理,以兼容非前端請求時沒有area_id的情況,如定時任務、mq消費

package org.jeecg.modules.game.config.area;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author sxd*/
@Configuration
public class MybatisPlusConfig {@Autowiredprivate GameTenantLineHandler gameTenantLineHandler;@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor1() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(gameTenantLineHandler));return interceptor;}
}
package org.jeecg.modules.game.config.area;import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.stream.Collectors;/*** @author: sxd* @date: 2025-01-13 16:06**/
@Service
public class GameTableService {@Autowiredprivate AreaIdHolder gameIdHolder;public List<String> getGameModuleTableNames() {List<String> tableNames = TableInfoHelper.getTableInfos().stream().map(tableInfo -> tableInfo.getEntityType().getPackage().getName()).filter(packageName -> packageName.startsWith("org.jeecg.modules.game.entity")).distinct().flatMap(packageName -> TableInfoHelper.getTableInfos().stream().filter(tableInfo -> tableInfo.getEntityType().getPackage().getName().equals(packageName)).map(tableInfo -> tableInfo.getTableName())).collect(Collectors.toList());return tableNames;}
}
package org.jeecg.modules.game.config.area;import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;/*** @author: sxd* @date: 2025-01-13 15:53**/
@Component
public class GameTenantLineHandler implements TenantLineHandler {@Autowiredprivate AreaIdHolder gameIdHolder;@Autowiredprivate GameTableService gameTableService;@Overridepublic Expression getTenantId() {Long gameId = gameIdHolder.getAreaId();if (gameId == null) {return null;}return new LongValue(gameId);}@Overridepublic String getTenantIdColumn() {return "area_id";}/*** 返回 true 表示不走AreaId邏輯*/@Overridepublic boolean ignoreTable(String tableName) {// 沒有區域id則不會走自動在where種追加area_id的邏輯Long gameId = gameIdHolder.getAreaId();if (gameId == null) {return true;}// 忽略不需要添加 area_id 條件的表List<String> gameTableNames = gameTableService.getGameModuleTableNames();return !gameTableNames.contains(tableName) || Arrays.asList(new String[]{"game_area", "game_prop"}).contains(tableName);}
}

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

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

相關文章

如何解決pip安裝報錯ModuleNotFoundError: No module named ‘logging’問題

【Python系列Bug修復PyCharm控制臺pip install報錯】如何解決pip安裝報錯ModuleNotFoundError: No module named ‘logging’問題 摘要&#xff1a; 在使用 PyCharm 2025 控制臺通過 pip install 安裝第三方庫時&#xff0c;常會遇到諸如 ModuleNotFoundError: No module name…

打破技術債困境:從“保持現狀”到成為變革的推動者

相信許多在科技行業的同行都面臨過類似的挑戰&#xff1a;明知系統存在“技術債”&#xff0c;卻因為溝通成本、團隊壓力和短期KPI等原因&#xff0c;難以推動改進&#xff0c;最終陷入“想做卻不敢做”的矛盾心態。這不僅影響個人心情&#xff0c;更重要的是&#xff0c;它像一…

Spring Boot 整合 RabbitMQ

Spring Boot 整合 RabbitMQ 一、概述&#xff1a;RabbitMQ 是什么&#xff1f; 你可以把 RabbitMQ 想象成一個「快遞中轉站」。 比如你在網上買了一本書&#xff0c;賣家&#xff08;生產者&#xff09;把包裹&#xff08;消息&#xff09;交給快遞站&#xff08;RabbitMQ&…

Unity Demo-3DFarm詳解-其一

我們來拆解一個種田游戲&#xff0c;這個游戲種類內部的功能還是比較模板化的&#xff0c;我們來一點點說。我們大體上分為這么幾個部分&#xff1a;農場運營玩法角色與玩家互動物品與背包存檔和進度管理用戶界面系統農場運營可以大體上分為&#xff1a;種植系統&#xff1a;支…

esp8266驅動下載

問題描述&#xff1a;esp8266插上電腦&#xff0c;設備管理器無法識別&#xff0c;顯示為USB serial&#xff08;黃色感嘆號&#xff09; 首先確認你的esp8266是不是 CH340 系列的 USB 轉串口芯片 CH340驅動下載地址

大語言模型的極限:知識、推理與創造力的邊界探析

大語言模型的極限&#xff1a;知識、推理與創造力的邊界探析 人工智能領域的快速發展推動了大語言模型&#xff08;LLM&#xff09;的廣泛應用&#xff0c;這些模型在文本生成、知識問答和創意表達等方面展現出前所未有的能力。然而&#xff0c;隨著應用場景的深化&#xff0c;…

git中的fork指令解釋

在Git中&#xff0c;Fork 是指將他人的代碼倉庫&#xff08;Repository&#xff09;復制到自己的賬戶下&#xff0c;創建一個完全獨立的副本[1][2]。以下是關于Fork的詳細說明&#xff1a; Fork的定義與核心作用 定義&#xff1a;Fork是代碼托管平臺&#xff08;如GitHub&#…

iPhone 抓包工具有哪些?多工具對比分析優缺點

iOS 平臺一向以安全性著稱&#xff0c;這也使得對其進行網絡調試和抓包變得異常困難。相比安卓&#xff0c;iPhone 抓包難點主要在以下幾點&#xff1a; 系統限制代理設置的靈活性無法自由安裝根證書抓包常涉及 HTTPS 解密與雙向認證破解普通用戶設備無 root 或越獄權限 因此&a…

使用 libcu++ 庫

文章目錄使用 libcu 庫安裝與設置基本組件1. 原子操作2. 內存管理3. 類型特性4. 同步原語編譯選項注意事項使用 libcu 庫 libcu 是 NVIDIA 提供的 CUDA C 標準庫實現&#xff0c;它為 CUDA 開發者提供了類似 C 標準庫的功能和接口。以下是使用 libcu 的基本指南&#xff1a; …

[Leetcode] 預處理 | 多叉樹bfs | 格雷編碼 | static_cast | 矩陣對角線

魔術排列模擬一個特定的洗牌過程&#xff0c;并找到使得經過一系列洗牌和取牌操作后&#xff0c;能夠與給定的目標數組target相匹配的最小k值核心思想: 預處理初始排列&#xff1a;從一個按順序排列的數組&#xff08;例如&#xff0c;{1, 2, 3, ..., n}&#xff09;開始。洗牌…

【技術追蹤】SynPo:基于高質量負提示提升無訓練少樣本醫學圖像分割性能(MICCAI-2025)

SAM 新用法&#xff0c;無需訓練&#xff0c;利用高質量負提示提升分割性能~ 論文&#xff1a;SynPo: Boosting Training-Free Few-Shot Medical Segmentation via High-Quality Negative Prompts 代碼&#xff1a;https://liu-yufei.github.io/synpo-project-page/ 0、摘要 大…

深入理解機器學習

一.前言本章節開始來講解一下機器學習的知識&#xff0c;本期作為一個了解就大概介紹一下&#xff0c;我們不會從機器學習基礎開始介紹&#xff0c;但是后面會來補充&#xff0c;隨著ai的不斷發展&#xff0c;機器學習在ai的領域里面的占比越來約少&#xff0c;我們還是以應用為…

數據結構 順序表(1)

目錄 1.線性表 2.順序表 1.線性表 線性表&#xff08;linear list&#xff09;是n個具有相同特性的數據元素的有限序列。線性表是一種在實際中廣泛使用 的數據結構&#xff0c;常見的線性表&#xff1a;順序表、鏈表、棧、隊列、字符串… 線性表在邏輯上是線性結構&#…

openssl 生成國密證書

openssl生成證書生成CA私鑰 openssl ecparam -genkey -name SM2 -out ca.key.pem -noout證書請求 openssl req -new -key ca.key.pem -out ca.cert.req -subj “/CNrtems-strongswan-CA”生成證書 openssl x509 -req -days 3650 -in ca.cert.req -signkey ca.key.pem -out ca.c…

系統架構設計師論文分享-論分布式事務技術及其應用

我的軟考歷程 摘要 2023年9月&#xff0c;我所在的公司通過了研發紗線MES系統的立項&#xff0c;該系統為國內紗線工廠提供SAAS服務&#xff0c;旨在提高紗線工廠的數字化和智能化水平。我在該項目中擔任系統架構設計師一職&#xff0c;負責該項目的架構設計工作。本文結合我…

東土科技智能塔機系統亮相南京,助力智能建造高質量發展

近日&#xff0c;由南京市城鄉建設委員會、江蘇省土木建筑學會主辦的“無人駕駛智能塔機觀摩會”&#xff0c;在中建三局一公司南京揚子江智慧中心項目現場成功舉辦。作為全國首批智能建造試點城市&#xff0c;南京市已出臺20余項支持政策&#xff0c;落地93個試點項目&#xf…

3D Surface Reconstruction with Enhanced High-Frequency Details

3D Surface Reconstruction with Enhanced High-Frequency Details核心問題&#xff1a;當前基于神經隱式表示&#xff08;如 NeuS&#xff09;的 3D 表面重建方法&#xff0c;通常采用隨機采樣策略。這種隨機采樣難以充分捕捉圖像中的高頻細節區域&#xff08;如紋理、邊緣、光…

Science Robotics 耶魯大學開源視觸覺新范式,看出機器人柔性手的力感知

摘要&#xff1a;在機器人視觸覺傳感領域&#xff0c;如何兼顧成本與性能始終是一大挑戰。耶魯大學在《Science Robotics》上發表最新研究&#xff0c;提出了一種“Forces for Free”&#xff08;F3&#xff09;新范式。該研究通過觀測一個經過特殊優化的開源柔性手&#xff08…

關于java項目中maven的理解

我的理解&#xff1a;maven是java項目的依賴管理工具&#xff0c;通過pom.xml文件配置要下載的依賴&#xff0c;settings.xml配置maven下載的鏡像沒有就默認在maven中央倉庫下載依賴&#xff0c;本地倉庫是存儲下載好的依賴ai:1. 功能定位局限Maven 不只是依賴管理工具&#xf…

緩存三大問題詳解與工業級解決方案

文章目錄緩存三大問題詳解與工業級解決方案概念總覽問題詳解1. 緩存穿透 (Cache Penetration)問題描述典型場景危害2. 緩存擊穿 (Cache Breakdown)問題描述典型場景危害3. 緩存雪崩 (Cache Avalanche)問題描述典型場景危害工業級解決方案緩存穿透解決方案方案1: 布隆過濾器方案…