Mybatis拦截器Interceptor

article/2025/10/1 8:17:14

前言

最近项目使用Mybatis拦截器对数据进行加解密,以下记录如何将拦截器集成到项目中以及在使用过程中踩过的一些小坑,与君共勉

1.Myabtis拦截器是什么?

MyBatis允许使用者在映射语句执行过程中的某一些指定的节点进行拦截调用,通过织入拦截器,在不同节点修改一些执行过程中的关键属性,从而影响SQL的生成、执行和返回结果,如:来影响Mapper.xml到SQL语句的生成、执行SQL前对预编译的SQL执行参数的修改、SQL执行后返回结果到Mapper接口方法返参POJO对象的类型转换和封装等。

2. 基础介绍

2.1 核心对象

从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:

  • Configuration:初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如插件,映射器,ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中。
  • SqlSessionFactory:SqlSession工厂。
  • SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要的数据库增删改查功能。
  • Executor:MyBatis的内部执行器,它负责调用StatementHandler操作数据库,并把结果集通过ResultSetHandler进行自动映射,另外,它还处理二级缓存的操作。
  • StatementHandler:MyBatis直接在数据库执行SQL脚本的对象。另外它也实现了MyBatis的一级缓存。
  • ParameterHandler:负责将用户传递的参数转换成JDBC Statement所需要的参数。是MyBatis实现SQL入参设置的对象。
  • ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合。是MyBatis把ResultSet集合映射成POJO的接口对象。
  • TypeHandler:负责Java数据类型和JDBC数据类型之间的映射和转换。
  • MappedStatement:MappedStatement维护了一条<select|update|delete|insert>节点的封装。
  • SqlSource :负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回。
  • BoundSql:表示动态生成的SQL语句以及相应的参数信息。

2. 2 执行流程

在这里插入图片描述

3. 如何使用

3. 1 创建拦截器

创建拦截器并实现org.apache.ibatis.plugin.Interceptor接口
类上添加@Intercepts注解
两种方式使拦截器生效

  • 类上添加@Component注解,使其成为Spring管理的Bean(推荐这种方式,但是有坑,后面介绍)
  • mybatis配置
  ##yaml增加以下配置mybatis:config-location: classpath:mybatis/mybatis-config.xml
 <!-- 创建mybatis-config.xml文件,内容如下--> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC"-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><plugins><plugin interceptor="***.***Interceptor"/></plugins> </configuration>

3. 2 添加注解

MyBatis拦截器默认可以拦截的类型只有四种,即四种接口类型Executor、StatementHandler、ParameterHandler和ResultSetHandler。对于我们的自定义拦截器必须使用MyBatis提供的@Intercepts注解来指明我们要拦截的是四种类型中的哪一种接口。

  • @Intercepts:标志该类是一个拦截器
  • @Signature:指明该拦截器需要拦截哪一个接口的哪一个方法

@Signature注解的参数:

参数描述
type四种类型接口中的某一个接口,如Executor.class 、StatementHandler.class、ParameterHandler.class、ResultSetHandler.class
method对应接口中的某一个方法名,比如Executor的query方法
args对应接口中的某一个方法的参数,比如Executor中query方法因为重载原因,有多个,args就是指明参数类型,从而确定是具体哪一个方法
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})

3. 2.1 type

MyBatis拦截器默认会按顺序拦截以下的四个接口中的所有方法:

org.apache.ibatis.executor.Executor  //拦截执行器方法
org.apache.ibatis.executor.statement.StatementHandler  //拦截SQL语法构建处理
org.apache.ibatis.executor.parameter.ParameterHandler  //拦截参数处理
org.apache.ibatis.executor.resultset.ResultSetHandler  //拦截结果集处理

具体是拦截这四个接口对应的实现类:

org.apache.ibatis.executor.CachingExecutor
org.apache.ibatis.executor.statement.RoutingStatementHandler
org.apache.ibatis.scripting.defaults.DefaultParameterHandler
org.apache.ibatis.executor.resultset.DefaultResultSetHandler

3. 3 代码示例

以下演示数据加解密过程
首先通过更新拦截器执行数据加密


