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

MyBatis Interceptor拦截器高级用法

拦截插入操作

场景描述:插入当前数据时,同时复制当前数据插入多行。比如平台权限的用户,可以同时给其他国家级别用户直接插入数据

  实现:

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Properties;/*** @author xxx* @version 1.0* @description 超级管理员创建基础资料,自动创建其他国家相应数据* @create 2024/3/2/002 13:48*/
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class InsertionLinkageInterceptor implements Interceptor {@Value("${product.country-id.tables}")private String countryIdTables;@Resourceprivate UserService userService;@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 只有超级管理员需要拦截if (!userService.isSuperAdmin()) {return invocation.proceed();}Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];// 拦截插入操作if (ms.getSqlCommandType() == SqlCommandType.INSERT) {Object parameter = args[1];Class<?> aClass = parameter.getClass();TableName annotation = aClass.getAnnotation(TableName.class);String tableName = annotation.value();// 此处业务逻辑判断 此处做了一个表格名动态配置,可自行修改 //TODOif (!countryIdTables.contains(tableName)) {return invocation.proceed();}CountryBaseInfoDO parameterDO = (CountryBaseInfoDO) args[1];parameterDO.setCountryId(userService.getUserCountryId());parameterDO.setCode(IdUtils.generateCode());Constructor<?> constructor = aClass.getConstructor();CountryBaseInfoDO paramObject;List<Long> countryList = userService.getUserCountryIds();for (Long countryId : countryList) {paramObject = (CountryBaseInfoDO) constructor.newInstance();BeanUtils.copyProperties(parameterDO, paramObject);paramObject.setCountryId(countryId);Executor executor = (Executor) invocation.getTarget();executor.update(ms, paramObject);}}// 继续执行原始方法return invocation.proceed();}}

有些实体可能需要自行创建 

拦截更新操作

更新数据时候,可能不止更新当前表,可能需要同时更新其他行数据

拦截查询

查询数据时候,可能需要同时默认加上某个条件

实现:

