게시판을 추천순, 날짜순 등으로 정렬을 하고자 했습니다. 처음에는 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);
}