【问题标题】:Create a collection resource with Sort and querydsl Predicate but no Pageable使用 Sort 和 querydsl Predicate 创建集合资源,但没有 Pageable
【发布时间】:2016-09-28 08:26:17
【问题描述】:

我正在使用 Spring data Rest 并寻找一种方法来创建具有排序和谓词(使用 querydsl)功能但没有分页器的集合(或搜索)资源。

到目前为止,我只需要禁用寻呼机,但具有排序功能。使用以下方法并调用GET /userAccounts/search/noPager 效果很好:

public interface ReportRepository 
    extends JpaRepository<Report, Integer>{

    /**
     * Non paged data with Sort capabilities
     */
    @RestResource(path="noPager")
    List<Report> findAllBy(Sort sort);

现在我需要添加谓词功能。如果我执行以下操作:

public interface UserAccountRepository 
    extends JpaRepository<UserAccount, Integer>,
            QueryDslPredicateExecutor<UserAccount> {

    /**
     * Non paged data with Sort capabilities
     */
    @RestResource(path="noPager")
    List<UserAccount> findAllBy(Predicate predicate, Sort sort);

调用GET /userAccounts/search/noPager时出现以下错误:

java.lang.IllegalArgumentException:无法检测参数名称 查询方法 fr.texsys.datemplus.dm.domain.data.UserAccountRepository.findAllBy! 在 JDK 8 上使用 @Param 或使用 -parameters 编译。 在 org.springframework.data.repository.support.ReflectionRepositoryInvoker.prepareParameters(ReflectionRepositoryInvoker.java:235) ~[spring-data-commons-1.12.3.RELEASE.jar!/:na] 在 org.springframework.data.repository.support.ReflectionRepositoryInvoker.invokeQueryMethod(ReflectionRepositoryInvoker.java:206) ~[spring-data-commons-1.12.3.RELEASE.jar!/:na]

更奇怪的是,我尝试将 QueryDSL 与 CrudRepository 一起使用,它没有寻呼机功能。如果我使用QueryDslPredicateExecutor&lt;UserAccount&gt; 扩展 CrudRepository,并调用集合资源GET /userAccounts,则激活寻呼机。

没有QueryDslPredicateExecutor:

public interface UserAccountRepository 
    extends CrudRepository<UserAccount, Integer> {

没有寻呼机:

{
  "_embedded" : {
    "userAccounts" : [...]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:15571/userAccounts"
    },
    "profile" : {
      "href" : "http://localhost:15571/profile/userAccounts"
    }
  }
}

但是QueryDslPredicateExecutor:

public interface UserAccountRepository 
    extends CrudRepository<UserAccount, Integer>,
            QueryDslPredicateExecutor<UserAccount> {

寻呼机被激活

{
  "_embedded" : {
    "userAccounts" : [ ... ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:15571/userAccounts"
    },
    "profile" : {
      "href" : "http://localhost:15571/profile/userAccounts"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 3,
    "totalPages" : 1,
    "number" : 0
  }
}

【问题讨论】:

    标签: spring spring-data spring-data-rest querydsl


    【解决方案1】:

    如何扩展JpaSpecificationExecutor 以便您可以使用Specification?

    创建您自己的规范实现将允许您创建您的搜索过滤器并根据需要对其进行排序(通过访问 CriteriaQuery)。

    希望对你有帮助...

    【讨论】:

    • 我查看了规范 API。一开始看起来很有希望,但这不是我所需要的,因为使用 spring data rest 我无法控制将调用哪个“listAll”方法(当 HTTP 请求以表单/ api/{存储库})。也许我需要的是创建自己的 Executor 但我不知道该怎么做!
    【解决方案2】:

    所以我设法做到了我想要的,但这真的很麻烦,希望有一种我没有发现的更轻更方便的方法:

    1:创建自定义QuerydslRepositoryInvokerAdapter并将invokeFindAll(Pageable pageable)方法路由到executor的findAll(Sort sort):

    public class CustomQuerydslRepositoryInvokerAdapter 
            extends QuerydslRepositoryInvokerAdapter {
    
        private final QueryDslPredicateExecutor<Object> executor;
        private final Predicate predicate;
    
        public CustomQuerydslRepositoryInvokerAdapter(
                RepositoryInvoker delegate, 
                QueryDslPredicateExecutor<Object> executor,
                Predicate predicate) {
            super(delegate, executor, predicate);
    
            Assert.notNull(delegate, "Delegate RepositoryInvoker must not be null!");
            Assert.notNull(executor, "QuerydslPredicateExecutor must not be null!");
    
            this.executor = executor;
            this.predicate = predicate;
        }
    
        @Override
        public Iterable<Object> invokeFindAll(Pageable pageable) {
            return executor.findAll(predicate, pageable.getSort());
        }
    
    }
    

    2:创建自定义RootResourceInformationHandlerMethodArgumentResolver:

    public class CustomQuerydslAwareRootResourceInformationHandlerMethodArgumentResolver 
        extends RootResourceInformationHandlerMethodArgumentResolver {
    
        private final Repositories repositories;
        private final QuerydslPredicateBuilder predicateBuilder;
        private final QuerydslBindingsFactory factory;
    
        public CustomQuerydslAwareRootResourceInformationHandlerMethodArgumentResolver(Repositories repositories,
                RepositoryInvokerFactory invokerFactory, ResourceMetadataHandlerMethodArgumentResolver resourceMetadataResolver,
                QuerydslPredicateBuilder predicateBuilder, QuerydslBindingsFactory factory) {
    
            super(repositories, invokerFactory, resourceMetadataResolver);
    
            this.repositories = repositories;
            this.predicateBuilder = predicateBuilder;
            this.factory = factory;
        }
    
        /* 
         * (non-Javadoc)
         * @see org.springframework.data.rest.webmvc.config.RootResourceInformationHandlerMethodArgumentResolver#postProcess(org.springframework.data.repository.support.RepositoryInvoker, java.lang.Class, java.util.Map)
         */
        @Override
        @SuppressWarnings({ "unchecked" })
        protected RepositoryInvoker postProcess(MethodParameter parameter, RepositoryInvoker invoker,
                Class<?> domainType, Map<String, String[]> parameters) {
    
            Object repository = repositories.getRepositoryFor(domainType);
    
            if (!CustomQueryDslPredicateExecutor.class.isInstance(repository)
                    || !parameter.hasParameterAnnotation(QuerydslPredicate.class)) {
                return invoker;
            }
    
            ClassTypeInformation<?> type = ClassTypeInformation.from(domainType);
    
            QuerydslBindings bindings = factory.createBindingsFor(null, type);
            Predicate predicate = predicateBuilder.getPredicate(type, toMultiValueMap(parameters), bindings);
    
            return new CustomQuerydslRepositoryInvokerAdapter(invoker, (QueryDslPredicateExecutor<Object>) repository, predicate);
        }
    
        private static MultiValueMap<String, String> toMultiValueMap(Map<String, String[]> source) {
    
            MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>();
    
            for (String key : source.keySet()) {
                result.put(key, Arrays.asList(source.get(key)));
            }
    
            return result;
        }
    
    
    }
    

    3:覆盖RootResourceInformationHandlerMethodArgumentResolver Bean定义:

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

    4:创建自定义QueryDslPredicateExecutor:

    public interface CustomQueryDslPredicateExecutor<T> extends QueryDslPredicateExecutor<T> {
    
        Iterable<T> findAll(Predicate predicate, Sort sort);
    
    }
    

    5:然后应用到Repository

    public interface UserAccountRepository 
        extends CrudRepository<UserAccount, Integer>,
                CustomQueryDslPredicateExecutor<UserAccount> {
        [...] 
    }
    

    哎哟!但它有效......

    【讨论】:

      猜你喜欢
      • 2021-11-30
      • 1970-01-01
      • 2013-05-11
      • 2020-12-15
      • 2016-11-27
      • 2017-12-03
      • 2022-07-24
      • 2021-05-29
      • 2020-11-09
      相关资源
      最近更新 更多