MyBatis-Plus如何优雅的配置多租户及分页
MyBatis-Plus如何优雅的配置多租户及分页
- 一、配置多租户
- 1、步骤一
- 2、步骤二
- 3、步骤三
- 步骤四
- 二、配置分页
- 1、步骤一
- 2、步骤二
- 3、步骤三
一、配置多租户
TenantLineInnerInterceptor
是 MyBatis-Plus
提供的一个插件,用于实现多租户的数据隔离。通过这个插件,可以确保每个租户只能访问自己的数据,从而实现数据的安全隔离。
1、步骤一
通过实现 TenantLineHandler
接口,处理租户相关的逻辑:
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.util.List;@Component
public class CustomTenantHandler implements TenantHandler {@Overridepublic Expression getTenantId() {// 假设有一个租户上下文,能够从中获取当前用户的租户Long tenantId = TenantContextHolder.getCurrentTenantId();// 返回租户ID的表达式return tenantId;}@Overridepublic String getTenantIdColumn() {return "tenant_id";}@Overridepublic boolean ignoreTable(String tableName) {// 根据需要返回是否忽略该表return false;}@Overridepublic void setProperties(Properties properties) {// 可以设置一些属性}
}
2、步骤二
但在实际应用场景中会存在部分表不分租户,这时需要忽略租户过滤指定表,常规情况下我们可能会定义一个常量数据来判断,但这样不方便维护,可以通过反射判断当前表是否存在租户id字段,以此忽略租户隔离:
/*** <p>* 租户处理器* </p>** @author 瞄你个汪* @since 2024/6/2 16:15*/
@Slf4j
@Component
public class TableTenantLineHandler implements TenantLineHandler {@Autowiredprivate AppConfiguration appConfig;...@Overridepublic boolean ignoreTable(String tableName) {return Strings.isEmpty(tableName) || appConfig.notHasTenantColumn(tableName, getTenantIdColumn());}...
}
3、步骤三
判断表是否存在租户字段:
/*** <p>* 应用配置类* </p>* @author 瞄你个汪* @since 2024/5/29 12:55*/
@Data
@Component
public class AppConfiguration {...// 这里我使用了SpringBoot Cache缓存@Cacheable(value="system", key="#methodName + ':' + #tableName")public boolean notHasTenantColumn(String tableName, String tenantId) {// TableInfoHelper 为MyBatis-Plus中的工具类List<TableInfo> tableInfos = TableInfoHelper.getTableInfos();for (TableInfo table : tableInfos) {if (tableName.equals(table.getTableName())) {return table.getFieldList().stream().noneMatch(x -> tenantId.equals(x.getColumn()));}}return false;}
}
步骤四
注入租户处理器
/*** <p>* MybatisPlus 配置* </p>* @author 瞄你个汪* @since 2024/6/2 16:30*/
@Configuration
@MapperScan("top.xxxx.mapper")
public class MybatisPlusConfig {@Autowiredprivate TableTenantLineHandler tableTenantLineHandler;@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();tenantInterceptor.setTenantLineHandler(tableTenantLineHandler);interceptor.addInnerInterceptor(tenantInterceptor);return interceptor;}
}
二、配置分页
1、步骤一
编写通用分页查询接口输入参数类:
/*** <p>* Http 分页查询输入参数* </p>* @author 瞄你个汪* @since 2024-05-01 12:00:00*/
@Data
public class PageInput<S> {/*** 查询条件*/private S search;/*** 页容量*/@Min(value = 1, message = "页容量不能小于1")private long size = 10;/*** 当前页*/@Min(value = 1, message = "当前页不能小于1")private long page = 1;/*** 排序字段*/private List<OrderItem> orders;public <R> IPage<R> getPage() {Page<R> page = new Page<>(this.page, size);page.setOrders(orders);page.setMaxLimit(500L);return page;}/*** 传递分页参数并设置查询记录*/public <R> IPage<R> reader(Function<IPage<R>, List<R>> func) {IPage<R> page = getPage();return page.setRecords(func.apply(page));}/*** 传递分页参数并设置查询记录*/public <R> IPage<R> reader(BiFunction<IPage<R>, QueryWrapper<R>, List<R>> func) {IPage<R> page = getPage();return page.setRecords(func.apply(page, new QueryWrapper<>()));}
}
2、步骤二
注入分页插件:
/*** <p>* MybatisPlus 配置* </p>* @author 瞄你个汪* @since 2024/6/2 16:30*/
@Configuration
@MapperScan("top.xxxx.mapper")
public class MybatisPlusConfig {@Autowiredprivate TableTenantLineHandler tableTenantLineHandler;@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();...// 分页配置, 这行配置必须放最后interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}
3、步骤三
使用:
/*** <p>* 系统用户表 前端控制器* </p>* @author 瞄你个汪* @since 2024-01-01 12:00:00*/
@Api(tags = "⚙ 系统用户管理")
@RestController()
@RequestMapping("/api/sysUser")
public class SysUserController {private final ISysUserService service;@Autowiredpublic SysUserController(SysUserServiceImpl _service) {service = _service;}/*** <p>* 分页查询系统用户数据* </p>* @param page 分页参数* @return 查询结果*/@PostMapping("page")@ApiOperation(value = "分页查询", notes = "分页查询系统用户数据")public Result<IPage<SysUser>> queryByPage(@Validated @RequestBody PageInput<String> page) {String search = page.getSearch();boolean notEmpty = Strings.isNotEmpty(search);return Result.ok(page.reader((fPage, query) -> {query.lambda().like(notEmpty, SysUser::getMobile, search).like(notEmpty, SysUser::getAccount, search).like(notEmpty, SysUser::getRealName, search).like(notEmpty, SysUser::getNickName, search);return this.service.list(fPage, query);}));}...
}
没有过滤条件:
@PostMapping("page")@ApiOperation(value = "分页查询", notes = "分页查询系统用户数据")public Result<IPage<SysUser>> queryByPage(@Validated @RequestBody PageInput<String> page) {return Result.ok(page.reader((_page, query) -> this.service.list(_page, query)));}
PS:觉得可以请帮忙点赞收藏,万分感谢🫡🫡🫡
相关文章:
MyBatis-Plus如何优雅的配置多租户及分页
MyBatis-Plus如何优雅的配置多租户及分页 一、配置多租户1、步骤一2、步骤二3、步骤三步骤四 二、配置分页1、步骤一2、步骤二3、步骤三 一、配置多租户 TenantLineInnerInterceptor 是 MyBatis-Plus 提供的一个插件,用于实现多租户的数据隔离。通过这个插件&#…...

国产操作系统上Vim的详解01--vim基础篇 _ 统信 _ 麒麟 _ 中科方德
原文链接:国产操作系统上Vim的详解01–vim基础篇 | 统信 | 麒麟 | 中科方德 Hello,大家好啊!今天给大家带来一篇在国产操作系统上使用Vim的详解文章。Vim是一款功能强大且高度可定制的文本编辑器,广泛应用于编程和日常文本编辑中。…...

如何正确理解事件溯源架构模式?
在微服务架构盛行的当下,DDD(领域驱动设计)也得到了崭新的发展。同时,随着DDD的不断发展,也诞生了一些新的设计思想和开发模式,今天要介绍的事件溯源是其中具有代表性的一种模式。 事件溯源模式是DDD领域中…...

【漏洞复现】电信网关配置管理系统 rewrite.php 文件上传漏洞
0x01 产品简介 中国电信集团有限公司(英文名称"China Telecom”、简称“"中国电信”)成立于2000年9月,是中国特大型国有通信企业、上海世博会全球合作伙伴。电信网关配置管理系统是一个用于管理和配置电信网络中网关设备的软件系统。它可以帮助网络管理员…...

线性调整率:LINE REGULATION详解
目录 一、概述 二、 举例 一、概述 LDO(低压差线性稳压器)的LINE REGULATION(线路调整或线性调整)参数是一个衡量稳压器输出稳定性的重要指标。它反映了LDO输出电压对输入电压变化的响应程度。 当输入电压在其规定的工作范围内变…...

Workfine默认首页功能详解
一、基本介绍 Workfine V6.3推出了默认的用户首页功能,这样用户在登入系统后就可以通过默认的首页栏进行一些业务操作。第一版的用户首页功能布局了审批,制单,业务导航,便捷入口,消息和预警六大块内容,后续…...

CSAPP Lab07——Malloc Lab完成思路
等不到天黑 烟火不会太完美 回忆烧成灰 还是等不到结尾 ——她说 完整代码见:CSAPP/malloclab-handout at main SnowLegend-star/CSAPP (github.com) Malloc Lab 按照惯例,我先是上来就把mm.c编译了一番,结果产生如下报错。搜索过后看样子应…...

简单、免费、无广告的高性能多线程文件下载工具
一、简介 1、它是一款免费、无广告的高性能多线程文件下载工具。它界面简洁,简单好用,压缩包大小仅有 0.7MB,目前仅支持 Windows 平台。 2、使用方法:点击程序左上角的【】按钮,将需要的链接输入进去后点击【下载】即…...
【退役之重学 SQL】什么是笛卡尔积
一、初识笛卡尔积 概念: 笛卡尔积是指在关系型数据库中,两个表进行 join 操作时,没有指定任何条件,导致生成的结果集,是两个表中所有行的组合。 简单来说: 笛卡尔积是两个表的乘积,结果集中的每…...
Vue3禁止 H5 界面放大与缩小功能
Vue3禁止 H5 界面放大与缩小功能 一、前言1.第一步2.第二部3.总结 一、前言 当涉及到禁止 H5 界面的放大与缩小功能时,Vue 3 提供了一种方便的方式来处理。我们可以使用 <script setup> 语法,将相关代码添加到 App.vue 组件中,以确保在…...

上位机图像处理和嵌入式模块部署(f407 mcu中tf卡读写和fatfs挂载)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 很早之前,个人对tf卡并不是很重视,觉得它就是一个存储工具而已。后来在移植v3s芯片的时候,才发现很多的soc其实…...

汽车识别项目
窗口设计 这里的代码放在py文件最前面或者最后面都无所谓 # 创建主窗口 window tk.Tk() window.title("图像目标检测系统") window.geometry(1000x650) # 设置窗口大小# 创建背景画布并使用grid布局管理器 canvas_background tk.Canvas(window, width1000, height…...
【面试题-012】什么是Spring 它有哪些优势
文章目录 Spring有哪些优势有哪些优势Spring和Springboot区别在 Spring 框架中,什么是AOP核心概念应用场景 Spring有哪些通知类型 Spring 是一个开源的 Java 平台,由 Rod Johnson 创建,用于简化企业级 Java 应用程序的开发。它于 2003 年首次…...
ImageButton src图片会照成内存泄露吗 会使native内存增加吗?
在Android开发中,ImageButton 是用来显示按钮的视图组件,它通常用于显示图标或图片。对于ImageButton使用的src属性(即按钮上的图片)通常不会导致内存泄漏,但是有几种情况可能会导致内存问题: 1. **不正确…...

负载均衡与容错性:集群模式在分布式系统中的应用
本文作者:小米,一个热爱技术分享的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是小米,一个热爱分享技术的29岁程序员。今天我们来聊一聊分布式系统中的一个重要概念:集群(Cluster)模式。相信很多朋友在日常开发…...

【UE5.1 角色练习】09-物体抬升、抛出技能 - part1
前言 在上一篇(【UE5.1 角色练习】08-传送技能)的基础上继续实现控制物体抬升、抛出的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中新建一个操作映射,这里命名为“Skill_GravityControl”,用按键4触发 2. 通过IK重定向…...

最大的游戏交流社区Steam服务器意外宕机 玩家服务受影响
易采游戏网6月3日消息:众多Steam游戏玩家报告称,他们无法访问Steam平台上的个人资料、好友列表和社区市场等服务。同时,社区的讨论功能也无法正常使用。经过第三方网站SteamDB的确认,,这一现象是由于Steam社区服务器突…...

如何手动批准内核扩展 Tuxera NTFS for mac内核扩展需要批准 内核扩展怎么打开
在了解如何手动批准内核扩展之前,我们应该先了解什么叫做内核扩展。内核扩展又被称为KEXT,通过它可以实现macOS系统与软件组件之间的交互,例如磁盘管理、任务管理和内存管理等等。 kext 是内核扩展(Kernel Extension)…...
ffmpeg常用命令
推流 ffmpeg -re -stream_loop -1 -i in.flv -c copy -f flv outurl 推流追加时间戳 ffmpeg -stream_loop -1 -re -i move.flv -vf "settbAVTB,setptstrunc(PTS/1K)*1Kst(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K),drawtextfontfilearial.ttf:text%{localtime}.%{eif\:…...
在MongoDB中,您可以通过以下步骤来创建账号密码,并限制其在特定数据库上的访问权限
在MongoDB中,您可以通过以下步骤来创建账号密码,并限制其在特定数据库上的访问权限: 连接到MongoDB数据库: 使用MongoDB的客户端(如mongo shell或者MongoDB Compass)连接到MongoDB服务器。 切换到admin数…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

GraphRAG优化新思路-开源的ROGRAG框架
目前的如微软开源的GraphRAG的工作流程都较为复杂,难以孤立地评估各个组件的贡献,传统的检索方法在处理复杂推理任务时可能不够有效,特别是在需要理解实体间关系或多跳知识的情况下。先说结论,看完后感觉这个框架性能上不会比Grap…...