/*** 这里拦截数据插入、修改、删除sql* 在数据插入或更新时执行数据加密* **/
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,Object.class}),
})
public class UpdateInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();Object parameterObject = invocation.getArgs()[1];boolean paramMapFlag = false;if (parameterObject instanceof MapperMethod.ParamMap) { // 当sql类型时UPDATE时,参数稍微有点变化MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameterObject;Set set = paramMap.keySet();for (Object key : set) {paramMap.get(key);parameterObject = paramMap.get(key);if (SqlCommandType.UPDATE.equals(sqlCommandType)) { encrypt(parameterObject); //加密paramMap.put(key, parameterObject);paramMapFlag = true;}}invocation.getArgs()[1] = paramMap;if (paramMapFlag) {return invocation.proceed();}}encrypt(parameterObject); //加密invocation.getArgs()[1] = parameterObject;return invocation.proceed();}@Overridepublic Object plugin(Object o) {return Plugin.wrap(o, this);}@Overridepublic void setProperties(Properties properties) {}
}

通过返回值拦截器进行数据解密

/*** 数据解密拦截器,这里拦截返回值并解密*/
@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class ResultInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object result = invocation.proceed();decrypt(result);	//返回值被拦截后,执行解密解密方法return result;}@Overridepublic Object plugin(Object o) {return Plugin.wrap(o, this);}@Overridepublic void setProperties(Properties properties) {}}

4. 踩坑集合

  • 不能使用依赖注入的方式,直接在拦截器里面注入其他的Bean
    在这里插入图片描述
    原因:拦截器的优先级高于Spring Bean容器的加载顺序
    解决方案:通过ApplicationContext存储Bean,通过getBean()的方式获取

  • 拦截器失效的部分场景,比如多数据源配置导致拦截器失效
    通此时需要手动创建sessionFactory并指定拦截器

 @Bean(name = "sessionFactory")public SqlSessionFactory sessionFactory(@Qualifier("dynamicDataSource") DynamicDataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();mybatisSqlSessionFactoryBean.setDataSource(dataSource);mybatisSqlSessionFactoryBean.setPlugins(ResultInterceptor, UpdateInterceptor);return mybatisSqlSessionFactoryBean.getObject();}

5. 总结

可以使用Mybatis拦截器来做一些数据过滤、数据加密脱敏、SQL执行时间性能监控和告警,当然也会额外产生一些性能开销,合理利用拦截器将会大大缩减开发成本。


http://chatgpt.dhexx.cn/article/54O9gU6P.shtml

相关文章

Springboot 自定义mybatis 拦截器,实现我们要的扩展

前言 相信大家对拦截器并不陌生&#xff0c;对mybatis也不陌生。 有用过pagehelper的&#xff0c;那么对mybatis拦截器也不陌生了&#xff0c;按照使用的规则触发sql拦截&#xff0c;帮我们自动添加分页参数 。 那么今天&#xff0c;我们的实践 自定义mybatis拦截器也是如此&a…

mybatis 拦截器

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

Mybatis——拦截器Interceptor

本篇介绍Mybatis拦截器/插件相关知识&#xff0c;包括相关的类及作用、拦截器有哪几种、拦截器可以在Mybatis的执行过程中的哪些节点起作用、拦截器如何使用、相关的API&#xff0c;最后附上代码示例。 1. Mybatis拦截器是什么&#xff1f;一般用途&#xff1f; MyBatis允许使…

vue后台管理框架(iview + vue)

iview官网&#xff1a;https://www.iviewui.com/docs/introduce vueiview后台管理文档&#xff1a;https://lison16.github.io/iview-admin-doc/#/ vueiview后台管理线上示例&#xff1a;https://admin.iviewui.com/login vueiview后台管理github&#xff1a;https://github.co…

基于ThinkPHP6+Layui的后台管理框架

项目介绍 一款 PHP 语言基于 ThinkPhp6.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架&#xff0c;可用于快速搭建前后端分离后台管理系统&#xff0c;本着简化开发、提升开发效率的初衷&#xff0c;框架自研了一套个性化的组件&am…

Quickadmin:基于ThinkPhp6+Vue+ElementUI后台管理框架

Quickadmin&#xff1a;基于ThinkPhp6VueElementUI后台管理框架 简介 QuickAdmin 是一款基于ThinkPHP 6.x&#xff0c;ElementUI&&Vue 2.x前后端分离后台管理框架&#xff0c;通过框架自带的在线代码生成器&#xff0c;可以轻松的实现后台管理的curd&#xff08;增删…

后台管理怎样用html实现,后台管理实现

京淘后台管理实现 1.1 商品列表展现 1.1.1 商品POJO对象 1.1.2 表格数据页面结构 1.1.3 请求URL地址 说明&#xff1a;如果采用UI框架并且添加了分页插件&#xff0c;则会自动的形成如下的URL请求地址 1.1.4 编辑ItemController 1.1.5 编辑ItemService 1.1.6 编辑ItemMapper 手…

【React项目架构 】+后台管理系统cms实操

