[SPRING] 조건 검색 필터를 구현
SPRING조건 검색 필터를 구현
나는 여러 하위 조건 검색 기능을 구현하고 싶습니다. 나는이 시도 :
@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를 사용하여 추가 하위 조건을 보낼 수있는 몇 가지 방법은 무엇입니까? 나는이 값을 보낼 수있는 가장 좋은 방법이 무엇인지 일반적으로이 문제에 대한 해결책을 찾을 수없는 이유는 무엇입니까?
해결법
-
==============================
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 등의 작업을 해결하는 가장 좋은 방법은 스프링 데이터 JPA 사양 (그리고 JPA 기준 API)를 사용하는 것입니다. 예를 들면 :
1)의 우리의 개체 모델에 대한 사양을 구현하는 필터 클래스를 만들어 보자 :
@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(); } };
이 필터 클래스를 완료하는 데 남아있다 :
@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])); } }
물론 구현의 한 예입니다. 당신은 사양 및 당신이 필요로하는 조건의 당신의 고유의 구현을 만들 수 있습니다. 여기에 주요 사항은 다음과 같습니다
from https://stackoverflow.com/questions/55919913/implement-search-filter-with-conditions by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] QueryDsl는 - 어떻게 받는다는와 Q 클래스를 만드는 방법? (0) | 2019.10.04 |
---|---|
[SPRING] REST API에 대한 JSON 응답에 필드를 제한? (0) | 2019.10.04 |
[SPRING] CrudRepository에서 사용자 지정 SQL 쿼리 (0) | 2019.10.04 |
[SPRING] 잭슨을 사용하여 자바에 POJO로 JSON 변환하는 방법 (0) | 2019.10.04 |
[SPRING] 봄 사양 및 Pageable를 (0) | 2019.10.04 |