Dev입성기/Dev 입성기_중기

본인이 좋아요 표시한 게시글 - 모두 조회 - 페이징

Mon Groy 2024. 7. 3. 03:19

조건

페이징 처리(5개씩)

 

며칠 전 자바의 정석에서 상속이나 인터페이스를 활용한 메서드를 생성하는 예시를 보고 한 번쯤 사용해 보고 싶었는데

이번 강의에서도 이를 활용하고 있었기에 이번 개인 과제를 진행하면서 참고해서 적용해보기로 했다

다른 점이라면 지난 팀과제에 이어 개인과제를 진행하는 것이라 adapter가 추가되어 있어서 이것도 고려해야 한다는 점이겠다

 

강사님이 만들어 놓은 결과물을 면밀히 뜯어 보다가 새롭게 알게 된 것

interface 가 interface 를 상속받을 때 extends 를 사용하며,

interface 의 기능 중 하나라도 구현한다면 그 때 implements 를 사용한다


 

JpaRepository ThanksQueryRepository
ThanksRepository
  ThanksQueryRepositoryImpl

 

클래스인 ThanksQueryRepositoryImpl 과 인터페이스인 ThanksQueryRepository를 새로 생성한다

 

ThanksRepository 는 두 인터페이스 JpaRepository 와 ThanksQueryRepository 의 상속을 받고

ThanksQueryRepositoryImpl 은 ThanksQueryRepository 의 상속을 받는다

 

ThanksRepository 는 단순 CRUD 를 수행하도록 하고 (JpaRepository의 영향)

나머지는 ThanksQueryRepositoryImpl 에서 수행하도록 할 것이다

 

ThanksQueryRepositoryImpl 이 ThanksQueryRepository에서 정의해 둔 메서드를 완성할 것이므로

ThanksRepository 에서 ThanksQueryRepository 에서 정의된 메서드를 사용할 때

ThanksQueryRepositoyImpl 의 메서드가 호출될 것이다

 

여기에 ThanksAdapter도 ThanksRepository를 호출하도록 설정되어 있이므로

큰 흐름은 결국 ThanksRepository 가 담당하는 것이다


강사님의 코드를 면밀히 뜯어보다가 또 발견한 것들이 있다

바로, 검색 조건을 한 클래스에 모아 놓은 것

찾아보니 보통 Condition 의 줄임말인 Cond 를 붙인다고 한다

 

그리고 이게 뭐야? 싶은 것이 있었는데

query 를 '분리'해 놓은 것이었다

더보기

query 라고 하는 단순 메서드 라고 여겨서

반환값이 List나 collection 타입으로 나오지 않는 이유가 뭐지?

라고 한참 생각했는데 이리저리 지지고볶다보니

query를 분리한 것이었던 것이다

페이징 처리하는 부분은 따로 분리해 놓지 않고 그냥 추가해 놓으셔서 알아챌 수 있었다

아마 일부러 힌트를 남겨두신 것이 아닐까?

 

거기에 정렬하는 것도 따로 떨어뜨려 놓으셔서

나는 모두 메서드로 뺀 다음 연결시키고 싶어졌다

var query = query(thread, cond)

             .offset(pageable.getOffset())

             .limit(pageable.getPageSize());

 

query.orderBy(thread.mentions.any().createdAt.desc());

 

var threads = query.fetch();

여기의 모든 쿼리를 각 역할에 맞는 메서드로 빼고 한 줄로 연결시킬 심산이다

물론 내가 작성하고 있는 도움이 돼요 기능에 맞춰서 말이다


private <T> JPAQuery<T> query(Expression<T> expr, ThreadSearchCond cond) {

return jpaQueryFactory.select(expr)

 

강사님이 만들어 두신 메서드를 구경하다가

Expression<T> 는 의문에 둔 채로 이것저것 구글링한다고 돌아다니고 있었다

그러다가 발견한 것이 상위의 관계도인데, 거기에 Expression<T> 가 있어 갑자기 이해가 되었다

얼마 전에 상속을 공부한 덕에 이해를 할 수 있었다고 생각한다


실력 격차가 심한 코드를 뜯어보고 있자니 시간이 참 잘 간다


https://earth-95.tistory.com/116

 

[Querydsl, pageable] slice를 이용한 무한 스크롤

들어가기 전에프로젝트를 진행하면서, 빵집의 상세 페이지에서 메뉴 더보기 클릭 시, 해당 빵집에 존재하는 모든 메뉴를 순차적으로 보여주어야 했습니다. 이때, 아래로 쭉 내렸을 때 메뉴가 더

earth-95.tistory.com

https://rachel0115.tistory.com/entry/QueryDsl-Page-Slice-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98-%EB%AC%B4%ED%95%9C-%EC%8A%A4%ED%81%AC%EB%A1%A4

 

[QueryDsl] Page, Slice (페이지네이션, 무한 스크롤)

개요 페이지네이션과 무한 스크롤은 사용자가 컨텐츠를 조작할 때 중요한 역할을 합니다. 사용자가 특정 정보를 탐색하는 과정에 영향을 미치기 때문에 UX에서 매우 중요한 요소라고 볼 수 있습

rachel0115.tistory.com

 

queryDsl 을 이용한 페이징이 내 실력엔 아직 어렵워서 내일 마저 해보기로 했다


fetchResults() 기능이 Deprecated 된 바람에 페이징 처리를 따로 진행해 줘야 하는데

그 때 전체 페이지 수를 count 하는 절차가 필요하다

 

처음에 queryDSL 한 메서드로 정렬과 페이지 수 처리까지 하는 건 좋았는데

여러 메서드로 분리하려다 보니까 반환타입의 차이 때문에

세조각으로 나누는 것은 힘들다는 것을 깨달았다

List<Thanks> result = query(thanks, user)

             .orderBy(thanks.userReviews.createdAt.desc())

             .offset(pageable.getOffset())

             .limit(PAGE_SIZE_FIVE)

             .fetch();

여기에서 정렬과 페이징 설정도 떼어내고 싶었는데 그러지 못했다

 

구글링해 본 결과 데이터를 count 하여 페이징 상태로 return 하는 방법은 크게 두 가지였다

private JPAQuery<Long> countQuery(User user) {

              return jpaQueryFactory

              .select(Wildcard.count)

              .from(thanks)

              .where(userIdEq(user.getId()));

}

일단 이 메서드가 정의된 전제 하에서

 

1. count 를 Long 타입으로 반환받을 경우

long total = countQuery(user).fetch().get(0);

return PageableExecutionUtils.getPage(result, pageable, () -> total);

 

2. count 를 JPAQuery<Long> 타입으로 반환받을 경우

JPAQuery<Long> total = countQuery(user);

return PageableExecutionUtils.getPage(result, pageable, total::fetchCount);