需求说明:

现有一个游戏后台管理系统,该系统可管理多个大区的数据,但是需要使用大区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: 布隆过滤器方案…