当前位置: 首页 > news >正文

某j,mybatis-plus,多租户,多表关联查询 ,主表不追加租户条件bug解决

1.原因

经过半天一点点的手撕源码自己重写了TenantLineHandler,但是又重复加了,到这时才意识某j已经重了TenantLineHandler再排查发下 他重写的 ignoreTable(String tableName)中传过来的tableName多加了反引号`,在比较前去掉就好了

2.多租户配置类代码

 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency>

package org.jeecg.config.mybatis;import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.TenantConstant;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.TokenUtils;
import org.jeecg.common.util.oConvertUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** 单数据源配置(jeecg.datasource.open = false时生效)* @Author zhoujf**/
@Configuration
@MapperScan(value={"org.jeecg.modules.**.mapper*"})
public class MybatisPlusSaasConfig {/*** 是否开启系统模块的租户隔离*  控制范围:用户、角色、部门、我的部门、字典、分类字典、多数据源、职务、通知公告**  实现功能*  1.用户表通过硬编码实现租户ID隔离*  2.角色、部门、我的部门、字典、分类字典、多数据源、职务、通知公告除了硬编码还加入的 TENANT_TABLE 配置中,实现租户隔离更安全*  3.菜单表、租户表不做租户隔离*  4.通过拦截器MybatisInterceptor实现,增删改查数据 自动注入租户ID*/public static final Boolean OPEN_SYSTEM_TENANT_CONTROL = true;/*** 哪些表需要做多租户 表需要添加一个字段 tenant_id*/public static final List<String> TENANT_TABLE = new ArrayList<String>();static {//1.需要租户隔离的表请在此配置if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {//a.系统管理表// TENANT_TABLE.add("sys_user");TENANT_TABLE.add("sys_role");TENANT_TABLE.add("crm_sys_config");TENANT_TABLE.add("sys_queue");//TENANT_TABLE.add("sys_announcement");}//2.示例测试//TENANT_TABLE.add("demo");//3.online租户隔离测试//TENANT_TABLE.add("ceapp_issue");}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptorinterceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {@Overridepublic Expression getTenantId() {String tenantId = TenantContext.getTenant();//如果通过线程获取租户ID为空,则通过当前请求的request获取租户(shiro排除拦截器的请求会获取不到租户ID)if(oConvertUtils.isEmpty(tenantId)){try {tenantId = TokenUtils.getTenantIdByRequest(SpringContextUtils.getHttpServletRequest());} catch (Exception e) {//e.printStackTrace();}}if(oConvertUtils.isEmpty(tenantId)){tenantId = "0";}return new LongValue(tenantId);}@Overridepublic String getTenantIdColumn(){return TenantConstant.TENANT_ID_TABLE;}// 返回 true 表示不走租户逻辑@Overridepublic boolean ignoreTable(String tableName) {tableName=tableName.replace("`","");for(String temp: TENANT_TABLE){if(temp.equalsIgnoreCase(tableName)){//判断是否使用注解不走多租户 //此文章中有MybatisTenantContext详细代码https://blog.csdn.net/zhaofuqiangmycomm/article/details/144106532if (Objects.nonNull(MybatisTenantContext.get())){return MybatisTenantContext.get();}return false; // 其他表进行租户过滤}}return true; // 返回 true,表示不对这些表进行租户过滤}}));//update-begin-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());//update-end-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//【jeecg-boot/issues/3847】增加@Version乐观锁支持 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}/*** 动态表名切换拦截器,用于适配vue2和vue3同一个表有多个的情况,如sys_role_index在vue3情况下表名为sys_role_index_v3* @return*/private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {//获取需要动态解析的表名String dynamicTableName = ThreadLocalDataHelper.get(CommonConstant.DYNAMIC_TABLE_NAME);//当dynamicTableName不为空时才走动态表名处理逻辑,否则返回原始表名if (ObjectUtil.isNotEmpty(dynamicTableName) && dynamicTableName.equals(tableName)) {// 获取前端传递的版本号标识Object version = ThreadLocalDataHelper.get(CommonConstant.VERSION);if (ObjectUtil.isNotEmpty(version)) {//拼接表名规则(原始表名+下划线+前端传递的版本号)return tableName + "_" + version;}}return tableName;});return dynamicTableNameInnerInterceptor;}}

3.手撕代码过程

1.找到类om.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor

中的processPlainSelect 这里是查询方法追加租户id的地方,再找到主表追加的地方

// 当有 mainTable 时,进行 where 条件追加
if (CollectionUtils.isNotEmpty(mainTables)) {plainSelect.setWhere(builderExpression(where, mainTables, whereSegment));
}

2.再看这个方法builderExpression 中构造每张表的查询条件

3.再点击 buildTableExpression中找到实现类

@Override
public Expression buildTableExpression(final Table table, final Expression where, final String whereSegment) {if (tenantLineHandler.ignoreTable(table.getName())) {return null;}return new EqualsTo(getAliasColumn(table), tenantLineHandler.getTenantId());
}

tenantLineHandler.ignoreTable( 是判断要不要走多租户的

4.再找到类tenantLineHandler,这里能发现mybatis-plus是默认所有表都走多租户的,

怎么配置让有的表走多租户,有的不走,就需要写一个配置类,继承tenantLineHandler,重写ignoreTable方法了,上面的MybatisPlusSaasConfig 是重写到内部类中去了,害我自己又写了一个

5.至此改掉 MybatisPlusSaasConfig中 的内部类MybatisPlusInterceptor 的ignoreTable中的比较bug问题解决,至于 tableName多加了反引号` 可能是某j的bug,有时候前端传过的参数也有多加反引号,有空还得好好排查下


http://www.mrgr.cn/news/78350.html

相关文章:

  • 使用Github Action将Docker镜像转存到阿里云私有仓库,供国内服务器使用,免费易用
  • 论文阅读 - Labeled Datasets for Research on Information Operations
  • Python 3 教程第2篇(基础语法)
  • 数据库编程(sqlite3)
  • 解决stuid项目类爆炸问题
  • 【21-30期】Java技术深度剖析:从分库分表到微服务的核心问题解析
  • element ui select绑定的值是对象的属性时,显示异常.
  • SAP学习
  • Android 图形系统之一:概览
  • 【Zookeeper】三,Zookeeper的安装与基本操作
  • 《Learning Three.js》学习(1)使用Three.js创建三维场景
  • ABAP OOALV模板
  • 蓝桥杯备赛笔记(一)
  • transformer学习笔记-神经网络原理
  • mini-spring源码分析
  • Leetcode(快慢指针习题思路总结,持续更新。。。)
  • 【halcon】Metrology工具系列之 get_metrology_object_model_contour
  • Leetcode 51 N Queens Leetcode N Queens II
  • Qt程序发布及打包成exe安装包
  • Windows Server 2019 虚拟机 安装Oracle19c,图文详情(超详细)
  • Chrome和edge浏览器如何为任何网站强制暗模式
  • git 学习笔记
  • VTK中对于相机camera的设置
  • 机载视频流回传+编解码方案
  • 分布式调用 - 服务间的远程调用RPC
  • Linux系统硬件老化测试脚本:自动化负载与监控