MybatisPlus-InnerInterceptor插件之beforeQuery方法
beforeQuery - 查询操作前置拦截
- 方法签名
void beforeQuery(Executor executor,
MappedStatement ms,
Object parameter,
RowBounds rowBounds,
ResultHandler resultHandler,
BoundSql boundSql)
- 用途
- 在执行查询SQL之前拦截
- 可以修改查询参数、SQL语句或执行环境
- 典型应用场景
- 动态表名替换
- 多租户数据过滤
- SQL性能监控开始
- 查询条件自动增强
beforeQuery 方法参数详解
beforeQuery 是 MyBatis-Plus 中非常重要的查询拦截方法,参数解析。
- Executor executor
- 作用
MyBatis 执行器,用于执行SQL操作
- 典型使用场景
获取当前事务状态
执行额外的查询操作
访问缓存
- 示例
Transaction transaction = executor.getTransaction();
boolean isCommited = transaction.isCommited();
- 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类型
- 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;
}
- RowBounds rowBounds
- 作用
内存分页参数(不推荐使用)
- 注意
MyBatis-Plus推荐使用IPage进行物理分页
这个参数通常用于兼容旧代码
- 示例
int offset = rowBounds.getOffset(); // 获取偏移量
int limit = rowBounds.getLimit(); // 获取每页数量
- ResultHandler resultHandler
- 作用
自定义结果集处理器
- 典型使用
很少在拦截器中直接使用
可用于自定义结果集处理逻辑
- 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();
}
}