如果您想创建非常特殊的过滤器,我相信您应该从发明搜索界面开始。例如这样的:
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
@Valuepublic 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)然后创建一个控制器方法:
@GetMappingpublic List<Model> getAllByFilter(ModelFilter filter) { return repo.findAll(filter); }剩下要做的就是准备我们的谓词))
为此,我们可以先创建一个方便的“谓词生成器”界面:
@FunctionalInterfaceinterface 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课程:
@Valuepublic 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])); }}当然,这只是实现的一个例子。您可以创建自己的规范和谓词实现。这里的主要内容是:
- 提出您的搜索界面
- 制定您的“过滤器”规范
- 准备您需要的所有谓词
- 在控制器方法中使用过滤器规范



