概要
原项目无任何数据权限,需要统一解决查询数据权限问题,框架使用的mybatis plus,因此想到使用mybatis plus拦截器,根据官网示例编写代码,但是在拦截器的代码实现中发现bean对象无法正常获取到,提示都是空指针异常
mybatis plus拦截器实现查询数据权限代码
配置拦截器代码
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description
* @Author Z
* @Date 15:36 2024/2/1
* @Version 1.0
**/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MARIADB);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(500L);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
//添加查询过滤器
interceptor.addInnerInterceptor(new QueryInterceptor());
return interceptor;
}
}
拦截器代码
/**
* @Description
* @Author Z
* @Date 16:09 2024/2/1
* @Version 1.0
**/
@Configuration
public class QueryInterceptor extends JsqlParserSupport implements InnerInterceptor {
@Resource
private StringRedisTemplate redisTemplate;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(this.parserSingle(mpBs.sql(), ms.getId()));
}
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
Object k_name = redisTemplate.opsForValue().get("k_name");
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody, (String) obj);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
}
}
/**
* 设置 where 条件
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
*/
private void setWhere(PlainSelect plainSelect, String whereSegment) {
}
}
问题
这样写以为会没问题,但是在debug调试中RedisTemplate提示NullPointerException
原因
- mybatis plus拦截器是在Spring bean注入前生效的,所以导致拦截器中想要使用Spring
- IOC的Bean容器是获取不到的,因此就变成了NullPointerException mybatis
plus添加拦截器时使用的是new QueryInterceptor(),没有交给Spring管理
我的解决方式
mybatis plus添加拦截器时使用Bean注入,交由Spring IOC来管理
更改后的代码:
配置拦截器代码
/**
* @Description
* @Author Z
* @Date 15:36 2024/2/1
* @Version 1.0
**/
@Configuration
public class MybatisPlusConfig {
private final StringRedisTemplate redisTemplate;
public MybatisPlusConfig(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MARIADB);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(500L);
//添加查询过滤器
interceptor.addInnerInterceptor(getQueryInterceptor());
//添加分页过滤器,分页过滤器必须添加在后面,或者使用@Order把paginationInnerInterceptor设置未后注入,否则分页统计查询语句不会正常过滤
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
@Bean
public QueryInterceptor getQueryInterceptor(){
return new QueryInterceptor(redisTemplate);
}
}
拦截器代码
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SetOperationList;
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 org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import java.sql.SQLException;
import java.util.List;
/**
* @Description
* @Author Z
* @Date 16:09 2024/2/1
* @Version 1.0
**/
@Configuration
public class QueryInterceptor extends JsqlParserSupport implements InnerInterceptor {
private final StringRedisTemplate redisTemplate;
public QueryInterceptor(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(this.parserSingle(mpBs.sql(), ms.getId()));
}
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
Object k_name = redisTemplate.opsForValue().get("k_name");
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody, (String) obj);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
}
}
/**
* 设置 where 条件
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
*/
private void setWhere(PlainSelect plainSelect, String whereSegment) {
//这里写where要接的数据查询条件
}