MyBatis 四种类型拦截器、MyBatis拦截器执行流程

一、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 拦截器的使用

常用的功能:

  1. SQL 修改:动态修改 SQL 语句,例如添加公共查询条件、排序或分页。

  2. 数据过滤:在查询或更新前后的数据处理,比如对敏感信息进行加密/解密操作,或者基于用户权限进行数据过滤。

  3. 性能监控:记录 SQL 的执行时间,进行性能分析和日志记录。

  4. 通用业务逻辑:插入统一的业务逻辑,如自动填充创建时间、更新时间、操作人信息等。

要使用 MyBatis 拦截器,你需要按照以下步骤进行:

  1. 自定义拦截器类

    • 创建一个实现了 org.apache.ibatis.plugin.Interceptor 接口的类。
    • 在该类中重写 intercept 方法,这个方法接收 Invocation 对象作为参数,在此方法内可以访问到被拦截的方法信息以及相关的对象,并进行前后置处理。
    • 使用 @Intercepts 注解来声明你想要拦截的目标方法签名(Method Signature),指定拦截哪个核心对象的哪个方法。
  2. 配置拦截器

    • 在 MyBatis 配置文件(mybatis-config.xml)中的 <plugins> 标签下添加 <plugin> 元素,配置拦截器类的全限定名。
    • 可以通过 <property> 子标签为拦截器提供额外的属性值。
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

 

 

 

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值