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

Mr. Cappuccino的第56杯咖啡——Mybatis拦截器

Mybatis拦截器

    • 概述
    • 应用场景
    • 项目结构
    • 实现分页查询
    • 其它拦截器的使用

概述

Mybatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用,通过织入拦截器,在不同节点修改一些执行过程中的关键属性,从而影响SQL的生成、执行和返回结果。

默认情况下,Mybatis支持四种对象拦截:

  1. Executor:拦截执行器的方法;
  2. ParameterHandler:拦截参数的处理;
  3. ResultSetHandler:拦截结果集的处理;
  4. StatementHandler:拦截Sql语法构建的处理;

执行顺序:Executor => StatementHandler => ParameterHandler => ResultSetHandler

注:本文代码基于《Mybatis一级缓存&二级缓存》中的“一级缓存(Spring整合Mybatis)”的代码进行调整。

应用场景

  1. 分页查询;
  2. 数据脱敏;
  3. 数据过滤;
  4. 监控Sql语句执行耗时;

项目结构

在这里插入图片描述

实现分页查询

StatementInterceptor.java

package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;/*** @author honey* @date 2023-08-02 15:25:26*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
})
@Component
public class StatementInterceptor implements Interceptor {@Value("${mybatis.page-helper.rule}")private String rule;@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();MetaObject metaObject = SystemMetaObject.forObject(statementHandler);MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();// 判断sql语句的类型switch (sqlCommandType) {case SELECT:extendLimit(statementHandler);break;case INSERT:case UPDATE:case DELETE:case FLUSH:default:break;}log.info("【StatementInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【StatementInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}private void extendLimit(StatementHandler statementHandler) throws NoSuchFieldException, IllegalAccessException {// 获取原生sql语句BoundSql boundSql = statementHandler.getBoundSql();Class<? extends BoundSql> aClass = boundSql.getClass();// 使用反射机制修改原生sql语句Field sql = aClass.getDeclaredField("sql");sql.setAccessible(true);String oldSqlStr = boundSql.getSql();log.info("原生sql语句:{}", oldSqlStr);// 加上分页规则sql.set(boundSql, oldSqlStr + " " + rule);}
}

application.yml

mybatis:page-helper:rule: limit 2

在这里插入图片描述

其它拦截器的使用

ExecutorInterceptor.java

package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;import java.util.Properties;/*** @author honey* @date 2023-08-02 18:11:28*/
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Component
public class ExecutorInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ExecutorInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ExecutorInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}

ParameterInterceptor.java

package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.sql.PreparedStatement;
import java.util.Properties;/*** @author honey* @date 2023-08-02 18:22:15*/
@Slf4j
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
})
@Component
public class ParameterInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ParameterInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ParameterInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}

ResultSetInterceptor.java

