MyBatis-Plus忽略多租户隔离自定义注解

微服务项目中由于默认开启了租户隔离,但是有些情况下需要个别方法不启用。

为了实现这个目标自定义了一个忽略租户隔离的注解:

@IgnoreTenant

将他加在方法上即可,例如:

    @IgnoreTenantpublic CrmSmsTemplate getTemplateByCodeAndTenandtId(String code, Integer tenantId) {return crmSmsTemplateMapper.selectOne(new QueryWrapper<CrmSmsTemplate>().eq("code", code).eq("tenant_id", tenantId));}

实现步骤:

1.首先定义MybatisPlus的配置类创建一个拦截器MybatisPlusInterceptor

将MybatisPlusSaasConfig中的mybatisPlusInterceptor方法修改
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)){if (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;}}

2,定义一个ThreadLocal本地线程变量 MybatisTenantContext用于维护是否开启租户隔离变量

package org.jeecg.config.mybatis;public class MybatisTenantContext {private static final ThreadLocal<Boolean> TENANT_CONTEXT_THREAD_LOCAL = new ThreadLocal<>();public static Boolean get() {return TENANT_CONTEXT_THREAD_LOCAL.get();}public static void set(boolean isIgnore){TENANT_CONTEXT_THREAD_LOCAL.set(isIgnore);}public static void clear(){TENANT_CONTEXT_THREAD_LOCAL.remove();}
}

3.

自定义注解IgnoreTenant

package org.jeecg.config.filter;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface IgnoreTenant {/*** true为不做租户隔离 false为做租户隔离* @return*/boolean isIgnore() default true;
}

4.注解实现类  

ps:如果方法或者类上有其他注解用到租户隔离的,如:日志注解,字典翻译注解在point.proceed()后执行逻辑。需要注意切面类的执行顺序,一定要保证TenantIgnoreAspect 先执行,不然其它注解还是会有租户隔离的情况。可以在TenantIgnoreAspect 切面类加上@Order(Integer.MIN_VALUE)注解 保证执行顺序

