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

MyBatis自定义拦截器

在Spring Boot中配置MyBatis拦截器的核心是将自定义拦截器注册到MyBatis的SqlSessionFactory中(MyBatis所有拦截器都需通过该工厂注册才能生效)。以下是完整、分场景的配置方案,包含基础配置、多拦截器、属性定制、注解版/XML版适配等,适配Spring Boot2/3版本。

一、自定义MyBatis拦截器

先实现一个标准的MyBatis拦截器(以「SQL耗时统计」为例),后续以此为例配置:

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;import java.util.Properties;/*** 示例拦截器:统计SQL执行耗时*/
// 拦截Executor的query/update方法(可根据需求替换拦截点)
@Intercepts({@Signature(type = Executor.class, method = "query",args = {org.apache.ibatis.mapping.MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "update",args = {org.apache.ibatis.mapping.MappedStatement.class, Object.class})
})
public class SqlCostInterceptor implements Interceptor {// 核心拦截逻辑@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.currentTimeMillis();try {// 执行原SQL方法return invocation.proceed();} finally {// 统计耗时long cost = System.currentTimeMillis() - startTime;System.out.println("SQL执行耗时:" + cost + "ms");}}// 包装目标对象(MyBatis自动调用,推荐用Plugin.wrap标准写法)@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}// 读取拦截器配置属性(可选)@Overridepublic void setProperties(Properties properties) {// 示例:读取配置的"logLevel"属性String logLevel = properties.getProperty("logLevel", "INFO");System.out.println("拦截器配置日志级别:" + logLevel);}
}

二、注册拦截器到SqlSessionFactory

Spring Boot中无需XML配置,通过@Configuration配置类注册SqlSessionFactory,并将拦截器注入其中。

2.1 方式1:基础版(单拦截器,无自定义属性)

适合拦截器无需配置属性、仅需简单注册的场景:

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;@Configuration
@MapperScan("com.yourpackage.mapper") // 替换Mapper接口包路径
public class MyBatisConfig {/*** 配置SqlSessionFactory,注册拦截器*/@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();// 1. 设置数据源(Spring Boot自动配置的数据源,直接注入)sessionFactoryBean.setDataSource(dataSource);// 2. 可选:加载Mapper.xml(注解版Mapper可省略)sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/**/*.xml") // 替换Mapper.xml路径);// 3. 核心:创建拦截器实例并注册SqlCostInterceptor sqlCostInterceptor = new SqlCostInterceptor();sessionFactoryBean.setPlugins(sqlCostInterceptor); // 单拦截器直接传入// 4. 可选:MyBatis 全局配置(如驼峰命名、日志等)org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true); // 下划线转驼峰sessionFactoryBean.setConfiguration(configuration);return sessionFactoryBean.getObject();}
}

2.2 方式2:进阶版(多拦截器+自定义属性)

适合需要注册多个拦截器、或给拦截器配置自定义属性的场景(如加密/解密拦截器):

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;
import java.util.Properties;@Configuration
@MapperScan("com.yourpackage.mapper")
public class MyBatisConfig {// ========== 1. 声明拦截器 Bean(便于依赖注入、属性配置) ==========@Beanpublic SqlCostInterceptor sqlCostInterceptor() {SqlCostInterceptor interceptor = new SqlCostInterceptor();// 给拦截器设置自定义属性(对应 intercept.setProperties 方法)Properties props = new Properties();props.setProperty("logLevel", "DEBUG");interceptor.setProperties(props);return interceptor;}// 示例:加密拦截器@Beanpublic EncryptParameterInterceptor encryptParameterInterceptor() {return new EncryptParameterInterceptor();}// 示例:解密拦截器@Beanpublic DecryptResultSetInterceptor decryptResultSetInterceptor() {return new DecryptResultSetInterceptor();}// ========== 2. 注册拦截器到 SqlSessionFactory ==========@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource,SqlCostInterceptor sqlCostInterceptor,EncryptParameterInterceptor encryptInterceptor,DecryptResultSetInterceptor decryptInterceptor) throws Exception {SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();sessionFactoryBean.setDataSource(dataSource);// 可选:加载 Mapper.xmlsessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));// 核心:注册多个拦截器(数组形式传入)sessionFactoryBean.setPlugins(sqlCostInterceptor, encryptInterceptor, decryptInterceptor);return sessionFactoryBean.getObject();}
}

2.3 方式3:极简版(仅Spring Boot+注解版MyBatis)

若项目完全使用注解版Mapper(无XML),且拦截器无自定义属性,可简化配置:

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;@Configuration
@MapperScan("com.yourpackage.mapper")
public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();sessionFactoryBean.setDataSource(dataSource);// 直接注册拦截器sessionFactoryBean.setPlugins(new SqlCostInterceptor(),new EncryptParameterInterceptor(),new DecryptResultSetInterceptor());return sessionFactoryBean.getObject();}
}