React项目架构 一、 react脚手架 (一) 、yarn 安装 (二) 、react安装 npx create-react-app [-g] npm i react17.0.0 react-dom17.0.0 babel-standalone6.26.0 npm i react-router-dom npm i redux4.1.1 --save npm i redux-thunk2.4.1 npm i redux-persist npm install an…

Python实现的一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台,不用配置各种运行环境

Mini Admin 完整代码下载地址&#xff1a;Python实现的一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台 Mini Admin,一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台 &#x1f680; 应用场景&#xff1a;2-5人的管理团队&#xff0c;需要管理的资源数…

vue——后台管理系统框架

效果图 代码: <template><el-container class="box-el-container"><el-aside class="box-el-aside" :style="{width:isCollapse?60px:200px}"><el-col :span="12" class="el-menu-aside"><!…

基于ThinkPHP6+Layui通用后台管理框架

项目介绍 一款 PHP 语言基于 ThinkPhp6.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架&#xff0c;可用于快速搭建前后端分离后台管理系统&#xff0c;本着简化开发、提升开发效率的初衷&#xff0c;框架自研了一套个性化的组件&am…

Rust学习指南(一)安装RUST后台管理框架

Windows安装 Rust安装非常简单&#xff0c;只要将Visual Studio的 Visual Studio的构建工具或者Visual Stuido 2022的构件工具安装即可。当被问及要安装哪些内容时&#xff0c;请确保已选择 “C build tools”&#xff0c;并包括 Windows 10 SDK 和英文语言包。具体可以参考这个…

php是一种通用开源,caozha-admin(PHP网站后台管理框架)

caozha-admin 后台管理框架 1.7.2 caozha-admin是一个通用的PHP网站后台管理框架&#xff0c;基于开源的ThinkPHP开发&#xff0c;特点&#xff1a;易上手&#xff0c;零门槛&#xff0c;界面清爽极简&#xff0c;极便于二次开发。 基础功能 1、系统设置 2、管理员管理 3、权限…

移动端后台管理系统框架

创建此项目的初衷 目前移动端越来越重要&#xff0c;好多项目都从PC端转移到了移动端。 前一段给客户做了一个PC和M自适应的项目&#xff0c;用vue-element-admin框架&#xff0c;手机端也能用&#xff0c;但体验有点差&#xff0c;客户改了好多。本来是好意&#xff0c;客户只…

(若依)RuoYi后台管理框架前端

若依后台管理 官方网址 后台管理二开推荐 官网的源码地址可供下载前后端代码 最近进到公司后跟着团队接了两家公司的App一套的开发&#xff0c;到公司的第一天就是先配置开发环境 安装软件之类的 第二天 带着熟悉RuoYi框架 很巧带我的大哥和我是一个学校毕业的 是大师兄 若依…

后台管理系统框架bootstrap中文版

简介&#xff1a; 后台管理系统框架bootstrap中文版 网盘下载地址&#xff1a; http://kekewl.cc/8TLdhidu7gi0 图片&#xff1a;

SpringBoot后台管理系统框架

SpringBoot后台管理系统框架 SpringBoot后台管理系统功能介绍 登录 注册 用户列表和添加功能 只是个框架 实现了shiro权限控制, 详细的shiro使用 一个模板项目系统 只有少量功能 使用技术 SpringBoot框架 Mysql数据库 redis shiro权限 thymeleaf(前端) 功能展示 shi…

thinkphp 后台管理框架swiftadmin的使用

SwiftAdmin 极速开发框架 这款框架是基于ThinkPHP Layui 完美契合&#xff0c;在开发上采用最精简最高效的做法去完成业务系统的需求&#xff0c;是一款优秀的中后台极速开发解决方案。 可以很卡快的上手开发&#xff0c;而且他的文档也很完善&#xff0c;代码量不是很多&…

layui搭建后台管理框架

简介&#xff1a;layui&#xff08;谐音&#xff1a;类UI) 是一款采用自身模块规范编写的前端 UI 框架&#xff0c;遵循原生 HTML/CSS/JS 的书写与组织形式&#xff0c;门槛极低&#xff0c;拿来即用。其外在极简&#xff0c;却又不失饱满的内在&#xff0c;体积轻盈&#xff0…

后台管理框架搭建

搭建一套通用的后台管理框架对于以后的快速开发时是非常重要的。通常框架需要包含权限验证、日志、及一些基础数据的增删改查功能。 本框架采用Spring MVCMybatisFreemarkerAdminlte前端 组合在一起搭建一个管理系统。 大概的样子如下&#xff1a; 1.权限 角色->应用-&…