我正在 Spring Data Rest 之上构建 REST API。最初扩展 JpaRepository 的所有存储库。最近决定采取更灵活的方法并使用 QueryDslPredicateExecutor<T>连同 QuerydslBinderCustomizer<Q>.

几乎所有findAll存储库中公开的方法应解决两种情况

  • 校长有一个角色 ROLE_ADMIN那么不应对来自 Pageable 的部分应用过滤, Sort

  • 校长没有角色 ROLE_ADMIN我只会返回那些属于当前用户的实体

完成这项工作就像注释 findAll 一样简单方法如下。

@Query("select e from Entity e where e.field = ?#{principal} or 1=?#{hasRole('ROLE_ADMIN') ? 1 : 0}") 
Page<Entity> findAll(Pageable pageable); 

现在我想要我们的 findAll类似于下面的内容

Page<Entity> findAll(Predicate predicate, Pageable pageable) 

Predicate正在根据请求参数构建(由 @QuerydslPredicate 提供)并传递给 RepositoryEntityController这一切都由 spring-data-rest 管理,这很棒。

@ResponseBody 
    @RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET) 
    public Resources<?> getCollectionResource(@QuerydslPredicate RootResourceInformation resourceInformation, 
            DefaultedPageable pageable, Sort sort, PersistentEntityResourceAssembler assembler) 
                    throws ResourceNotFoundException, HttpRequestMethodNotSupportedException {     

我想调整那个谓词(上面我想解决的 2 个场景)。 这将类似于下面的内容。

BooleanBuilder builder = new BooleanBuilder(predicateBuildFromHttpRequest); 
        builder.and(predicateAddressingOurRequirements); 
        builder.getValue(); 

@PostFilter不会是一个选项,因为所有 repo 协议(protocol)的返回类型都是 Page<Entity> .

我想解决的用例对我来说似乎很常见。话虽如此,我查看了 spring-data 和 spring-data-rest 文档,但找不到与我的问题相关的任何内容。

问题是:我是否在这里遗漏了一些明显的东西并且可以快速取胜?或者我需要自己实现定制解决方案?非常感谢任何意见!

请您参考如下方法:

Querydsl 谓词由 QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver 构造,遗憾的是它是私有(private)包,不能直接扩展。

但是,您可以复制它,添加您的安全谓词逻辑,然后放入您的实现而不是以前的解析器。

public class MyQueryDslRootResourceArgumentResolver extends RootResourceInformationHandlerMethodArgumentResolver { 
 
    // the most of the code is ommitted, the content is identical with  
    // QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver,  
    // the important part is postProcessMethod where you can modify the predicate 
 
 
    @Override 
    @SuppressWarnings({"unchecked"}) 
    protected RepositoryInvoker postProcess(MethodParameter parameter, RepositoryInvoker invoker, 
                                            Class<?> domainType, Map<String, String[]> parameters) { 
 
        Object repository = repositories.getRepositoryFor(domainType); 
 
        if (!QueryDslPredicateExecutor.class.isInstance(repository) 
                || !parameter.hasParameterAnnotation(QuerydslPredicate.class)) { 
            return invoker; 
        } 
 
        ClassTypeInformation<?> type = ClassTypeInformation.from(domainType); 
 
        QuerydslBindings bindings = factory.createBindingsFor(null, type); 
 
        // modify your predicate here 
        Predicate predicate = predicateBuilder.getPredicate(type, toMultiValueMap(parameters), bindings); 
 
        return new QuerydslRepositoryInvokerAdapter(invoker, (QueryDslPredicateExecutor<Object>) repository, predicate); 
    } 
 
 
} 

然后使用自定义解析器实现添加您自己的配置类。

public class CustomRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration { 
 
    @Autowired 
    ApplicationContext applicationContext; 
 
    @Override 
    public RootResourceInformationHandlerMethodArgumentResolver repoRequestArgumentResolver() { 
        QuerydslBindingsFactory factory = applicationContext.getBean(QuerydslBindingsFactory.class); 
        QuerydslPredicateBuilder predicateBuilder = new QuerydslPredicateBuilder(defaultConversionService(), 
                factory.getEntityPathResolver()); 
 
        return new MyQueryDslRootResourceArgumentResolver(repositories(), 
                repositoryInvokerFactory(defaultConversionService()), resourceMetadataHandlerMethodArgumentResolver(), 
                predicateBuilder, factory); 
    } 
} 


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!