MyBatis 自定义拦截的应用

本文介绍了如何在MyBatis中使用插件功能实现自定义拦截器,包括字段自动填充(如创建人、时间、删除标志)以及对SQL执行过程中的分页、数据权限处理。详细阐述了Executor、ParamterHandler、ResultSetHandler和StatementHandler的拦截作用。
摘要由CSDN通过智能技术生成
MyBatis提供一种插件plugin的功能,虽是插件,但拥有拦截器的功能。

通过自定义拦截器可以完成字段自动填充,像创建、更新时间,删除标志,创建人等...
还可以完成自定义数据分页、数据权限的拼接替换等...

拦截器的拦截范围
Executor(update,query,commit,rollback,close,isClosed) 拦截执行器的方法
ParamterHandler(getParamterObject setParamters) 拦截参数的处理
ResultSetHandler(handleResultSets,handleOutputparamters) 拦截结果集处理
StatementHandler(prepare,parameterize,batch,update,query) 拦截sql语法构建的处理

自定义拦截器

Executor

通用字段的自动填充

package com.datasource.config.mybatis;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 针对insert update操作对 创建人 创建时间 删除标志 更新人 更新时间 拦截填充
 *
 * @author Neoooo
 * @since 2023-08-28
 */
@Slf4j
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class MyBatisOperateInterceptor implements Interceptor {

    private static final String CREATE_BY = "createBy";
    private static final String UPDATE_BY = "updateBy";
    private static final String CREATE_TIME = "createTime";
    private static final String UPDATE_TIME = "updateTime";
    private static final String IS_DELETE = "isDelete";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement statement = (MappedStatement) invocation.getArgs()[0];
        // 操作类型 只对 insert update 进行拦截
        SqlCommandType sqlCommandType = statement.getSqlCommandType();
        if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
            Object arg = invocation.getArgs()[1];
            if (arg instanceof Map<?, ?>) {
                for (Object obj : ((Map<?, ?>) arg).values()) {
                    insertOrUpdateOperate(obj, sqlCommandType);
                }
            } else {
                insertOrUpdateOperate(arg, sqlCommandType);
            }
        }
        return invocation.proceed();
    }


    /**
     * 添加或者
     *
     * @param object         数据对象
     * @param sqlCommandType 操作行为 insert or update
     */
    private void insertOrUpdateOperate(Object object, SqlCommandType sqlCommandType) throws IllegalAccessException {
        if (object == null) {
            log.info("object set properties ,object must is not null");
            return;
        }
        List<Field> declaredFields = new ArrayList<>(Arrays.asList(object.getClass().getDeclaredFields()));
        if (object.getClass().getSuperclass() != null && object.getClass().getSuperclass() != Object.class) {
            // 当前类具有超类父类(所有类都是继承于Object 所以要排除掉)
            Field[] superClassFields = object.getClass().getSuperclass().getDeclaredFields();
            declaredFields.addAll(Arrays.asList(superClassFields));
        }
        // 添加
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                System.out.println(declaredField.getName());
                switch (declaredField.getName()) {
                    case CREATE_BY:
                        // 创建人
                        declaredField.set(object, "Neoooo");
                        break;
                    case CREATE_TIME:
                        // 创建时间
                        declaredField.set(object, LocalDateTime.now());
                        break;
                    case IS_DELETE:
                        // 删除标志
                        declaredField.set(object, false);
                        break;
                    default:
                        break;
                }
            } else if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                switch (declaredField.getName()) {
                    case UPDATE_BY:
                        // 更新人 TODO 可获取当前登录用户
                        declaredField.set(object, "admin");
                        break;
                    case UPDATE_TIME:
                        // 更新时间
                        declaredField.set(object, LocalDateTime.now());
                        break;
                    default:
                        break;
                }
            }
        }
    }


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

    @Override
    public void setProperties(Properties properties) {

    }
}
/**
 * 针对myabtis拦截器的使用,注入至ioc容器即可
 *
 * @author Neoooo
 * @since 2023-08-28
 */
@Configuration
public class MyBatisConfiguration {
    @Bean
    public MyBatisOperateInterceptor myBatisOperateInterceptor() {
        return new MyBatisOperateInterceptor();
    }
}

StatementHandler

分页、数据权限的构建

package com.datasource.config.mybatis;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.Properties;

/**
 * 针对sql做一些 封装
 * 分页
 * 权限拼接
 *
 * @author Neoooo
 * @since 2023-08-28
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MyBatisQueryInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        // 通过MetaObject优雅访问对象的属性,这里是访问statementHandler的属性;:MetaObject是Mybatis提供的一个用于方便、
        // 优雅访问对象属性的对象,通过它可以简化代码、不需要try/catch各种reflect异常,同时它支持对JavaBean、Collection、Map三种类型对象的操作。
        MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,new DefaultReflectorFactory());
        // 先拦截到RoutingStatementHandler,里面有个StatementHandler类型的delegate变量,其实现类是BaseStatementHandler,然后就到BaseStatementHandler的成员变量mappedStatement
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        // id为执行的mapper方法的全路径名,如com.uv.dao.UserMapper.insertUser
        String id = mappedStatement.getId();
        // sql语句类型 select、delete、insert、update
        if (SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
            BoundSql boundSql = statementHandler.getBoundSql();
            String sql = boundSql.getSql();
            // TODO 在此阶段可以做一些分页,数据权限的sql拼接,替换等处理
            sql = sql + " limit 1";
            Field sqlField = boundSql.getClass().getDeclaredField("sql");
            sqlField.setAccessible(true);
            sqlField.set(boundSql, sql);
        }
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {

    }
}
/**
 * 针对myabtis拦截器的使用,注入至ioc容器即可
 *
 * @author Neoooo
 * @since 2023-08-28
 */
@Configuration
public class MyBatisConfiguration {
    @Bean
    public MyBatisQueryInterceptor myBatisQueryInterceptor() {
        return new MyBatisQueryInterceptor ();
    }
}
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis是一个提供持久化操作的Java框架,而自定义标签是MyBatis一个重要的功能。自定义标签可以让我们方便地扩展和定制MyBatis的功能,从而更好地满足项目的需求。 自定义标签的实现需要以下几个步骤: 1. 创建一个继承自`org.apache.ibatis.builder.xml.XMLConfigBuilder`的类,并重写其的方法。 2. 在新建的类,通过解析XML文件的方式,获取自定义标签的配置信息。 3. 解析自定义标签的配置信息后,根据配置信息进行相应的处理,例如创建新的对象、注册新的类型处理器等。 4. 在新建的类重写的方法,将处理后的配置信息应用MyBatis的配置对象。 5. 在MyBatis的配置文件引入自定义标签的命名空间,并使用自定义标签。 通过自定义标签,我们可以实现如下功能: 1. 注册自定义的type handler,用于处理自定义的数据类型,如日期类型、枚举类型等。 2. 注册自定义拦截器,用于在执行SQL语句前后进行一些额外逻辑的处理。 3. 注册自定义的插件,用于在MyBatis的执行过程进行一些额外的处理,如打印SQL语句、统计SQL执行时间等。 4. 扩展MyBatis的XML配置文件,实现一些特定的功能需求,如分页查询、动态SQL等。 总之,自定义标签是MyBatis一个非常重要的功能,通过使用自定义标签,我们可以方便地扩展和定制MyBatis的功能,以满足不同项目的需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值