package com.mybatis.interceptor;import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.sql.Statement;
import java.util.Properties;/*** @author honey* @date 2023-08-02 18:24:00*/
@Slf4j
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
public class ResultSetInterceptor implements Interceptor {Properties properties;@Overridepublic Object intercept(Invocation invocation) throws Throwable {log.info("【ResultSetInterceptor】方法拦截前执行");Object result = invocation.proceed();log.info("【ResultSetInterceptor】方法拦截后执行");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {this.properties = properties;}
}

在这里插入图片描述

相关文章:

Mr. Cappuccino的第56杯咖啡——Mybatis拦截器

Mybatis拦截器 概述应用场景项目结构实现分页查询其它拦截器的使用 概述 Mybatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用&#xff0c;通过织入拦截器&#xff0c;在不同节点修改一些执行过程中的关键属性&#xff0c;从而影响SQL的生成、执行和返回结果…...

容器化安装环境EFK搭建

容器化安装环境 Docker中安装并启动ElasticSearch 前置配置 第一步&#xff1a;在宿主机上执行echo “net.ipv4.ip_forward1” >>/usr/lib/sysctl.d/00-system.conf 2.第二步&#xff1a;重启network和docker服务 [rootlocalhost /]# systemctl restart network &&…...

基于 Debian GNU/Linux 12 “书虫 “的Neptune 8.0 “Juna “来了

导读Neptune Linux 发行版背后的团队发布了 Neptune 8.0&#xff0c;作为这个基于 Debian 的 GNU/Linux 发行版的重大更新&#xff0c;它围绕最新的 KDE Plasma 桌面环境构建。 Neptune 8.0 被命名为 “Juna”&#xff0c;是在Neptune 7.5 发布 11 个月后发布的&#xff0c;也是…...

GDAL C++ API 学习之路 (4) Spatial Reference System篇 OGRSpatialReference类

class OGRSpatialReference #include <ogr_spatialref.h> OGRSpatialReference 是 GDAL/OGR 库中的一个重要类&#xff0c;用于管理和操作地理空间数据的空间参考系统&#xff08;Spatial Reference System&#xff0c;SRS&#xff09;。它提供了一系列功能&…...

RS232转Profinet网关rs232转网口需要如何设置

大家好&#xff0c;今天我要给大家带来一个很有意思的案例分享。你们猜猜&#xff0c;这回我们要用捷米的一款神奇的网关JM-RS485/232-PN做什么呢&#xff1f;没错&#xff0c;我们要把一台扫码枪设备通过这个RS232转PROFINET网关&#xff0c;接入到一台西门子S7-1200PLC的Prof…...

LaTex的下载与安装超详细windows版

1.LaTex的下载 &#xff08;texlive下载TexStudio下载&#xff09; &#xff08;1&#xff09;texlive下载&#xff1a; 这里清华镜像下载 &#xff08;2&#xff09;TexStudio下载&#xff1a; 点这里下载镜像 可以根据不同的系统选择不同的版本 2 .LaTex的安装 &#…...

MySQL | 存储过程快速入门

文章目录 一、概述1.1 MySQL存储过程和函数的概念1.2 优势和适用场景 二、存储过程基础2.1 存储过程与传统SQL查询的区别2.2 创建和调用存储过程创建存储过程调用存储过程 2.3 参数传递与返回值创建带有输出参数的存储过程调用带有输出参数的存储过程 2.4 流程控制语句IF语句WH…...

C# 图表控件库 ScottPlot

推荐使用ScottPlot原因&#xff1a; 1.图形界面简洁&#xff0c;样式丰富 2.代码较少 3.官方提供多种实例源码&#xff0c;并可以直接通过图形界面查看&#xff0c;便于快速开发 Github源码链接&#xff1a;https://github.com/ScottPlot/ScottPlot 官网WindowFrom Demo实例…...

013 怎么查看自己电脑的wifi密码

方法一&#xff1a;查看当前电脑连接的无线密码 步骤1&#xff1a; 打开windows命令行窗口&#xff0c;输入&#xff1a;ncpa.cpl 快速打开“控制面板”中的“网络连接”&#xff0c;如下图&#xff1a; 步骤2&#xff1a; 右键&#xff0c;打开“状态” 步骤3&#xff1a;…...

深入了解 LoRaWAN® MAC 命令

本文深入探讨了用于 LoRaWAN 网络管理的 MAC 命令。它面向终端设备软件开发人员和使用 LoRa 构建设备的团队经理,这些设备实现了LoRaWAN 链路层规范 v1.0.4。本文帮助您了解不同类型的 MAC 命令、每个命令的用途以及如何解释这些命令。 已经使用LoRaMAC-Node™等软件来处理 MA…...

跨境电商与隐擎fox指纹浏览器:保障安全与效率的完美结合

随着全球化的发展&#xff0c;跨境电商已成为各国贸易的重要组成部分。然而&#xff0c;随之而来的风险和挑战也日益增多&#xff0c;其中之一就是关联浏览器和多开浏览器可能带来的安全隐患。为了确保跨境电商的顺利运营和数据安全&#xff0c;隐擎fox指纹浏览器作为一种防关联…...

【网络编程】五种网络IO模式

对于一次IO访问&#xff08;以read为例&#xff09;&#xff0c;数据会先被拷贝到操作系统内核的缓冲区中&#xff0c;然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说&#xff0c;当一个read操作发生时&#xff0c;会经历两个阶段&#xff1a; 1、等待数据准…...

面试总结-2023版

本文受众主要为&#xff0c;互联网技术研发人员。 技术面试一般三面和HRBP面不太会卡人&#xff0c;主要都是停在了一面和二面上。我这次换工作前期主要是一面通过率比较低&#xff0c;后面主要是二面通过低。 总结影响面试通过的几点因素&#xff1a; 是否真的招人&#xf…...

bigemap在草原行业的应用案例

一.为什么选择Bigemap 1.使用软件一般都用于套坐标以及空间规划图&#xff0c;方便于项目选址和居民建房报建 2.在卫星图上找到用地范围&#xff0c;然后打点&#xff0c;导出点位范围的2000坐标&#xff0c;用于汇报出图 3.CGCS2000坐标系通过矢量转换转成地方坐标系...

DevOps系列文章之 java调用python脚本

在java类中直接执行python语句 在java类中直接调用本地python脚本 使用Runtime.getRuntime()执行python脚本文件&#xff08;推荐&#xff09; 调用python脚本中的函数 简单介绍 官网地址 首页 | (jython.org) Jython项目提供了Java中的Python实现&#xff0c; 为Python提供了…...

PHP异步框架总结

目前主要有: 国产 swoole workerman 国外 framework-x revoltrevolt reactphp amphp async...

vsto excel 可以异步写入值么

在 VSTO (Visual Studio Tools for Office) 中&#xff0c;Excel 可以使用异步方式写入值。异步编程允许您在后台线程中执行耗时的操作&#xff0c;而不会阻塞主线程&#xff0c;从而提高程序的响应性能。 从 .NET 4.5 开始&#xff0c;可以使用异步和 await 关键字来简化异步…...

Android Gradle 骚操作,将两个项目合并到一个项目中

1. 前言 在工作中&#xff0c;由于各种原因&#xff0c;导致需要将两个可单独运行的App项目&#xff0c;合并到一个git仓库里&#xff0c;且单独的App项目里还有其他Module模块。 如果只是将两个项目复制到同一个文件夹下&#xff0c;还是得单独打开各个项目&#xff0c;是很不…...

虹科案例|如何分析设备故障时间和次数,打破生产瓶颈?

虹科设备绩效管理系统 保障生产设备的稳定性和可靠性 生产设备的稳定性和可靠性是保证企业正常生产的重要条件之一&#xff0c;设备故障的频发严重影响企业的正常生产&#xff0c;那么如何分析设备故障时间和次数&#xff0c;查找设备故障原因&#xff0c;协助企业打破生产瓶…...

SVN代码迁移到Git方法

1.在SVN上新增一个项目 一、点击新建项目 二、创建空白项目 三、填入项目信息 四、myProject项目模板创建成功 2.将代码提交到Git 一、新建一个文件夹myProject&#xff0c;将从SVN下载过来的代码复制一份拷贝到该文件夹下&#xff0c;注意&#xff1a;不要把.SVN文件拷…...

Linux更换阿里云yum源

1、备份 cd /etc/yum.repos.d/ mv CentOS-Base.repo CentOS-Base.backup2、下载新的CentOS-Base.repo 到/etc/yum.repos.d/ wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo如果出现解析错误 Could not resolve host: mirrors.a…...

【1.3】Java微服务:Spring Cloud版本说明

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…...

OpenMP

官方文档&#xff1a;OpenMP | LLNL HPC Tutorials OpenMP总览 统一内存访问&#xff1a;OpenMP、Pthreads 非统一内存访问&#xff1a;MPI OpenMP与Pthread OpenMP原理 串行区到达并行区后会派生多个线程&#xff0c;并行区代码执行完后进行线程合并&#xff0c;剩下主线程 编…...

Eureka 学习笔记4:EurekaClient

版本 awsVersion ‘1.11.277’ EurekaClient 接口实现了 LookupService 接口&#xff0c;拥有唯一的实现类 DiscoveryClient 类。 LookupService 接口提供以下功能&#xff1a; 获取注册表根据应用名称获取应用根据实例 id 获取实例信息 public interface LookupService<…...

前端后端路径问题详解

加了项目名&#xff0c;访问所有页面都是 在 项目名下 出来的路径 不加项目名&#xff0c;访问所有页面都不用加项目名&#xff0c;然后前后端的加/的效果都一样&#xff0c;都是在根目录下没有项目名的路径&#xff01;&#xff01;&#xff01; 后端 一、MVC 1.不管是转发…...

@vue/composition-api原理解析

前言 上一篇文章介绍了vue/composition-api是什么&#xff0c;以及为什么要用&#xff0c;现在来系统地解析一下 vue/composition-api 的实现原理&#xff0c;希望可以加深对其工作机制的理解。 老规矩先分享下AI评价&#xff1a;对vue/composition-api实现原理的介绍整体上非…...

Kubernetes(K8s)从入门到精通系列之三:K8s的基本概念和术语之资源对象概述

Kubernetes K8s从入门到精通系列之三&#xff1a;K8s的基本概念和术语之资源对象概述 K8s中的基本概念和术语大多是围绕资源对象(Resource Object)来说的&#xff0c;而资源对象在总体上可分为以下两类&#xff1a; 某种资源的对象&#xff0c;例如节点(Node)、Pod、服务(Serv…...

cc2652在使用过程中的一些注意事项

可能不只是cc2652有这些坑&#xff0c;估计cc26xx系列都存在。 CCS的预编译宏配置位置 时钟获取 时钟获取__STATIC_INLINE uint32_t SysCtrlClockGet( void )在sys_ctrl.h中&#xff0c;sys_ctrl.h没有在工程路径下面&#xff0c;在其sdk中 节拍时间获取 ICall_getTicks(); …...

YAPI接口自动鉴权功能部署详解

目录 安装准备 在线安装 离线安装 配置使用 安装准备 以下操作&#xff0c;默认要求自己部署过yapi&#xff0c;最好是部署过yapi二次开发环境。 无论是选择在线安装或者是本地安装&#xff0c;都需要安装client工具。 1、yapi-cli&#xff1a;npm install yapi-cli –g…...

【雕爷学编程】Arduino动手做(180)---Seeeduino Lotus开发板3

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…...