Java 自定义 mybatis 多拦截器协作给SQL动态批量添加过滤条件

下面将为你详细介绍如何通过自定义 MyBatis 多拦截器协作,在 XML 文件中为 SQL 添加过滤条件。我们会创建两个拦截器,一个用于在 SQL 执行前解析并添加过滤条件,另一个用于打印添加条件后的 SQL 信息。

实现思路

  1. 自定义拦截器 :创建两个实现 ​​Interceptor​​ 接口的拦截器类。第一个拦截器用于在 SQL 中添加过滤条件,第二个拦截器用于打印添加条件后的 SQL 信息。

  2. 注册拦截器 :将这些拦截器注册到 MyBatis 的 ​​InterceptorChain​​ 中。

  3. 定义拦截顺序:按照业务需求,确定各个拦截器的执行顺序。

代码示例

第一个拦截器,在 SQL 中添加过滤条件 AddFilterConditionInterceptor

java 复制代码
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.util.Properties;

// 第一个拦截器,在 SQL 中添加过滤条件
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class AddFilterConditionInterceptor implements Interceptor {

    private static final String FILTER_CONDITION = " AND status = 'ACTIVE'";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        BoundSql boundSql = statementHandler.getBoundSql();
        String originalSql = boundSql.getSql();

        // 检查 SQL 是否为 SELECT 语句
        if (originalSql.trim().toUpperCase().startsWith("SELECT")) {
            String newSql = originalSql + FILTER_CONDITION;
            metaObject.setValue("delegate.boundSql.sql", newSql);
        }

        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        // 设置属性
    }
}

第二个拦截器,打印添加条件后的 SQL 信息 PrintSqlInterceptor

java 复制代码
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;

import java.sql.Connection;
import java.util.Properties;

// 第二个拦截器,打印添加条件后的 SQL 信息
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class PrintSqlInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql();
        System.out.println("Modified SQL: " + sql);
        return invocation.proceed();
    }

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

    @Override
    public void setProperties(Properties properties) {
        // 设置属性
    }
}

MyBatis 配置类,注册拦截器

java 复制代码
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;

// MyBatis 配置类,注册拦截器
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);

        // 创建拦截器实例
        AddFilterConditionInterceptor addFilterConditionInterceptor = new AddFilterConditionInterceptor();
        PrintSqlInterceptor printSqlInterceptor = new PrintSqlInterceptor();

        // 获取 MyBatis 配置
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        // 添加拦截器
        configuration.addInterceptor(addFilterConditionInterceptor);
        configuration.addInterceptor(printSqlInterceptor);

        sessionFactory.setConfiguration(configuration);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return sessionFactory.getObject();
    }
}

代码解释

  1. ​AddFilterConditionInterceptor​
  • 该拦截器在 SQL 执行前进行拦截。
  • 通过 ​MetaObject​ 获取原始 SQL 语句。
  • 检查 SQL 是否为 ​SELECT​ 语句,如果是,则在原 SQL 后面添加过滤条件 ​AND status = 'ACTIVE'​
  • 使用 ​metaObject.setValue​ 方法更新 SQL 语句。
  1. ​PrintSqlInterceptor​
  • 该拦截器在 SQL 执行前进行拦截。
  • 获取添加过滤条件后的 SQL 语句并打印。
  1. ​MyBatisConfig​
  • 这是 MyBatis 的配置类,通过 ​​SqlSessionFactoryBean​​​ 创建 ​​SqlSessionFactory​​。

  • 在配置中添加自定义的拦截器,拦截器的添加顺序即为执行顺序。

注意事项

  • 拦截器的执行顺序由添加到 ​Configuration​ 中的顺序决定。
  • 过滤条件的添加逻辑可以根据实际需求进行修改,例如从上下文或参数中获取动态条件。
  • 多个拦截器之间要避免逻辑冲突,以免影响系统的正常运行。
  • 拦截器的逻辑要尽量简洁,避免影响 SQL 的执行性能。
相关推荐
野犬寒鸦1 天前
从零起步学习并发编程 || 第一章:初步认识进程与线程
java·服务器·后端·学习
我爱娃哈哈1 天前
SpringBoot + Flowable + 自定义节点:可视化工作流引擎,支持请假、报销、审批全场景
java·spring boot·后端
李梨同学丶1 天前
0201好虫子周刊
后端
思想在飞肢体在追1 天前
Springboot项目配置Nacos
java·spring boot·后端·nacos
Loo国昌2 天前
【垂类模型数据工程】第四阶段:高性能 Embedding 实战:从双编码器架构到 InfoNCE 损失函数详解
人工智能·后端·深度学习·自然语言处理·架构·transformer·embedding
ONE_PUNCH_Ge2 天前
Go 语言泛型
开发语言·后端·golang
良许Linux2 天前
DSP的选型和应用
后端·stm32·单片机·程序员·嵌入式
不光头强2 天前
spring boot项目欢迎页设置方式
java·spring boot·后端
怪兽毕设2 天前
基于SpringBoot的选课调查系统
java·vue.js·spring boot·后端·node.js·选课调查系统
学IT的周星星2 天前
Spring Boot Web 开发实战:第二天,从零搭个“会卖萌”的小项目
spring boot·后端·tomcat