[Querydsl] Querydsl 동적으로 정렬하는 방법
2023. 3. 6. 21:04
게시글 조회 화면에서 검색타입, 정렬 방법에 따라 다른 결과를 반환해야 하는 기능을 구현하고 있었다.
단순한 검색 기능이면 스프링 데이터 JPA로 JPQL을 사용했겠지만, 이번 기능은 고려해야 할 부분이 많았기 때문에 Querydsl을 사용해서 구현해 보기로 했다.
where문 작성의 경우 BooleanExpression과 BooleanBuilder를 사용해서 간단하게 작성할 수 있었는데, 정렬 조건에 따른 작성을 어떻게 해야 하는지가 문제였다.
처음엔 service단에서 sort값에 따라 처리하도록 아래와 같이 작성했었다.
//PostService
public Page<Post> findPosts(int page, int size, PostSearchDto postSearchDto, String sort) {
PageRequest pageRequest = PageRequest.of(page, size);
if (sort != null && sort.equals("Likes")) {
return postRepository.getPostsSortByLikes(postSearchDto, pageRequest);
} else {
return postRepository.getPostsSortByNewest(postSearchDto, pageRequest);
}
}
//PostRepositoryImpl
//최신순
@Override
public Page<Post> getPostsSortByNewest(PostSearchDto postSearchDto, Pageable pageable) {
List<Post> results = queryFactory
.select(post)
.from(post)
.leftJoin(post.pet, pet)
.where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
//...
}
//좋아요 순
@Override
public Page<Post> getPostsSortByLikes(PostSearchDto postSearchDto, Pageable pageable) {
List<Post> results = queryFactory
.select(post)
.from(post)
.leftJoin(post.pet, pet)
.where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
.orderBy(post.likesCnt.desc())
.orderBy(post.id.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
//...
}
댓글 순까지 작성하면 orderBy를 제외한 다른 절들은 똑같은데 orderBy 때문에 3개의 메서드가 작성되는 게 별로였고 추후에 조건이 추가된다면 또 메서드를 만들어야 한다.
OrderSpecifier
Querydsl은 동적으로 정렬조건을 적용할 수 있게 OrderSpecifier를 제공한다.
@Override
public Page<Post> getPosts(PostSearchDto postSearchDto, Pageable pageable, String sort) {
List<Post> results = queryFactory
.select(post)
.from(post)
.leftJoin(post.pet, pet).fetchJoin()
.leftJoin(post.postComments, postComment)
.where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
.orderBy(getOrderSpecifier(sort).stream().toArray(OrderSpecifier[]::new))
.groupBy(post.id)
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
//...
}
private List<OrderSpecifier> getOrderSpecifier(String sort) {
List<OrderSpecifier> orders = new ArrayList<>();
if (StringUtils.hasText(sort)) {
Order direction = Order.DESC;
switch (sort) {
case "likes":
orders.add(new OrderSpecifier(direction, post.likesCnt));
orders.add(new OrderSpecifier(direction, post.id));
break;
case "comments":
orders.add(new OrderSpecifier(direction, postComment.id.count()));
orders.add(new OrderSpecifier(direction, post.id));
break;
case "newest":
orders.add(new OrderSpecifier(direction, post.id));
break;
default:
throw new BusinessLogicException(ExceptionCode.INVALID_SORT_TYPE);
}
}
return orders;
}
위와 같이 List에 정렬 조건별로 OrderSpecifier를 추가해서 반환하는 메서드를 만들어 사용하면 정렬 조건이 추후에 조건이 바뀌거나 추가되어도 쉽게 적용이 가능하다.
참고 블로그
'Programming > Spring' 카테고리의 다른 글
[Spring] HttpServletRequest 요청마다 같은 주소값을 반환하는 이유 (0) | 2023.02.25 |
---|---|
[Spring] RequestContextHolder를 통해 HttpServletRequest, Response 가져오기 (0) | 2023.02.17 |
[Spring] 같은 타입의 빈 문제 해결 방법(@Primary, @Qualifier) (0) | 2023.02.15 |
[Spring] 스프링 컨테이너와 빈 (0) | 2023.02.13 |
[Spring] 예외처리 - ExceptionHandler, ControllerAdvice (0) | 2022.10.30 |