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 的执行性能。
相关推荐
沐雨橙风ιε14 分钟前
Spring Boot整合Apache Shiro权限认证框架(应用篇)
java·spring boot·后端·apache shiro
考虑考虑17 分钟前
fastjson调用is方法开头注意
java·后端·java ee
小蒜学长37 分钟前
springboot基于javaweb的小零食销售系统的设计与实现(代码+数据库+LW)
java·开发语言·数据库·spring boot·后端
brzhang1 小时前
为什么 OpenAI 不让 LLM 生成 UI?深度解析 OpenAI Apps SDK 背后的新一代交互范式
前端·后端·架构
EnCi Zheng1 小时前
JPA 连接 PostgreSQL 数据库完全指南
java·数据库·spring boot·后端·postgresql
brzhang1 小时前
OpenAI Apps SDK ,一个好的 App,不是让用户知道它该怎么用,而是让用户自然地知道自己在做什么。
前端·后端·架构
LucianaiB2 小时前
从玩具到工业:基于 CodeBuddy code CLI 构建电力变压器绕组短路智能诊断系统
后端
武子康3 小时前
大数据-118 - Flink 批处理 DataSet API 全面解析:应用场景、代码示例与优化机制
大数据·后端·flink
不要再敲了3 小时前
Spring Security 完整使用指南
java·后端·spring
IT_陈寒3 小时前
Redis 高性能缓存设计:7个核心优化策略让你的QPS提升300%
前端·人工智能·后端