Querydsl 동적 정렬

qufdl·2023년 6월 15일
0

Spring Boot

목록 보기
2/5
post-thumbnail

Querydsl 동적 정렬

게시판을 추천순, 날짜순 등으로 정렬을 하고자 했습니다. 처음에는 repository에 정렬 조건을 보내 orderBy에 넣는 방식으로 구현하려고 했으나, 조건이 늘어날 경우 분기문이 너무 많아질것 같았습니다. 그래서 방법을 찾던 와중, OrderSpecifier라는 클래스를 이용한 동적 정렬 방법을 찾을 수 있었습니다.

OrderSpecifier 공식문서

@Immutable
public class OrderSpecifier<T extends Comparable> implements Serializable {

    private static final long serialVersionUID = 3427652988262514678L;

    /**
     * Behaviour for order of null values
     */
    public enum NullHandling { Default, NullsFirst, NullsLast }

    private final Order order;

    private final Expression<T> target;

    private final NullHandling nullHandling;

    public OrderSpecifier(Order order, Expression<T> target, NullHandling nullhandling) {
        this.order = order;
        this.target = target;
        this.nullHandling = nullhandling;
    }

    public OrderSpecifier(Order order, Expression<T> target) {
        this(order, target, NullHandling.Default);
    }

OrderSpecifier 은 Sort의 Order(ASC/DESC)와 Expression<T> target, 즉 정렬 기준이 되는 칼럼의 path를 이용해 생성할 수 있습니다.

OrderSpecifier 리스트 생성 메서드

  private List<OrderSpecifier> getAllOrderSpecifiers(Pageable pageable) {
      List<OrderSpecifier> ORDERS = new ArrayList<>();

      if (!isEmpty(pageable.getSort())) {
          for (Sort.Order order : pageable.getSort()) {
              Order direction = Order.DESC; 

              switch (order.getProperty()) {
                  case "createdAt":
                      ORDERS.add(new OrderSpecifier(direction, post.createdAt));
                      break;
                  case "hearts":
                      ORDERS.add(new OrderSpecifier(direction, post.hearts.size()));
                  default:
                      break;
              }
          }
      }
      return ORDERS;
  }
  • ORDERS : 정렬 조건이 늘어날 수 있으므로 List로 구현
  • pageable의 sort 필드를 탐색하며 OrderSpecifier 객체 생성
  • 이 프로젝트에서는 내림차순 정렬만 필요해 Order direction = Order.DESC; 로 구현했다. 필요에 따라 Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC; 로 구현하면 상황에 따라 정렬 조건을 바꿀 수 있다.

생성된 OrderSpecifier 객체를 querydsl orderBy 함수의 인자로 넣어주면 됩니다.

    public Page<Post> findAllPostsPage(FindPostRequest request, Pageable pageable) {
        List<OrderSpecifier> ORDERS = getAllOrderSpecifiers(pageable);

        List<Post> content = queryFactory
                .selectFrom(post)
                .leftJoin(post.hearts, heart)
                .where(
                        titleEq(request.getTitle())
                )
                .orderBy(ORDERS.stream().toArray(OrderSpecifier[]::new))
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        JPAQuery<Long> countQuery = queryFactory
                .select(post.count())
                .from(post)
                .where(titleEq(request.getTitle()));

        return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne);
    }

References

0개의 댓글