Mybatis Plus 与 Pagehelper 拦截器执行顺序问题

Mybatis Plus 与 Pagehelper 拦截器执行顺序问题

在使用Mybatis Plus中提供的数据权限拦截器相关处理时,使用Pagehelper进分页会出现查询count的sql中没有增加权限查询的sql拼接。
问题分析:由于mybatis plus 与 pagehelper的实现都是通过mybatis的拦截器进行处理基本就能想到在拦截器执行的时候先走的Pagehelper的分页拦截器,导致权限没有拼接上去;

解决方式一

自行配置SqlSessionFactory的创建,在代码factory.setPlugins这部分内容里面修改自己的逻辑,将拦截器顺序修改一下即可
配置代码如下,下方配置参考的是MybatisPlusAutoConfiguration中的配置

@EnableConfigurationProperties({PageHelperProperties.class, PageHelperStandardProperties.class,MybatisPlusProperties.class})
@Configuration
public class MybatisPlusConfig implements InitializingBean {

    private final PageHelperProperties standardProperties;

    private final MybatisPlusProperties properties;

    private final Interceptor[] interceptors;

    private final TypeHandler[] typeHandlers;

    private final LanguageDriver[] languageDrivers;

    private final ResourceLoader resourceLoader;

    private final DatabaseIdProvider databaseIdProvider;

    private final List<ConfigurationCustomizer> configurationCustomizers;

    private final List<SqlSessionFactoryBeanCustomizer> sqlSessionFactoryBeanCustomizers;

    private final List<MybatisPlusPropertiesCustomizer> mybatisPlusPropertiesCustomizers;

    private final ApplicationContext applicationContext;

    public MybatisPlusConfig(MybatisPlusProperties properties,
                             ObjectProvider<Interceptor[]> interceptorsProvider,
                             ObjectProvider<TypeHandler[]> typeHandlersProvider,
                             ObjectProvider<LanguageDriver[]> languageDriversProvider,
                             ResourceLoader resourceLoader,
                             ObjectProvider<DatabaseIdProvider> databaseIdProvider,
                             ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
                             ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers,
                             ObjectProvider<List<MybatisPlusPropertiesCustomizer>> mybatisPlusPropertiesCustomizerProvider,
                             ApplicationContext applicationContext,
                             PageHelperStandardProperties standardProperties) {
        this.properties = properties;
        this.interceptors = interceptorsProvider.getIfAvailable();
        this.typeHandlers = typeHandlersProvider.getIfAvailable();
        this.languageDrivers = languageDriversProvider.getIfAvailable();
        this.resourceLoader = resourceLoader;
        this.databaseIdProvider = databaseIdProvider.getIfAvailable();
        this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
        this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();
        this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
        this.applicationContext = applicationContext;
        this.standardProperties = standardProperties.getProperties();
    }

