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 的执行性能。
相关推荐
阳光是sunny2 小时前
LangGraph中的Reducer是什么
前端·人工智能·后端
灯澜忆梦2 小时前
GO_并发编程---定时器
开发语言·后端·golang
阳光是sunny2 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
皮皮林5512 小时前
开源实力派,给本地 AI 装上深度调研能力,一张 3090 跑到 95.7 分!
后端
努力的小雨3 小时前
把 Windows 桌面图标做成一个会自己运转的小世界
后端
武子康3 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
腾渊信息科技公司4 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
IT_陈寒5 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学5 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈6 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端