리뷰 리스트를 조회하는 API 내에서,
- 최근 등록 순
- 별점 높은 순
- 별점 낮은 순
으로 데이터를 정렬했어야 했다.
정적으로 고정된 정렬이 아닌, 파라미터 값에 따라 동적으로 정렬이 되어야 했다.
queryDsl 에서 동적 정렬을 위한 OrderSpecifier 클래스를 사용해보려고 한다!
일단 해당 클래스의 필드들을 살펴보면 아래와 같다.
클래스의 멤버들을 살펴 보면 해당 클래스의 생성자를 사용하여 생성할 수 있는데,
파라미터 변수들로는 Order enum, target 객체, NullHandling enum이 존재한다.
- order Enum은 아래와 같이 구성되며, 상황에 맞게 내림차순, 오름차순을 적용해주면 될 것 같다.
public enum Order {
/**
* Ascending order
*/
ASC,
/**
* Descending order
*/
DESC;
}
- NullHandling Enum은 null인 컬럼에 대해 정렬을 어떻게 처리해 줄 것인지에 대한 옵션이다.
정의되어 있는 Enum 값을 보게 되면 아래와 같다.
public enum NullHandling { Default, NullsFirst, NullsLast }
NullsFirst
- null에 대한 값들을 앞쪽으로 정렬할 것인지
NullsLast
- null에 대한 값들을 뒤쪽으로 정렬할 것인지
OrderSpecifier 클래스를 사용하여 paramter에 따른 정렬을 동적으로 만들어보았다.
@Override
public Page<Review> findAllReviewByRoomList(List<Long> roomseqList, Pageable pageable, ReviewDto.ReqRes req) {
List<Review> fetch = jpaQueryFactory.selectFrom(QReview.review)
.join(QReview.review.room, QRoom.room).fetchJoin()
.where(QReview.review.room.roomSeq.in(roomseqList))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(reviewSort(req))
.fetch();
JPAQuery<Long> countQuery = jpaQueryFactory.select(QReview.review.count())
.from(QReview.review)
.where(QReview.review.room.roomSeq.in(roomseqList));
return PageableExecutionUtils.getPage(fetch, pageable, countQuery::fetchOne);
}
// reviewSort() 메서드
private OrderSpecifier<?> reviewSort(ReviewDto.ReqRes req) {
if (!ObjectUtils.isEmpty(req) && !ObjectUtils.isEmpty(req.getFilterType())) {
switch (req.getFilterType()) {
case "recentDate":
return new OrderSpecifier(Order.DESC, QReview.review.createdAt);
case "highScore":
return new OrderSpecifier(Order.DESC, QReview.review.avgStartScore);
case "lowScore":
return new OrderSpecifier(Order.ASC, QReview.review.avgStartScore);
}
}
return new OrderSpecifier(Order.DESC, QReview.review.createdAt);
}
기본 정렬은 리뷰 등록일자가 최신순으로 되어 있으므로, default 값으로 설정해 준다.
-------------------- 추가된 내용 --------------------
order by에 대해서 다중으로 적용해야 하는 로직이 추가되어야 했다.
예를 들어 위의 로직은 order by created_at desc 하나의 조건이였다면,
추가되는 로직에서는 order by best_yn desc, created_at desc 와 같이 정렬조건이 다중으로 적용되어야 했다.
이를 OrderSpecifier에서 적용을 하기 위해서
OrderSpecifier[]
배열을 사용하여 정렬 조건들을 넣어주면 되었다.
private List<OrderSpecifier<?>> reviewSort(ReviewDto.ReqRes req) {
List<OrderSpecifier<?>> orderSpecifierList = new ArrayList<>();
if (ReviewDto.FilterType.LOWSCORE.getName().equals(req.getFilterType())) {
orderSpecifierList.add(new OrderSpecifier<>(Order.ASC, QReview.review.avgStartScore));
} else if (ReviewDto.FilterType.HIGHSCORE.getName().equals(req.getFilterType())) {
orderSpecifierList.add(new OrderSpecifier<>(Order.DESC, QReview.review.avgStartScore));
} else {
orderSpecifierList.add(new OrderSpecifier<>(Order.DESC, QReview.review.bestYn));
orderSpecifierList.add(new OrderSpecifier<>(Order.DESC, QReview.review.createdAt));
}
return orderSpecifierList;
}
// 적용 쿼리
List<Review> fetch = jpaQueryFactory.selectFrom(QReview.review)
.join(QReview.review.room, QRoom.room).fetchJoin()
.where(QReview.review.room.roomSeq.in(roomseqList))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(reviewSort(req).toArray(OrderSpecifier[]::new))
.fetch();
몇개의 정렬조건이 들어갈지 모르니 위와 같이 ArrayList를 통해서 각 case마다 정렬조건을 넣어주고,
query문 내에 해당 메소드를 불러올 때, ArrayList > Array 로 변경을 해주면
OrderSpecifier을 사용하여 다중 정렬 조건을 적용할 수 있다.
'토이 프로젝트 배우게 된 것들 & 오류 해결🐰' 카테고리의 다른 글
JPA | @Transactional 과 변경감지 (0) | 2023.01.30 |
---|---|
JPA | 일대일 양방향 관계에서 CasCade 옵션 적용 일화 ..?🤔 (0) | 2023.01.25 |
Querydsl | Pageable과 page를 사용하는 방법 (2) | 2023.01.11 |
JPA | QueryDsl 집계함수[SUM, COUNT ..] 사용 시, Dto로 반환 (0) | 2023.01.04 |
feign client ErrorDecoder 인터페이스 사용시 마주한 문제 해결기 🙂 (0) | 2023.01.02 |