MybatisPlus-InnerInterceptor插件之beforeQuery方法

beforeQuery - 查询操作前置拦截

  1. 方法签名
void beforeQuery(Executor executor, 
                 MappedStatement ms, 
                 Object parameter, 
                 RowBounds rowBounds,
                 ResultHandler resultHandler, 
                 BoundSql boundSql)
  1. 用途
  • 在执行查询SQL之前拦截
  • 可以修改查询参数、SQL语句或执行环境
  1. 典型应用场景
  • 动态表名替换
  • 多租户数据过滤
  • SQL性能监控开始
  • 查询条件自动增强

beforeQuery 方法参数详解

beforeQuery 是 MyBatis-Plus 中非常重要的查询拦截方法,参数解析。

  1. Executor executor
  • 作用

MyBatis 执行器,用于执行SQL操作

  • 典型使用场景

获取当前事务状态

执行额外的查询操作

访问缓存

  • 示例
Transaction transaction = executor.getTransaction();
boolean isCommited = transaction.isCommited();
  1. MappedStatement ms
  • 作用

包含了一条SQL语句的所有配置信息

  • 重要属性

id:Mapper方法的全限定名 (如 "com.example.UserMapper.selectById")

sqlCommandType:SQL类型 (SELECT/INSERT/UPDATE/DELETE)

configuration:MyBatis配置对象

  • 示例
String mapperMethod = ms.getId(); // 获取当前执行的Mapper方法
SqlCommandType sqlType = ms.getSqlCommandType(); // 判断SQL类型
  1. Object parameter
  • 作用

Mapper方法传入的参数

  • 处理技巧

可能是单个参数、Map或@Param注解标注的多参数,需要根据实际业务判断参数类型

  • 示例
if (parameter instanceof Map) {
    Map<?,?> paramMap = (Map<?,?>) parameter;
    Object idValue = paramMap.get("id");
} else if (parameter instanceof Long) {
    Long id = (Long) parameter;
}
  1. RowBounds rowBounds
  • 作用

内存分页参数(不推荐使用)

  • 注意

MyBatis-Plus推荐使用IPage进行物理分页

这个参数通常用于兼容旧代码

  • 示例
int offset = rowBounds.getOffset(); // 获取偏移量
int limit = rowBounds.getLimit();   // 获取每页数量
  1. ResultHandler resultHandler
  • 作用

自定义结果集处理器

  • 典型使用

很少在拦截器中直接使用

可用于自定义结果集处理逻辑

  1. BoundSql boundSql
  • 作用

包含最终要执行的SQL和参数映射信息

  • 核心功能

获取和修改SQL语句

访问参数映射

获取参数值

  • 示例
String sql = boundSql.getSql(); // 获取SQL
List<ParameterMapping> mappings = boundSql.getParameterMappings(); // 获取参数映射
Object parameterObject = boundSql.getParameterObject(); // 获取参数对象

测试使用

# 实现额外的业务数据权限,将task.task_id IN ()自动拼写在sql中
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.zq.common.core.domain.TaskIdQuery;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;
import java.util.Map;
import java.util.Set;

public class StationPermissionInterceptor implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        if (ms.getId().equals("com.zq.mes.craft.mapper.ExecTaskMapper.testPage")) {
            if (parameter instanceof Map) {
                Map<?, ?> paramMap = (Map<?, ?>) parameter;
                Object idValue = paramMap.get("query");
                TaskIdQuery query = (TaskIdQuery) idValue;
                Set<Long> taskIds = query.getTaskIds();
                if (CollectionUtil.isEmpty(taskIds)) {
                    return;
                }
                String taskIdsSQL = convertSetToSqlString(taskIds);
                String originalSql = boundSql.getSql();
                String whereClause = " WHERE task.task_id IN ( " + taskIdsSQL + " )";
                String newSql;
                if (originalSql.contains("WHERE")) {
                    newSql = originalSql.replace("WHERE", whereClause + " AND ");
                } else if (originalSql.contains("where")) {
                    newSql = originalSql.replace("where", whereClause + " and ");
                } else {
                    newSql = originalSql + whereClause;
                }

                // 使用反射修改SQL
                ReflectUtil.setFieldValue(boundSql, "sql", newSql);
            }
        }
    }

    public String convertSetToSqlString(Set<Long> ids) {
        ExpressionList expressionList = new ExpressionList();
        ids.forEach(id -> expressionList.addExpressions(new LongValue(id)));
        return expressionList.toString();
    }
}

# MybatisPlus的配置文件,需将StationPermissionInterceptor加入

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.zq.framework.interceptor.StationPermissionInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * MybatisPlus配置
 *
 * @author zq
 */
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
@RequiredArgsConstructor
public class MybatisPlusConfig {


    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor());
        // 乐观锁插件
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
        // 阻断插件
        interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
        // 测试自定义
        interceptor.addInnerInterceptor(new StationPermissionInterceptor());
        return interceptor;
    }

    /**
     * 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
     */
    public PaginationInnerInterceptor paginationInnerInterceptor() {
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        // 设置数据库类型为mysql
        paginationInnerInterceptor.setDbType(DbType.MYSQL);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        paginationInnerInterceptor.setMaxLimit(-1L);
        return paginationInnerInterceptor;
    }

    /**
     * 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
     */
    public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
        return new OptimisticLockerInnerInterceptor();
    }

    /**
     * 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
     */
    public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
        return new BlockAttackInnerInterceptor();
    }
}

image

posted @ 2025-08-12 04:08  南翔技校毕业后  阅读(70)  评论(0)    收藏  举报