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 的执行性能。
相关推荐
今天过得怎么样2 分钟前
彻底搞懂 Spring Boot 中 properties 和 YAML 的区别
后端
qq_12498707535 分钟前
基于springboot的幼儿园家校联动小程序的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·微信小程序·小程序
武子康43 分钟前
大数据-189 Nginx JSON 日志接入 ELK:ZK+Kafka+Elasticsearch 7.3.0+Kibana 实战搭建
大数据·后端·elasticsearch
断春风1 小时前
订单超时自动取消系统架构解析
后端·系统架构
Angletank1 小时前
SpringBoot中ORM组件通过JAP组件的使用
spring boot·后端·orm·jpa
moxiaoran57531 小时前
Go语言的map
开发语言·后端·golang
小信啊啊1 小时前
Go语言数组
开发语言·后端·golang
白宇横流学长1 小时前
基于SpringBoot实现的零食销售商城设计与实现【源码+文档】
java·spring boot·后端
superman超哥1 小时前
仓颉语言中异常捕获机制的深度剖析与工程实践
c语言·开发语言·后端·python·仓颉
驱动探索者1 小时前
[缩略语大全]之[INTEL]篇
java·后端·spring·intel