一、Mybatis提供了四种类型的拦截器
MyBatis 拦截器(Interceptor)是 MyBatis 提供的一种强大的扩展机制,它允许开发者在不修改 MyBatis 内置逻辑的情况下插入自定义的行为。拦截器主要用于在 SQL 执行的各个阶段进行干预,如预处理、参数设置、结果集处理等环节
拦截的执行顺序是Executor->StatementHandler->ParameterHandler->ResultHandler
1. Executor(执行器拦截器):
- 用途:拦截MyBatis执行器方法的执行。
- 使用:允许拦截和自定义MyBatis执行器的行为。例如,可以添加缓存、日志记录或审计功能到执行器中。这些拦截器可以在MyBatis执行的不同阶段扩展或修改其行为。您可以通过实现MyBatis提供的相应接口并在MyBatis配置文件中进行配置来实现这些拦截器。
2. StatementHandler(语句拦截器):
-- 用途:拦截SQL语句的执行。
- 使用:可以在SQL语句执行之前修改或增强它们。例如,可以向WHERE子句添加额外的条件或记录执行的语句。分页等
3. ParameterHandler(参数拦截器):
- 用途:拦截SQL语句的参数设置。
- 使用:允许在将参数设置到SQL语句之前修改或验证它们。例如,可以对作为参数传递的敏感信息进行加密或解密。
4. ResultHandler(结果集拦截器):
- 用途:拦截从SQL语句返回的结果集的处理。
- 使用:可以在将结果集返回给应用程序之前修改或分析它们。例如,可以对结果集数据进行转换或执行额外的计算。
二、配置(@Intercepts注解--拦截执行器-拦截参数)
@Component
@Intercepts({@Signature(type = ParameterHandler.class,
method = "setParameters",
args = {PreparedStatement.class})})
public class ParameterPlugin implements Interceptor {
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
Object parameterObject = parameterHandler.getParameterObject();
//第一种,性能高
// if(parameterObject instanceof BaseModel){
// BaseModel baseModel = (BaseModel) parameterObject;
// baseModel.setLastUpdateBy(LocalUserUtil.getLocalUser().getNickName());
// }
//第二种使用反射处理,扒光撕开
Field lastUpdateBy = ReflectUtil.getField(parameterObject.getClass(), "lastUpdateBy");
if (lastUpdateBy != null) {
ReflectUtil.setFieldValue(parameterObject,lastUpdateBy,LocalUserUtil.getLocalUser().getNickName());
}
return invocation.proceed();
}
三、MyBatis拦截器执行流程
1、创建自定义拦截器类:实现ibatis下的Intercepter接口,重写intercepter()方法。
2、使用@Intercepters注解指定拦截目标
在自定义拦截器类上使用@Intercepters注解,并同时使用@Signature指定拦截的接口类型,方法名与参数类型
3、在当前类上加@Conponent注解,注入到IOC容器中。
四、MyBatis 拦截器的使用
常用的功能:
-
SQL 修改:动态修改 SQL 语句,例如添加公共查询条件、排序或分页。
-
数据过滤:在查询或更新前后的数据处理,比如对敏感信息进行加密/解密操作,或者基于用户权限进行数据过滤。
-
性能监控:记录 SQL 的执行时间,进行性能分析和日志记录。
-
通用业务逻辑:插入统一的业务逻辑,如自动填充创建时间、更新时间、操作人信息等。
要使用 MyBatis 拦截器,你需要按照以下步骤进行:
-
自定义拦截器类:
- 创建一个实现了
org.apache.ibatis.plugin.Interceptor
接口的类。 - 在该类中重写
intercept
方法,这个方法接收Invocation
对象作为参数,在此方法内可以访问到被拦截的方法信息以及相关的对象,并进行前后置处理。 - 使用
@Intercepts
注解来声明你想要拦截的目标方法签名(Method Signature),指定拦截哪个核心对象的哪个方法。
- 创建一个实现了
-
配置拦截器:
- 在 MyBatis 配置文件(mybatis-config.xml)中的
<plugins>
标签下添加<plugin>
元素,配置拦截器类的全限定名。 - 可以通过
<property>
子标签为拦截器提供额外的属性值。
- 在 MyBatis 配置文件(mybatis-config.xml)中的
1<plugins>
2 <plugin interceptor="com.example.MyInterceptor">
3 <!-- 如果拦截器有属性需要设置 -->
4 <property name="someProperty" value="value"/>
5 </plugin>
6</plugins>
3.在拦截器中实现逻辑: 在自定义拦截器的 intercept
方法内编写实际的业务逻辑,根据需要调用 Invocation.proceed()
来执行原方法,并在前后做相应的处理。
实现代码如下:
package cn.yy.config;
import cn.example.core.threadlocal.LocalUserUtil;
import cn.hutool.core.util.ReflectUtil;
import org.apache.ibatis.executor.parameter.ParameterHandler;
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.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.PreparedStatement;
@Component
@Intercepts({
// 指定要拦截的方法签名,这里是拦截Executor的update方法
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
// 可以添加更多要拦截的方法签名...
})
public class ParameterInterceptor implements Interceptor {
//拦截器给lastUpdateBy属性添加值 LocalUserUtil.getLocalUser().getNickName()
@Override
public Object intercept(Invocation invocation) throws Throwable {
ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
Object parameterObject = parameterHandler.getParameterObject();
//第一种,性能高
// if(parameterObject instanceof BaseModel){
// BaseModel baseModel = (BaseModel) parameterObject;
// baseModel.setLastUpdateBy(LocalUserUtil.getLocalUser().getNickName());
// }
//第二种使用反射处理,扒光撕开
Field lastUpdateBy = ReflectUtil.getField(parameterObject.getClass(), "lastUpdateBy");
if (lastUpdateBy != null) {
ReflectUtil.setFieldValue(parameterObject,lastUpdateBy, LocalUserUtil.getLocalUser().getNickName());
}
return invocation.proceed();
}
}
注:修改操作中不能使用动态sql