您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

使用条件实施搜索过滤器

使用条件实施搜索过滤器

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

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

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

其他 2022/1/1 18:14:37 有544人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