문제 상황
'너나들이' 프로젝트 중 Querydsl을 활용하여 어렵게 어렵게 객체 join을 구현하고 페이징처리까지 했으니 이젠 좀 무난하게 검색기능을 마무리 하나 싶었습니다.
그러나.. 사용자의 기호에 따라 동적으로 정렬해주는 필터링 기능을 구현하려고 기분 좋게 pageable에 sort 정보를 빼올려고 했는데,,
offset 과 limit은 pageable에서 정보를 가져올 수 있었지만 sort는 에러가 나는 것을 확인했습니다.
만약 정적으로 정렬을 해줄려면 Qpost객체가 갖고 있는 칼럼을 하나 뽑아서 오름차순 또는 내림차순을 시켜주면 됩니다. ex) 'orderBy(post.postId.desc())'
그러나! 저는 동적 Sorting을 어떻게든 해보고 싶어서 orderBy가 필요로 하는 인자가 무엇일까 찾아봤더니
이렇게 오늘의 주인공인 OrderSpecifier 라는 클래스를 구현해주어야 한다는 것을 알 수 있었습니다.
해결 과정
그럼 대체 어떻게 OrderSpecifier를 구현할 것인가...에 대한 고민에 빠져서 공식문서를 확인해봤습니다.
생성자를 유심히 봤는데 필요로 하는 인자들은 Sort의 order와 Expression 객체, Null값을 핸들링하기 위한 enum값이었습니다.
order는 pageable에 sort 정보로 넣어놨던 것을 빼오면 될 것 같고, null핸들링은 enum 타입 중 default 기준으로 진행하면 된다는 생각이 들었으나 Expression<>..? 에 관한 것은 감이 오지 않았습니다.
그러면? 구글링.
https://uchupura.tistory.com/7
위 블로그를 참고해서 파악한 결과, Expression target은 정렬 기준이 되는 칼럼의 Path로, 기준이 되는 칼럼과 그 칼럼이 속한 엔티티가 합쳐진 것이었습니다. 예를 들어 postId를 정렬 기준으로 정하면, postId는 당연히 Post 엔티티에 속할 것이고 이 두개가 합쳐진 Post객체.postId가 Path가 되는 것입니다.
이와 같이 표현될 수 있습니다.
List형태로 반환되는 이유는 애초에 sort정보를 여러 개 넣을 수 있기 때문이고, 저 또한 첫번째 정렬기준에서 동일한 값을 가진 경우는 최신순으로 조회되게 설정하기 위해 sort정보를 2개 넣었습니다. 이게 무슨 말인지 확인해보기 위해 일부러 코드에서 print를 찍어봤습니다.
프린트가 찍힌 것을 보면 그림에 표시한 대로 같은 형태의 정보가 2번 나온 것을 알 수 있고 첫번째 기준이 likeCnt(스크랩 순)이고 그 수가 같을 경우 2번째 기준인 postId로 최신순으로 도출하겠다고 한 것입니다.
그럼 결국 orders 리스트에 add되는 것은 생성자를 통해 구현한 OrderSpecifier객체들 입니다.
ex) new OrderSpecifier(DESC, post.likeCnt)...
그럼 이제 마지막으로 우리가 구현한 getOrderSpecifier() 메소드를 orderBy()에 어떻게 적용시키냐만 남았습니다.
구현한 코드부터 보여드리겠습니다.
친숙하지는 않지만 인자로 OrderSpecifier를 주기 위해서 stream api를 활용했습니다. 아직 람다식과 함수형 인터페이스를 잘 몰라서 알고쓰기 위해 더욱 학습이 필요한 부분이긴 합니다.
따라서 기본적인 흐름을 위주로 말씀드리면,
pageable.sort()를 인자로 넣어서 getOrderSpecifier의 List결과값을 반환했고 이를 stream 하여 .toArray() 메소드를 활용해 OrderSpecifier를 배열 형태로 만들어 적용시켰습니다.
'OrderSpecifier[]::new' 는 함수형 인터페이스에서 생성자 메소드 참조로, :: 기준 우측에 있는 생성자 메소드를 적용해 배열을 생성하겠다는 말입니다.
보다 문법적인 자세한 설명은 이 블로그를 참고했습니다!
결론
우리가 흔히 생각하는 조회순, 스크랩순, 최신순으로 유저가 선택할 때 마다 동적으로 정렬하는 것에 성공했습니다!🥳
이 방법 외에도 미쳐 몰랐던 더 쉬운 방법이나 다른 방법이 있을 수도 있습니다. 그러나 처음 보는 클래스를 구현하기 위해 공식문서를 파헤쳐보고 구현하기 위해 새로운 기술들을 연달아 배워 볼 수 있는 기회였고 공부할 거리만 산더미처럼 얻어간...값진 경험이었습니다 ㅎㅎ
동적 sort를 할수없어서 정적 sort로 바꾸려고했었는대 솔루션 잘봤습니다.