    @Override
    public void afterPropertiesSet() {
        if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) {
            mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties));
        }
        checkConfigFileExists();
    }

    private void checkConfigFileExists() {
        if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
            Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
            Assert.state(resource.exists(),
                    "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
        }
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        applyConfiguration(factory);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            PageInterceptor interceptor = new PageInterceptor();
            interceptor.setProperties(this.standardProperties);
            LinkedList<Interceptor> list = new LinkedList<>(Arrays.stream(this.interceptors).toList());
            list.addFirst(interceptor);
            factory.setPlugins(list.toArray(new Interceptor[]{}));
        }
        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }
        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }
        if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.typeHandlers)) {
            factory.setTypeHandlers(this.typeHandlers);
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
        this.getBeanThen(TransactionFactory.class, factory::setTransactionFactory);

        Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
        if (!ObjectUtils.isEmpty(this.languageDrivers)) {
            factory.setScriptingLanguageDrivers(this.languageDrivers);
        }
        Optional.ofNullable(defaultLanguageDriver).ifPresent(factory::setDefaultScriptingLanguageDriver);

        applySqlSessionFactoryBeanCustomizers(factory);

        GlobalConfig globalConfig = this.properties.getGlobalConfig();
        this.getBeanThen(MetaObjectHandler.class, globalConfig::setMetaObjectHandler);
        this.getBeanThen(AnnotationHandler.class, globalConfig::setAnnotationHandler);
        this.getBeanThen(PostInitTableInfoHandler.class, globalConfig::setPostInitTableInfoHandler);
        this.getBeansThen(IKeyGenerator.class, i -> globalConfig.getDbConfig().setKeyGenerators(i));
        this.getBeanThen(ISqlInjector.class, globalConfig::setSqlInjector);
        this.getBeanThen(IdentifierGenerator.class, globalConfig::setIdentifierGenerator);
        factory.setGlobalConfig(globalConfig);
        return factory.getObject();
    }

    /**
     * 检查spring容器里是否有对应的bean,有则进行消费
     *
     * @param clazz    class
     * @param consumer 消费
     * @param <T>      泛型
     */
    private <T> void getBeanThen(Class<T> clazz, Consumer<T> consumer) {
        if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
            consumer.accept(this.applicationContext.getBean(clazz));
        }
    }

    /**
     * 检查spring容器里是否有对应的bean,有则进行消费
     *
     * @param clazz    class
     * @param consumer 消费
     * @param <T>      泛型
     */
    private <T> void getBeansThen(Class<T> clazz, Consumer<List<T>> consumer) {
        if (this.applicationContext.getBeanNamesForType(clazz, false, false).length > 0) {
            final Map<String, T> beansOfType = this.applicationContext.getBeansOfType(clazz);
            List<T> clazzList = new ArrayList<>();
            beansOfType.forEach((k, v) -> clazzList.add(v));
            consumer.accept(clazzList);
        }
    }

    private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {
        MybatisPlusProperties.CoreConfiguration coreConfiguration = this.properties.getConfiguration();
        MybatisConfiguration configuration = null;
        if (coreConfiguration != null || !StringUtils.hasText(this.properties.getConfigLocation())) {
            configuration = new MybatisConfiguration();
        }
        if (configuration != null && coreConfiguration != null) {
            coreConfiguration.applyTo(configuration);
        }
        if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
            for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
                customizer.customize(configuration);
            }
        }
        factory.setConfiguration(configuration);
    }

    private void applySqlSessionFactoryBeanCustomizers(MybatisSqlSessionFactoryBean factory) {
        if (!CollectionUtils.isEmpty(this.sqlSessionFactoryBeanCustomizers)) {
            for (SqlSessionFactoryBeanCustomizer customizer : this.sqlSessionFactoryBeanCustomizers) {
                customizer.customize(factory);
            }
        }
    }
}

解决方式二

通过反射机制对SqlSessionFactory中的拦截器进行排序
配置代码如下:

@Configuration
public class MybatisInterceptorConfig implements ApplicationListener<ContextRefreshedEvent> {

    private final List<SqlSessionFactory> sqlSessionFactoryList;
    // 这里设置拦截器顺序,要把PageInterceptor拦截器放在MybatisPlusInterceptor之前
    // mybatis拦截器执行链路是通过(Plugin.wrap)动态代理方式创建的执行链路
    // 靠前创建的代理对象执行时会越靠后,看懂Plugin.wrap中的代码就能理解
    private final Map<Class<?>,Integer> sortNum = new HashMap<>(){
        put(PageInterceptor.class,1);
        put(MybatisPlusInterceptor.class,2);
    }};


    public MybatisInterceptorConfig(List<SqlSessionFactory> sqlSessionFactoryList) {
        this.sqlSessionFactoryList = sqlSessionFactoryList;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (sqlSessionFactoryList != null && !sqlSessionFactoryList.isEmpty()) {
            for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
                org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
                InterceptorChain interceptorChain = (InterceptorChain) geFieldValue(configuration, "interceptorChain");
                List<Interceptor> interceptors = (List<Interceptor>) geFieldValue(interceptorChain, "interceptors");
                interceptors.sort((o1, o2) -> {
                    Integer num1 = sortNum.get(o1.getClass());
                    Integer num2 = sortNum.get(o2.getClass());
                    if(num1 != null && num2 != null){
                        return num1.compareTo(num2);
                    }
                    return 0;
                });
            }
        }
    }

    private Object geFieldValue(Object obj, String fieldName) {
        Field field = ReflectionUtils.findField(obj.getClass(), fieldName);
        field.setAccessible(true);
        return ReflectionUtils.getField(field, obj);
    }

}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值