@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class CommonQueryInterceptor implements Interceptor {private final static String FIELD_COUNTRY_ID = "country_id";@Value("${product.country-id.tables}")private String countryIdTables;@Resourceprivate UserService userService;@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 超级管理员查看所有if (!userService.isSuperAdmin()) {return invocation.proceed();}RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();//获取StatementHandler构造器StatementHandler delegate = (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate");BoundSql boundSql = delegate.getBoundSql();String sql = boundSql.getSql();Statement statement = CCJSqlParserUtil.parse(sql);// 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性MappedStatement mappedStatement = (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement");SqlCommandType commandType = mappedStatement.getSqlCommandType();if (SqlCommandType.SELECT.equals(commandType)) {Select select = (Select) statement;PlainSelect selectBody = (PlainSelect) select.getSelectBody();Table fromItem = (Table) selectBody.getFromItem();String name = fromItem.getName();// 不在配置的表中,直接返回if (!countryIdTables.contains(name)) {return invocation.proceed();}appendCondition(selectBody);ReflectUtil.setFieldValue(boundSql, "sql", statement.toString());// 超级管理员插入时候同步插入所有国家的数据} else if (SqlCommandType.UPDATE.equals(commandType)) {String extraCondition = " or id  in(" + userService.getNeedUpdateIds() + ")";sql = sql + extraCondition;ReflectUtil.setFieldValue(boundSql, "sql", sql);}return invocation.proceed();}/*** 追加条件*/private void appendCondition(PlainSelect selectBody) {try {// 获取where条件String stringExpression;try {EqualsTo where = (EqualsTo) selectBody.getWhere();stringExpression = where.getStringExpression();} catch (Exception e) {stringExpression = selectBody.getWhere().toString();}//如果字段搜索条件为空则搜索字段为空或指定数据StringBuilder sqlFilter = new StringBuilder(128);if (!stringExpression.contains(FIELD_COUNTRY_ID)) {sqlFilter.append("(country_id in ( ").append(userService.getNeedUpdateIds()).append(")) ");buildWhereClause(selectBody, sqlFilter.toString());}} catch (Exception e) {log.error("appendCondition error", e);//多表查询时由于不是最后一层,获取不到Table,继续获取子表
//            SubSelect ss = (SubSelect) selectBody.getFromItem();
//            PlainSelect subSelect = (PlainSelect) ss.getSelectBody();
//            appendCondition(subSelect);}}private void buildWhereClause(PlainSelect select, String dataFilter) throws JSQLParserException {if (select.getWhere() == null) {select.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter));} else {AndExpression and = new AndExpression(CCJSqlParserUtil.parseCondExpression(dataFilter), select.getWhere());select.setWhere(and);}}}

相关文章:

MyBatis Interceptor拦截器高级用法

拦截插入操作 场景描述&#xff1a;插入当前数据时&#xff0c;同时复制当前数据插入多行。比如平台权限的用户&#xff0c;可以同时给其他国家级别用户直接插入数据 实现&#xff1a; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.Executor; impor…...

Python学习入门(2)——进阶功能

14. 迭代器和迭代协议 在Python中&#xff0c;迭代器是支持迭代操作的对象&#xff0c;即它们可以一次返回其成员中的一个。任何实现了 __iter__() 和 __next__() 方法的对象都是迭代器。 class Count:def __init__(self, low, high):self.current lowself.high highdef __i…...

华为改进点

华为公司可以在员工福利方面做出改进&#xff0c;提高员工的工作满意度和忠诚度。例如&#xff0c;可以增加员工福利&#xff0c;如提供更多灵活的工作时间、提供更好的培训和发展机会、加大健康保障和福利待遇等。 此外&#xff0c;华为公司也可以加强与客户的沟通与合作&…...

分布式技术---------------消息队列中间件之 Kafka

目录 一、Kafka 概述 1.1为什么需要消息队列&#xff08;MQ&#xff09; 1.2使用消息队列的好处 1.2.1解耦 1.2.2可恢复性 1.2.3缓冲 1.2.4灵活性 & 峰值处理能力 1.2.5异步通信 1.3消息队列的两种模式 1.3.1点对点模式&#xff08;一对一&#xff0c;消费者主动…...

BGP扩展知识总结

一、BGP的宣告问题 在BGP协议中每台运行BGP的设备上&#xff0c;宣告本地直连路由在BGP协议中运行BGP协议的设备&#xff0c;来宣告通过IGP学习到的未运行BGP协议设备产生的路由&#xff1b;&#xff08;常见&#xff09; 在BGP协议中宣告本地路由表中路由条目时&#xff0c;将…...

华为OD-C卷-按身高和体重排队[100分]

题目描述 某学校举行运动会&#xff0c;学生们按编号(1、2、3…n)进行标识&#xff0c;现需要按照身高由低到高排列&#xff0c;对身高相同的人&#xff0c;按体重由轻到重排列&#xff1b;对于身高体重都相同的人&#xff0c;维持原有的编号顺序关系。请输出排列后的学生编号…...

云原生(八)、Kubernetes基础(一)

K8S 基础 # 获取登录令牌 kubectl create token admin --namespace kubernetes-dashboard1、 NameSpace Kubernetes 启动时会创建四个初始名字空间 default:Kubernetes 包含这个名字空间&#xff0c;以便于你无需创建新的名字空间即可开始使用新集群。 kube-node-lease: 该…...

Linux 系统解压缩文件

Linux系统&#xff0c;可以使用unzip命令来解压zip文件 方法如下 1. 打开终端&#xff0c;在命令行中输入以下命令来安装unzip&#xff1a; sudo apt-get install unzip 1 2. 假设你想要将zip文件解压缩到名为"target_dir"的目录中&#xff0c;在终端中切换到目标路…...

linux如何使 CPU使用率保持在指定百分比?

目录 方法1&#xff1a;&#xff08;固定在100%&#xff09; 方法2&#xff1a;&#xff08;可以指定0~100%&#xff09; 方法3&#xff1a;使用ChaosBlade工具&#xff08;0~100%&#xff09; 方法1&#xff1a;&#xff08;固定在100%&#xff09; for i in seq 1 $(cat /pro…...

LLMs之Morphic:Morphic(一款具有生成式用户界面的人工智能答案引擎)的简介、安装、使用方法之详细攻略

LLMs之Morphic&#xff1a;Morphic(一款具有生成式用户界面的人工智能答案引擎)的简介、安装、使用方法之详细攻略 目录 Morphic的简介 1、技术栈 Morphic的安装和使用方法 1、克隆仓库 2、安装依赖 3、填写密钥 4、本地运行应用 部署 Morphic的简介 2024年4月初发布&#xff…...

[react] useState的一些小细节

1.无限循环 因为setState修改是异步的,加上会触发函数重新渲染, 如果代码长这样 一秒再修改,然后重新触发setTImeout, 然后再触发,重复触发循环 如果这样呢 还是会,因为你执行又会重新渲染 2.异步修改数据 为什么修改多次还是跟不上呢? 函数传参解决 因为是异步修改 ,所以…...

蓝桥杯【第15届省赛】Python B组

这题目难度对比历届是相当炸裂的简单了…… A&#xff1a;穿越时空之门 【问题描述】 随着 2024 年的钟声回荡&#xff0c;传说中的时空之门再次敞开。这扇门是一条神秘的通道&#xff0c;它连接着二进制和四进制两个不同的数码领域&#xff0c;等待着勇者们的探索。 在二进制…...

CSS aspect-ratio属性设置元素宽高比

aspect-ratio 是CSS的一个属性&#xff0c;用于设置元素的期望宽高比。它设置确保元素保持特定的比例&#xff0c;不受其内容或容器大小的影响。 语法&#xff1a; aspect-ratio: <ratio>;其中 <ratio> 是一个由斜杠&#xff08;/&#xff09;分隔的两个数字&…...

Jones矩阵符号运算

文章目录 Jones向量Jones矩阵 有关Jones矩阵、Jones向量的基本原理&#xff0c;可参考这个&#xff1a; 通过Python理解Jones矩阵&#xff0c;本文主要介绍sympy中提供的有关偏振光学的符号计算工具 Jones向量 Jones向量是描述光线偏振状态的重要工具&#xff0c;例如一个偏振…...

解决 App 自动化测试的常见痛点!

App 自动化测试中有些常见痛点问题&#xff0c;如果框架不能很好的处理&#xff0c;就可能出现元素定位超时找不到的情况&#xff0c;自动化也就被打断终止了。很容易打消做自动化的热情&#xff0c;导致从入门到放弃。比如下面的两个问题&#xff1a; 一是 App 启动加载时间较…...

2016NOIP普及组真题 1. 买铅笔

线上OJ&#xff1a; 一本通&#xff1a;http://ybt.ssoier.cn:8088/problem_show.php?pid1973 核心思想&#xff1a; 向上取整的代码 (m (n-1))/n 。&#xff08;本题考点与2023年J组的第一和第二题一样&#xff09; 比如需要买31支笔&#xff0c;每包30支&#xff0c;则需要…...

机器学习—数据集(二)

1可用数据集 公司内部 eg:百度 数据接口 花钱 数据集 学习阶段可用的数据集&#xff1a; sklearn:数据量小&#xff0c;方便学习kaggle&#xff1a;80万科学数据&#xff0c;真实数据&#xff0c;数据量大UCI&#xff1a;收录了360个数据集&#xff0c;覆盖科学、生活、经济等…...

华为S5735S核心交换配置实例

以下脚本实现创建vlan2,3&#xff0c;IP划分&#xff0c;DHCP启用&#xff0c;接口划分&#xff0c;ssh,telnet,http,远程登录启用 默认用户创建admin/admin123提示首次登录需要更改用户密码S5735产品手册更多功能配置&#xff0c;移步官网参考手册配置 system-viewsysname t…...

Mysql主从复制安装配置

mysql主从复制安装配置 1、基础设置准备 #操作系统&#xff1a; centos6.5 #mysql版本&#xff1a; 5.7 #两台虚拟机&#xff1a; node1:192.168.85.111&#xff08;主&#xff09; node2:192.168.85.112&#xff08;从&#xff09;2、安装mysql数据库 #详细安装和卸载的步骤…...

【刷题】图论——最小生成树:Prim、Kruskal【模板】

假设有n个点m条边。 Prim适用于邻接矩阵存的稠密图&#xff0c;时间复杂度是 O ( n 2 ) O(n^2) O(n2)&#xff0c;可用堆优化成 O ( n l o g n ) O(nlogn) O(nlogn)。 Kruskal适用于稀疏图&#xff0c;n个点m条边&#xff0c;时间复杂度是 m l o g ( m ) mlog(m) mlog(m)。 Pr…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案

一、延迟敏感行业面临的DDoS攻击新挑战 2025年&#xff0c;金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征&#xff1a; AI驱动的自适应攻击&#xff1a;攻击流量模拟真实用户行为&#xff0c;差异率低至0.5%&#xff0c;传统规则引…...

【版本控制】GitHub Desktop 入门教程与开源协作全流程解析

目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork&#xff08;创建个人副本&#xff09;步骤 2: Clone&#xff08;克隆…...

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器

从本章节开始&#xff0c;进入到函数有多个参数的情况&#xff0c;前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参&#xff0c;ECX是整型的第一个参数的寄存器&#xff0c;那么多个参数的情况下函数如何传参&#xff0c;下面展开介绍参数为整型时候的几种情…...