mybatis 拦截器

时间:2025-03-02 08:40:01

在mybatis中可被拦截的类型有四种(按照拦截顺序):

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

其实Executor都可以实现ParameterHandler,ResultHandler,StatementHandler拦截器的功能

拦截器一般在业务处理中用于:

1、分页查询

2、多租户添加条件过滤

3、对返回结果,过滤掉审计字段,敏感字段

4、对返回结果中的加密数据进行解密

5、对新增数据自动添加创建人,创建时间,更新时间,更新人 ,对更新数据自动新增更新时间,更新人

现在来用拦截器是实现需求5:

package ;

import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import .*;

import ;
import ;
@Slf4j
@Intercepts( {@Signature(type = ,method = "update",args = {,})})
@Component
public class MyExecutor implements Interceptor {
    @Override
    @SuppressWarnings("unchecked")
    public Object intercept(Invocation invocation) throws Throwable {
        // 根据签名指定的args顺序获取具体的实现类
        // 1. 获取MappedStatement实例, 并获取当前SQL命令类型
        MappedStatement ms = (MappedStatement) ()[0];
        SqlCommandType commandType = ();

        // 2. 获取当前正在被操作的类, 有可能是Java Bean, 也可能是普通的操作对象, 比如普通的参数传递
        // 普通参数, 即是 @Param 包装或者原始 Map 对象, 普通参数会被 Mybatis 包装成 Map 对象
        // 即是 $ParamMap
        Object parameter = ()[1];
        // 获取拦截器指定的方法类型, 通常需要拦截 update
        String methodName = ().getName();
        ("NormalPlugin, methodName; {}, commandType: {}", methodName, commandType);

        // 3. 获取当前用户信息
        User user = new User(1,"yangcai","sssss");
        // 默认测试参数值
        int creator = 2, updater = 3;

        if (parameter instanceof BaseEntity) {
            // 4. 实体类
            BaseEntity entity = (BaseEntity) parameter;
            if (user != null) {
                creator = ();
                updater = ();
            }
            if (("update")) {
                if (()) {
                    (creator);
                    (updater);
                    (());
                    (());
                } else if (()) {
                    (updater);
                    (());
                }
            }
        } else if (parameter instanceof Map) {
            // 5. @Param 等包装类
            // 更新时指定某些字段的最新数据值
            if (()) {
                // 遍历参数类型, 检查目标参数值是否存在对象中, 该方式需要应用编写有一些统一的规范
                // 否则均统一为实体对象, 就免去该重复操作
                Map map = (Map) parameter;
                if (("creator")) {
                    ("creator", creator);
                }
                if (("updateTime")) {
                    ("updateTime",());
                }
            }
        }
        // 6. 均不是需要被拦截的类型, 不做操作
        return ();
    }

    @Override
    public Object plugin(Object target) {
        return (target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}

其实这个也可以用 ParameterHandler来实现,拦截器底层是用了jdk动态代理