使用Sort和querydsl Predicate创建一个集合资源,但没有Pageable

时间:2016-09-28 08:26:18

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

我正在使用Spring数据Rest并寻找一种方法来创建具有Sort和Predicate(使用querydsl)功能的Collection(或搜索)资源,但没有没有运气的Pager。

到目前为止,我只需要禁用寻呼机但具有排序功能。使用以下内容并调用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);

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

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)   〜[!弹簧数据公地1.12.3.RELEASE.jar /:NA]           在org.springframework.data.repository.support.ReflectionRepositoryInvoker.invokeQueryMethod(ReflectionRepositoryInvoker.java:206)   〜[!弹簧数据公地1.12.3.RELEASE.jar /:NA]

更奇怪的是,我尝试将QueryDSL与CrudRepository一起使用,而CrudRepository没有寻呼机功能。如果我使用QueryDslPredicateExecutor<UserAccount>扩展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
  }
}

2 个答案:

答案 0 :(得分:0)

如何扩展JpaSpecificationExecutor以便您使用Specification

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

希望有帮助...

答案 1 :(得分:0)

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

1:创建自定义QuerydslRepositoryInvokerAdapter并将invokeFindAll(Pageable pageable)方法发送到findAll(Sort sort)的{​​{1}}:

executor

2:创建自定义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()); } }

RootResourceInformationHandlerMethodArgumentResolver

3:覆盖RootResourceInformationHandlerMethodArgumentResolver Bean定义:

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;
    }


}

4:创建自定义@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()); } }

QueryDslPredicateExecutor

5:然后将其应用于存储库

public interface CustomQueryDslPredicateExecutor<T> extends QueryDslPredicateExecutor<T> {

    Iterable<T> findAll(Predicate predicate, Sort sort);

}

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