package org.jeecg.config.filter;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.mybatis.MybatisTenantContext;
import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Objects;@Aspect
@Slf4j
@Component
@Order(Integer.MIN_VALUE)
public class TenantIgnoreAspect {/*** 切入点*/@Pointcut("@within(org.jeecg.config.filter.IgnoreTenant) ||@annotation(org.jeecg.config.filter.IgnoreTenant)")public void pointcut() {}@Around("pointcut()")public Object around(ProceedingJoinPoint point) throws Throwable {try {Class<?> targetClass = point.getTarget().getClass();IgnoreTenant classIgnoreTenant = targetClass.getAnnotation(IgnoreTenant.class);MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();IgnoreTenant methodIgnoreTenant = method.getAnnotation(IgnoreTenant.class);//判断类上是否有注解boolean isClassAnnotated = AnnotationUtils.isAnnotationDeclaredLocally(IgnoreTenant.class, targetClass);//判断方法上是否有注解boolean isMethodAnnotated = Objects.nonNull(methodIgnoreTenant);//如果类上有if (isClassAnnotated) {MybatisTenantContext.set(classIgnoreTenant.isIgnore());}//如果方法上有 以方法上的为主if (isMethodAnnotated) {MybatisTenantContext.set(methodIgnoreTenant.isIgnore());}Object result = point.proceed();return result;} finally {MybatisTenantContext.clear();}}
}

到此为止就可以使用注解:@IgnoreTenant

参考:MyBatis-Plus忽略多租户隔离自定义注解_mybaits plus 忽略租户隔离的注解-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/480656.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中科亿海微SoM模组——波控处理软硬一体解决方案

本文介绍的波控处理软硬一体解决方案主要是面向相控阵天线控制领域&#xff0c;波控处理通过控制不同天线组件的幅相来调整天线波束的方向和增益&#xff0c;实现高精度角度控制和高增益。本方案由波控处理板、波控处理控制软件算法和上位机软件共同构成。波控处理SoM模组原型样…

Java设计模式 —— 【创建型模式】工厂模式(简单工厂、工厂方法模式、抽象工厂)详解

文章目录 前言一、简单工厂&#xff08;静态工厂&#xff09;1、概述2、代码实现3、优缺点 二、工厂方法模式1、概述2、代码实现3、优缺点 三、抽象工厂模式1、概述2、代码实现3、优缺点 四、总结 前言 先看个案例&#xff1a;【手机和手机店】在没有工厂的时候&#xff0c;手…

【阅读记录-章节4】Build a Large Language Model (From Scratch)

文章目录 4. Implementing a GPT model from scratch to generate text4.1 Coding an LLM architecture4.1.1 配置小型 GPT-2 模型4.1.2 DummyGPTModel代码示例4.1.3 准备输入数据并初始化 GPT 模型4.1.4 初始化并运行 GPT 模型 4.2 Normalizing activations with layer normal…

关于VNC连接时自动断联的问题

在服务器端打开VNC Server的选项设置对话框&#xff0c;点左边的“Expert”&#xff08;专家&#xff09;&#xff0c;然后找到“IdleTimeout”&#xff0c;将数值设置为0&#xff0c;点OK关闭对话框。搞定。 注意,服务端有两个vnc服务,这俩都要设置ide timeout为0才行 附件是v…

遗传算法与深度学习实战(25)——使用Keras构建卷积神经网络

遗传算法与深度学习实战&#xff08;25&#xff09;——使用Keras构建卷积神经网络 0. 前言1. 卷积神经网络基本概念1.1 卷积1.2 步幅1.3 填充1.4 激活函数1.5 池化 2. 使用 Keras 构建卷积神经网络3. CNN 层的问题4. 模型泛化小结系列链接 0. 前言 卷积神经网络 (Convolution…

使用 Docker Compose 来编排部署LMTNR项目

使用 Docker Compose 来部署一个包含 Linux、MySQL、Tomcat、Nginx 和 Redis 的完整项目的例子。假设我们要部署一个简单的 Java Web 应用&#xff0c;并且使用 Nginx 作为反向代理服务器。 项目目录结构 首先需要确保 Docker 和docker-compose已经安装并正在运行。docker --v…

快速理解倒排索引在ElasticSearch中的作用

一.基础概念 定义&#xff1a; 倒排索引是一种数据结构&#xff0c;用来加速文本数据的搜索和检索&#xff0c;和传统的索引方式不同&#xff0c;倒排索引会被每个词汇项与包含该词汇项的文档关联起来&#xff0c;从而去实现快速的全文检索。 举例&#xff1a; 在传统的全文…

跨平台应用开发框架(3)-----Qt(样式篇)

目录 1.QSS 1.基本语法 2.QSS设置方式 1.指定控件样式设置 2.全局样式设置 1.样式的层叠特性 2.样式的优先级 3.从文件加载样式表 4.使用Qt Designer编辑样式 3.选择器 1.类型选择器 2.id选择器 3.并集选择器 4.子控件选择器 5.伪类选择器 4.样式属性 1.盒模型 …

Pump Science平台深度剖析:兴起、优势、影响与未来

在过去的几个月里&#xff0c;人们越来越关注去中心化科学&#xff08;DeSci&#xff09;。DeSci 是一种利用区块链技术进行科学研究的新方法。传统的科学研究经常面临所谓的“死亡之谷”&#xff0c;这指的是基础科学研究与成功开发和造福患者的实施之间的重要时期。DeSci 旨在…

网安瞭望台第4期:nuclei最新poc分享

国内外要闻 多款 D-Link 停产路由器漏洞&#xff1a;攻击者可远程执行代码 近日&#xff0c;知名网络硬件制造商 D-Link 发布重要安全公告。由于存在严重的远程代码执行&#xff08;RCE&#xff09;漏洞&#xff0c;其敦促用户淘汰并更换多款已停产的 VPN 路由器型号。 此次…

TDengine在debian安装

参考官网文档&#xff1a; 官网安装文档链接 从列表中下载获得 Deb 安装包&#xff1b; TDengine-server-3.3.4.3-Linux-x64.deb (61 M) 进入到安装包所在目录&#xff0c;执行如下的安装命令&#xff1a; sudo dpkg -i TDengine-server-<version>-Linux-x64.debNOTE 当…

Mybatis集成篇(一)

Spring 框架集成Mybatis 目前主流Spring框架体系中&#xff0c;可以集成很多第三方框架&#xff0c;方便开发者利用Spring框架机制使用第三方框架的功能。就例如本篇Spring集成Mybatis 简单集成案例&#xff1a; Config配置&#xff1a; Configuration MapperScan(basePack…

k8s Init:ImagePullBackOff 的解决方法

kubectl describe po (pod名字) -n kube-system 可查看pod所在的节点信息 例如&#xff1a; kubectl describe po calico-node-2lcxx -n kube-system 执行拉取前先把用到的节点的源换了 sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"re…

nginx+php压测及报错优化

测试环境&#xff1a;虚拟机centos7&#xff0c;nginxphp 压测工具&#xff1a;Apipost 访问的php程序中添加sleep()增加程序执行时长&#xff0c;使用Apipost进行压测&#xff0c;根据服务器配置设置一个大概可能触发报错的并发和轮训次数&#xff0c;若无报错逐渐增加并发和…

【数据结构】ArrayList与顺序表

ArrayList与顺序表 1.线性表2.顺序表2.1 接口的实现 3. ArrayList简介4. ArrayList使用4.2 ArrayList常见操作4.3 ArrayList的遍历4.4 ArrayList的扩容机制 5. ArrayList的具体使用5.1 杨辉三角5.2 简单的洗牌算法 6. ArrayList的问题及思考 【本节目标】 线性表顺序表ArrayLis…

GaussDB高智能--智能优化器介绍

书接上文库内AI引擎&#xff1a;模型管理&数据集管理&#xff0c;从模型管理与数据集管理两方面介绍了GaussDB库内AI引擎&#xff0c;本篇将从智能优化器方面解读GaussDB高智能技术。 4 智能优化器 随着数据库与AI技术结合的越来越紧密&#xff0c;相关技术在学术界的数…

GDPU Android移动应用 数据存储

又是学到了数据持久化。 登录界面 题外话&#xff1a;有无动画大佬带带呀&#xff0c;前端移动端可免( •̀ .̫ •́ )&#xff0c;合作可私信哦。 1.用户登陆和“记住我”功能 该内容拥有两个Activity活动视图&#xff1a; &#xff08;1&#xff09;LoginActivity&#x…

麒麟性能评估优化

cpu性能 Vmstat输出结果详解如下: r 列表示运行和等待cpu时间片的进程数,这个值如果长期大于系统CPU的个数,说 明CPU不足,需要增加CPU; b 列表示在等待资源的进程数,比如正在等待I/O、或者内存交换等; us 列显示了用户进程消耗的CPU 时间百分比。us的值比较高时,说明用…

Python基础学习-12匿名函数lambda和map、filter

目录 1、匿名函数&#xff1a; lambda 2、Lambda的参数类型 3、map、 filter 4、本节总结 1、匿名函数&#xff1a; lambda 1&#xff09;语法&#xff1a; lambda arg1, arg2, …, argN : expression using arg 2&#xff09; lambda是一个表达式&#xff0c;而不是一个语…

uniapp定义new plus.nativeObj.View实现APP端全局弹窗

为什么要用new plus.nativeObj.View在APP端实现弹窗&#xff1f;因为uni.showModal在APP端太难看了。 AppPopupView弹窗函数参数定义 参数一:弹窗信息(所有属性可不填&#xff0c;会有默认值) 1.title:"", //标题 2.content:"", //内容 3.confirmBoxCo…