三、关键注意事项

3.1 拦截器执行顺序

MyBatis 拦截器遵循责任链模式:

  • setPlugins(拦截器A, 拦截器B, 拦截器C) 中,注册顺序越靠前,执行顺序越靠后;
  • 例如:注册顺序为「加密拦截器 → 解密拦截器 → 耗时统计拦截器」,执行时顺序为「耗时统计 → 解密 → 加密」;
  • 若拦截不同接口(如 ParameterHandler/ResultSetHandler/Executor),顺序不影响;若拦截同一接口,需按业务逻辑调整。

3.2 拦截器生效的前提

  • @MapperScan必须扫描到你的Mapper接口(否则Mapper无法被MyBatis管理,拦截器不生效);
  • 拦截器的@Intercepts注解必须正确:type(拦截接口)、method(拦截方法)、args(方法参数类型)需与MyBatis源码完全匹配;
  • SqlSessionFactory必须被Spring扫描到(配置类加@Configuration)。

3.3 常见拦截点参考

拦截接口 拦截方法 适用场景
Executor query/update SQL 执行耗时、分页、数据权限
ParameterHandler setParameters 参数加密、参数校验
ResultSetHandler handleResultSets 结果集解密、数据脱敏
StatementHandler prepare SQL 改写、SQL 日志打印

3.4 调试拦截器是否生效

  1. 在拦截器的intercept方法中加System.out.println或日志,执行Mapper方法查看是否输出;
  2. 打断点:在intercept方法中打断点,调试执行Mapper方法,确认是否进入拦截逻辑;
  3. 检查Spring上下文:启动项目后,查看SqlSessionFactory Bean是否包含你的拦截器(可通过Spring Boot Actuator或调试模式查看)。

四、常见问题排查

4.1 拦截器不生效

  1. 检查@Intercepts注解的type/method/args是否正确(参数类型必须是全限定类名);
  2. 检查SqlSessionFactory是否注册了拦截器(断点查看sessionFactoryBean.getPlugins());
  3. 检查Mapper接口是否被@MapperScan扫描(未扫描则MyBatis不会处理该Mapper)。

4.2 拦截器执行顺序错误

  1. 调整setPlugins中拦截器的传入顺序(注册顺序与执行顺序相反);
  2. 若需精准控制,可自定义InterceptorChain,但不推荐(破坏MyBatis原生逻辑)。

4.3 反射报错(如字段不可访问)

  1. 在拦截器中处理实体字段时,需调用field.setAccessible(true);
  2. 避免拦截String/Integer等基础类型(无字段可反射)。

通过以上配置,即可在Spring Boot中灵活配置MyBatis拦截器,适配单/多拦截器、注解/XML版MyBatis、自定义属性等场景。

http://www.jsqmd.com/news/65706/

相关文章:

  • 网线大鲨鱼
  • 深入解析:mysql内置函数——了解常用的函数
  • 【P1】win10安装 Docker教程 - 详解
  • csq-蓝桥杯python-基础语法1-逻辑运算与条件语句
  • 高级语言程序设计第八次个人作业
  • Cor1e的支票
  • 卷积神经网络是从多层感知机基础上发展起来的吗?
  • gaussdb json解析
  • 详细介绍:python logging模块:专业日志记录
  • JAX核心设计解析:函数式编程让代码更可控
  • 20232305 2025-2026-1 《网络与系统攻防技术》实验八实验报告
  • 患者投诉管理,是否正面临这些难题?
  • NOIP 游记
  • CF794E Choosing Carrot
  • 澄清:梯度下降优化的是模型参数,而非损失函数本身
  • 用心算感受天地运行法则的气功
  • 一文带你搞懂 AI Agent 开发利器:LangGraph 与 LangChain 区别
  • core学习之路
  • XXL-JOB v3.3.1 发布 | 升级SpringBoot4、健壮性增强
  • 梯度:明明是个“方向”,为啥偏叫“度”?
  • 苹果游戏订阅服务新增六款作品,涵盖模拟与动作冒险类型
  • 深入解析:【WPF】WrapPanel的用法
  • 10407_基于springboot的就业信息分享系统
  • U渠道:构建百万级广告甲乙方资源生态,助力行业高效对接与价值共赢
  • 微信小程序开发案例 | 幸运抽签小工具(上)
  • 学习笔记
  • 陪诊不是“陪跑”——北京陪诊机构调研榜出炉,三家机构凭实力登榜
  • 梯度下降:站在碗壁,如何找到最低点?
  • 牛客周赛121
  • 北京陪诊服务市场调研揭晓,三大机构凭何脱颖而出?