使用条件实施搜索过滤器

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

    @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是否可以发送其他子条件?总的来说,我找不到解决方案来发送这些值的最佳实践是什么?

回答:

如果您想创建非常特殊的过滤器,我相信您应该从发明搜索界面开始。例如这样的:

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

规范(和JPA Criteria API)。例如:

1)让我们创建一个为我们的实体Filter实现的类:Specification``Model

@Value

public class ModelFilter implements Specification<Model> {

private String name;

private String createdAt;

@Override

public Predicate toPredicate(Root<Model> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

List<Predicate> predicates = new ArrayList<>();

// Prepare predicates and fill the list with them...

return builder.and(predicates.toArray(new Predicate[0]));

}

}

2)然后创建一个控制器方法:

@GetMapping

public List<Model> getAllByFilter(ModelFilter filter) {

return repo.findAll(filter);

}

剩下要做的就是准备我们的谓词))

为此,我们可以先创建一个方便的“谓词生成器”界面:

@FunctionalInterface

interface PredicateBuilder<T> {

Optional<Predicate> get(String fieldName, String value, Root<T> root, CriteriaBuilder builder);

static Matcher getMatcher(String op, String value) {

return getMatcher(op, value, "(.+)");

}

static Matcher getMatcher(String op, String value, String pattern) {

return Pattern.compile(op + "\\(" + pattern + "\\)").matcher(value);

}

}

然后尝试使我们的谓词:

PredicateBuilder<Model> eq = (fieldName, value, root, cb) -> {

Matcher m = getMatcher("eq", value);

if (m.matches()) {

return Optional.of(cb.equal(cb.upper(root.get(fieldName)), m.group(1).toUpperCase()));

} else {

return Optional.empty();

}

};

PredicateBuilder<Model> like = (fn, value, root, cb) -> {

Matcher m = getMatcher("like", value);

if (m.matches()) {

return Optional.of(cb.like(cb.upper(root.get(fn)), "%" + m.group(1).toUpperCase() + "%"));

} else {

return Optional.empty();

}

};

PredicateBuilder<Model> sw = (fn, value, root, cb) -> {

Matcher m = getMatcher("sw", value);

if (m.matches()) {

return Optional.of(cb.like(cb.upper(root.get(fn)), m.group(1).toUpperCase() + "%"));

} else {

return Optional.empty();

}

};

PredicateBuilder<Model> between = (fn, value, root, cb) -> {

Matcher m = getMatcher("between", value, "(.+)\\s*,\\s*(.+)");

if (m.matches()) {

LocalDate from = LocalDate.parse(m.group(1));

LocalDate to = LocalDate.parse(m.group(2));

return Optional.of(cb.between(root.get(fn), from, to));

} else {

return Optional.empty();

}

};

PredicateBuilder<Model> from = (fn, value, root, cb) -> {

Matcher m = getMatcher("from", value);

if (m.matches()) {

LocalDate from = LocalDate.parse(m.group(1));

return Optional.of(cb.greaterThanOrEqualTo(root.get(fn), from));

} else {

return Optional.empty();

}

};

PredicateBuilder<Model> to = (fn, value, root, cb) -> {

Matcher m = getMatcher("to", value);

if (m.matches()) {

LocalDate to = LocalDate.parse(m.group(1));

return Optional.of(cb.lessThanOrEqualTo(root.get(fn), to));

} else {

return Optional.empty();

}

};

剩下的只是完成Filter课程:

@Value

public class ModelFilter implements Specification<Model> {

private String name;

private String createdAt;

PredicateBuilder<Model> eq = ... ;

PredicateBuilder<Model> like = ... ;

PredicateBuilder<Model> sw = ... ;

PredicateBuilder<Model> between = ... ;

PredicateBuilder<Model> from = ... ;

PredicateBuilder<Model> to = ... ;

@Override

public Predicate toPredicate(Root<Model> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

List<Predicate> predicates = new ArrayList<>();

if (name != null) {

eq.get("name", name, root, builder).ifPresent(predicates::add);

like.get("name", name, root, builder).ifPresent(predicates::add);

sw.get("name", name, root, builder).ifPresent(predicates::add);

}

if (createdAt != null) {

between.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);

from.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);

to.get("createdAt", createdAt, root, builder).ifPresent(predicates::add);

}

return builder.and(predicates.toArray(new Predicate[0]));

}

}

当然,这只是实现的一个例子。您可以创建自己的规范和谓词实现。这里的主要内容是:

  • 提出您的搜索界面
  • 制定您的“过滤器”规范
  • 准备您需要的所有谓词
  • 在控制器方法中使用过滤器规范

以上是 使用条件实施搜索过滤器 的全部内容, 来源链接: utcz.com/qa/403870.html

回到顶部