使用条件实现搜索过滤器

我想用几个子条件实现搜索功能。我试过这个:


    @GetMapping("find")

    public Page<PaymentTransactionsDTO> getAllBySpecification(

            @And({

                    @Spec(path = "name", spec = LikeIgnoreCase.class),

                    @Spec(path = "unique_id", spec = LikeIgnoreCase.class),

                    @Spec(path = "createdAt", params = "from", spec = GreaterThanOrEqual.class),

                    @Spec(path = "createdAt", params = "to", spec = LessThanOrEqual.class)

            }) Specification<PaymentTransactions> specification,

            Pageable pageable

    ) {        

        return transactionService.getAllBySpecification(specification, pageable));       

    }

存储库:


      @Override

      public Page<PaymentTransactions> getAllBySpecification(final Specification<PaymentTransactions> specification, final Pageable pageable) {

          return dao.findAll(specification, pageable);

      }

目前此请求正在运行:


GET /api/transactions/find?unique_id=22&page=0&size=10 

但我也想实现这些额外的搜索条件,不仅发送基本搜索unique_id:


start with 

=

end with 

contains

使用https://github.com/tkaczmarzyk/specification-arg-resolver有没有办法发送额外的子条件?我一般找不到这个问题的解决方案,发送这些值的最佳做法是什么?


慕标5832272
浏览 111回答 1
1回答

森栏

如果您想创建非常特殊的过滤器,我相信您应该从发明搜索界面开始。例如像这样:GET /models?name=eq(john smith)&createdAt=between(2019-01-01,2019-01-31)GET /models?name=like(sm)&createdAt=from(2019-01-01)GET /models?name=sw(john)&createdAt=to(2019-01-31)之后,您将能够尝试实施它。IMO 解决此类任务的最佳方法是使用 Spring Data JPA Specifications(和 JPA Criteria API)。例如:1)让我们创建一个为我们的实体Filter实现的类:SpecificationModel@Valuepublic class ModelFilter implements Specification<Model> {&nbsp; &nbsp; private String name;&nbsp; &nbsp; private String createdAt;&nbsp; &nbsp; @Override&nbsp; &nbsp; public Predicate toPredicate(Root<Model> root, CriteriaQuery<?> query, CriteriaBuilder builder) {&nbsp; &nbsp; &nbsp; &nbsp; List<Predicate> predicates = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; // Prepare predicates and fill the list with them...&nbsp; &nbsp; &nbsp; &nbsp; return builder.and(predicates.toArray(new Predicate[0]));&nbsp; &nbsp; }}2)然后创建一个控制器方法:@GetMappingpublic List<Model> getAllByFilter(ModelFilter filter) {&nbsp; &nbsp; return repo.findAll(filter);&nbsp;}剩下要做的就是准备我们的谓词))为此,我们可以先创建一个方便的“谓词生成器”界面:@FunctionalInterfaceinterface PredicateBuilder<T> {&nbsp; &nbsp; Optional<Predicate> get(String fieldName, String value, Root<T> root, CriteriaBuilder builder);&nbsp; &nbsp; static Matcher getMatcher(String op, String value) {&nbsp; &nbsp; &nbsp; &nbsp; return getMatcher(op, value, "(.+)");&nbsp; &nbsp; }&nbsp; &nbsp; static Matcher getMatcher(String op, String value, String pattern) {&nbsp; &nbsp; &nbsp; &nbsp; return Pattern.compile(op + "\\(" + pattern + "\\)").matcher(value);&nbsp; &nbsp; }}然后尝试制作我们的谓词:平等的PredicateBuilder<Model> eq = (fieldName, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("eq", value);&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.equal(cb.upper(root.get(fieldName)), m.group(1).toUpperCase()));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};喜欢PredicateBuilder<Model> like = (fn, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("like", value);&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.like(cb.upper(root.get(fn)), "%" + m.group(1).toUpperCase() + "%"));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};从...开始PredicateBuilder<Model> sw = (fn, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("sw", value);&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.like(cb.upper(root.get(fn)), m.group(1).toUpperCase() + "%"));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};之间PredicateBuilder<Model> between = (fn, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("between", value, "(.+)\\s*,\\s*(.+)");&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; LocalDate from = LocalDate.parse(m.group(1));&nbsp; &nbsp; &nbsp; &nbsp; LocalDate to = LocalDate.parse(m.group(2));&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.between(root.get(fn), from, to));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};从PredicateBuilder<Model> from = (fn, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("from", value);&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; LocalDate from = LocalDate.parse(m.group(1));&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.greaterThanOrEqualTo(root.get(fn), from));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};至PredicateBuilder<Model> to = (fn, value, root, cb) -> {&nbsp; &nbsp; Matcher m = getMatcher("to", value);&nbsp; &nbsp; if (m.matches()) {&nbsp; &nbsp; &nbsp; &nbsp; LocalDate to = LocalDate.parse(m.group(1));&nbsp; &nbsp; &nbsp; &nbsp; return Optional.of(cb.lessThanOrEqualTo(root.get(fn), to));&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; return Optional.empty();&nbsp; &nbsp; }};剩下的只是完成Filter课程:@Valuepublic class ModelFilter implements Specification<Model> {&nbsp; &nbsp; private String name;&nbsp; &nbsp; private String createdAt;&nbsp; &nbsp; PredicateBuilder<Model> eq = ... ;&nbsp; &nbsp; PredicateBuilder<Model> like = ... ;&nbsp; &nbsp; PredicateBuilder<Model> sw = ... ;&nbsp; &nbsp; PredicateBuilder<Model> between = ... ;&nbsp; &nbsp; PredicateBuilder<Model> from = ... ;&nbsp; &nbsp; PredicateBuilder<Model> to = ... ;&nbsp; &nbsp; @Override&nbsp; &nbsp; public Predicate toPredicate(Root<Model> root, CriteriaQuery<?> query, CriteriaBuilder builder) {&nbsp; &nbsp; &nbsp; &nbsp; List<Predicate> predicates = new ArrayList<>();&nbsp; &nbsp; &nbsp; &nbsp; if (name != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; eq.get("name", name, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; like.get("name", name, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sw.get("name", name, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if (createdAt != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; between.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; from.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; to.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return builder.and(predicates.toArray(new Predicate[0]));&nbsp; &nbsp; }}当然,这只是实现的一个例子。您可以创建自己需要的规范和谓词的实现。这里的主要内容是:想出你的搜索界面制定您的“过滤器”规范准备好你需要的所有谓词在控制器方法中使用过滤器规范
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java