다음은 내가 Spring에서 지원하는 Pageable 인터페이스를 활용할 때, 여러 케이스를 시도하면서 얻었던 결론을 정리한 것이다.
⚽ Pageable 정렬 동작 방식
CASE 1) 조회하고자 하는 쿼리에 OrderBy (정적 정렬 조건)명시되어있을 때
- Querydsl을 사용한 메소드의 경우에는 클라이언트에서 sort에 파라미터 값 보내도 무시됨(Querydsl에서는 따로 정렬 쿼리 메소드를 구현해서 작업을 해주지 않는 이상 Pageable sort가 동작하지 않음)
- JPA에서 반환 타입이 Page이고, @Query 어노테이션으로 JPQL에 정적 정렬 조건을 넣는 경우 클라이언트에서 전달받은 sort 파라미터 추가돼서 정렬 조건으로 들어감 (JPQL 정적 정렬 + 클라이언트로부터 받은 sort 정렬 조건)
- 파라미터 값 보내지 않으면, 서버 디폴트(@PageDefault) 정렬 조건(어노테이션)이 있는 경우에는 정적 정렬 조건에 더해서 디폴트 정렬조건도 같이 적용(중복 주의), 디폴트 정렬 조건이 없으면 정적 정렬 조건만 적용
CASE 2) 조회하고자 하는 쿼리에 OrderBy(정적 정렬 조건) 명시되어있지 않을 때
- 클라이언트에서 sort에 파라미터 값 보내지 않으면
- 서버에 Default 정렬 조건 명시되어있으면 해당 정렬 조건으로 정렬
- 명시하지 않았으면 정렬 조건 들어가지 않음
- 클라이언트에서 sort 파라미터 값 요청 보내면 repository 인터페이스에서 반환 타입으로 Page를 쓰면 해당 클라이언트 요청 sort 파라미터 값으로 정렬
CASE 3) 동적 정렬 조건
- Querydsl에서만 동적 정렬 조건 적용, 파라미터 값으로 pageble 객체와 Q클래스 엔티티를 전달하면 사용 가능
- 예제 코드
public class QueryDslUtils {
public static List<OrderSpecifier> getOrderSpecifiers(List<? extends SortCode> sortCodes, Pageable pageable, Path<?> qEntity) {
List<OrderSpecifier> orders = new ArrayList<>();
PathBuilder pathBuilder = new PathBuilder<>(qEntity.getType(), qEntity.getMetadata());
for (SortCode sortCode : sortCodes) {
orders.add(new OrderSpecifier<>(sortCode.getOrder(), pathBuilder.get(sortCode.getField())));
}
// pageable의 sort 파라미터에 해당하는 부분
// for (Sort.Order order : pageable.getSort()) {
// Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;
// orders.add(new OrderSpecifier<>(direction, pathBuilder.get(order.getProperty())));
// }
// return orders;
return orders;
}
}
여기서 주석 처리된 부분을 사용하지 않았던 이유로는, 프로젝트를 진행하면서 웹에서는 페이징 sort를 위한 파라미터로 sort=column1,desc&sort=column2,asc 이런 형식으로 쿼리 파라미터를 받을 수 있었는데, 같이 프로젝트를 진행한 iOS 클라이언트 개발자분께서 sort=column1&sort=desc&sort=column2&sort=asc 이런 형식으로 쿼리 파라미터를 넘겨줄 수 있다고 하여 다음과 같이 sortCode라는 인터페이스를 따로 정의해놓고 그것을 상속 받는 여러 도메인에 대한 정렬 enum 들을 정의해서 파라미터를 받을 수 있도록 구현하였다.
public interface SortCode {
String getField();
Order getOrder();
}
@Getter
public enum CommentSortCode implements SortCode {
MOST_LIKED("likeCount", Order.DESC), // 좋아요 많은 순
NEWEST("createDateTime", Order.DESC); // 최근 작성 순
private final String field;
private final Order order;
CommentSortCode(String field, Order order) {
this.field = field;
this.order = order;
}
}
'개발기록(feat.삽질)' 카테고리의 다른 글
| log4jdbc로 JPA 쿼리 로그 Formatter 적용하기 (0) | 2025.06.26 |
|---|---|
| 내부 트랜잭션이 @Transactional(propagation = Propagation.REQUIRES_NEW)일 때, 외부 트랜잭션에 대해서는 커밋이 되어야하는데 되지 않는 문제 (0) | 2025.03.05 |
| JPA Bulk Insert (1) | 2024.12.13 |
| [Querydsl] java.time.LocalDateTime is not compatible with java.lang.String 에러 (0) | 2024.10.23 |
| Jackson사용 시 primitive boolean주의점 (0) | 2024.08.19 |