Programming/JPA & Spring Data JPA 기초
24. Specification을 이용한 검색 조건 지정
JKROH
2023. 4. 18. 15:19
반응형
해당 강의는 코드 위주로 진행됩니다. 실질적인 객체 처리를 담당하는 코드는 링크에서 확인하시길 바랍니다.
* Specification
- 검색 조건을 생성하는 인터페이스다.
- Criteria를 이용해서 검색 조건을 생성한다.
public interface Specification<T> extends Serializable {
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder);
}
- 리포지토리 Specificatoin을 이용해서 검색 조건을 지정한다.
- List<T> findAll(Specification<T> spec)
public interface UserRepository extends Repository<User, String> {
List<User> findAll(Specification<User> spec);
}
- findAll은 spec을 이용해서 검색 조건을 생성하고 해당 검색 조건에 해당하는 엔티티를 찾아서 List로 반환한다.
* Specfication 구현 / 사용
- UserNameSpecification 클래스에서 확인할 수 있다.
- toPredicate을 오버라이딩한다.
- UserNameSpecification 객체를 만들고 이를 findAll 에 인자로 넘겨준다.
UserNameSpecification spec = new UserNameSpecification("이름");
List<User> users = userRepoistory.findAll(spec);
* 람다로 간결하게 구현
- Specification을 구현한 클래스를 매번 만들면 귀찮으니 람다식을 이용해서 스펙 객체를 생성하도록 구현해보자.
- Spec을 생성하는 클래스를 만들고 메서드 안에 람다식을 통해 Spec객체를 구현하도록 한다.
public class UserSpecs {
public static Specification<User> nameLie(String value {
return (root, query, cb) -> cb.like(root.get("name"), "%" + value + "%");
}
=================
UserNameSpecification spec = UserSpecs.nameLike("이름");
List<User> users = userRepository.findAll(spec);
* 검색 조건 조합
- Specification의 or / and 메서드로 이용해서 조건을 조합해서 사용할 수 있다.
- or / and는 default 구현 되어있다.
Specification<User> nameSpec = UserSpecs.nameLike("이름1");
Specification<User> afterSpec = UserSpecs.createdAfter(LocalDateTime.now().minusHours(1));
Specification<User> compositespec = nameSpec.and(afterSpec);
List<User> users2 = userRepository.findAll(compositespec);
==================
Specification<User> spec3 = UserSpecs.nameLike("이름2")
.and(UserSpecs.createdAfter(LocalDateTime.now().minusHours(1)));
List<User> users3 = userRepository.findAll(spec3);
- 선택적으로 조합하는 경우
Specification<User> spec = Specification.where(null);
if (keyword != null && !keyword.trim().isEmpty())) { // keyword가 null이 아니고 빈 문자열이 아니면
spec = spec.and(UserSpecs.nameLike(keyword)); // spec을 조합
}
if (dateTime != null) { // dateTime이 null이 아니면
spec = spec.and(UserSpecs.createdAfter(dateTime)); // spec을 조합
}
List<User users = userRepository.findAll(spec);
* Specification + 페이징, 정렬
- List<User>findAll(Specification<T> spec, Sort s)
- Page<User>findAll(Specification<T> spec, Pageable p)
- List<User>findAll(Specification<T> spec, Pageable p)
* SpecBuilder
- 위의 검색 조건 조합에서 if 절을 덜 쓰기 위해서 SpecBuilder를 구현하면 코드를 좀 더 깔끔하게 만들 수 있다.
- 자세한 설명은 링크에서 확인할 수 있다.
* 정리
- Specification 인터페이스를 이용해서 검색 조건을 생성할 수 있다.
- 조건의 조합도 가능하다.
- and / or
반응형