Pagination

박채은·2022년 12월 26일
0

Spring

목록 보기
15/35

스프링 데이터 JPA는 매우 편리하게 표준화된 페이징 및 정렬 방식을 제공한다.

  • 페이징과 정렬 파라미터
    • org.springframework.data.domain.Sort : 정렬 인터페이스
    • org.springframework.data.domain.Pageable : 페이징 인터페이스 (내부에 Sort 포함)

Repository

CrudRepository

  • CRUD 메소드를 가지고 있는 인터페이스

PagingAndSortingRepository

  • CrudRepository를 상속받은 인터페이스
  • CRUD 메소드에 Paging과 Sorting 기능이 추가

PagingAndSortingRepository


Pagination

  • 사용자가 볼 만큼만 서버에 요청하면서 서버에 부하를 줄이도록 하는 기술

Pageable

  • 페이징 인터페이스

  • Pageable을 사용할 때 반환 타입

    • Page : 전체 데이터의 갯수를 세는 count 쿼리 결과를 포함하는 객체
      • Slice를 상속한다.
    • Slice : count 쿼리 없이 다음 페이지만 확인 가능한 객체
    • List : count 쿼리 없이 결과만 반환

ListSlicePage

Page<Member> findByUsername(String username,Pageable pageable); // count 쿼리 포함
Slice<Member> findByUsername(String username,Pageable pageable); // 결과 + 다음 페이지
List<Member> findByUsername(String username,Pageable pageable); // 결과만 반환

Page vs Slice

  • Page는 select 쿼리 이후에, 전체 데이터의 갯수를 세는 count 쿼리를 실행한다.
  • Slice는 count 쿼리가 없지만, select 쿼리 시에 limit + 1까지의 데이터를 가져온다.
    • count 쿼리가 없기 때문에 성능상 유리하다.
    • 데이터 양이 많을수록 Slice를 사용하는 것이 좋다.

✔️ 언제 사용하나요?
- Page : 게시판처럼 데이터의 갯수가 파악되어야 하는 경우 사용된다.
- Slice : 무한 스크롤 등 데이터의 갯수가 필요없는 상황에서 사용된다.

Page와 Slice의 차이점


PageRequest

  • Pageable의 구현체
  • PageRequest 생성자의 파라미터에는 현재 페이지, 조회할 데이터 수, 정렬 정보가 들어갈 수 있다.
    • page
    • size
    • Sort 객체: default가 오름차순
  • page는 0부터 시작한다.
    • 사용자/클라이언트는 1부터 시작이므로, page 값을 받아와서 page-1 해줘야 한다.
  • PageRequest.of() : PageRequest를 생성해주는 메소드

Pagination 구현

✔️ 목표
회원 정보 목록 조회 기능에 페이지네이션(Pagination) 기능을 적용하는 실습

✔️ 조건
인메모리 데이터베이스인 H2의 MEMBER 테이블에 20건의 데이터가 저장되어 있다.
MEMBER 테이블의 데이터를 Pagination을 적용하여 memberId 기준 내림차순(최신순)으로 클라이언트에게 전달한다.

✔️ 전체 코드
Github


DTO

Pagination을 적용한 데이터를 담을 DTO 클래스가 필요하다.
=> PaginationResponseDto 생성

PageInfo

  • Page에 관한 정보를 가진 객체

MemberResponseDto

  • Member에 관한 정보를 가진 객체

PaginationResponseDto

  • Pagination을 적용했을 때, 클라이언트에게 전달해야하는 응답 데이터
  • Page에 대한 정보(pageInfo)와, 해당 페이지에 존재하는 Member 리스트에 대한 데이터(data)를 포함해야한다.


MemberRepository

MemberRepository에 paging 기능을 위한 별도의 메서드 생성해야 한다.

기존 CrudRepository 인터페이스 내에는 Iterable<T> findAll()만 있다.

Paging을 수행해주는 Page<Member> findAll(Pageable pageable);를 추가해준다.

매개변수로 Pageable 타입의 객체(PageRequest)를 넘겨주면, PageRequest의 정보를 읽어 Member 객체를 담은 Page 객체를 리턴해준다.


MemberService

Pageable의 구현체인 PageRequest 객체를 생성하여, findAll 메서드에 전달한다.

  • Sort.by(Sort.Direction.DESC, "memberId") : memberId를 기준으로 내림차순 정렬

Controller

  • getMembers() 메서드에 페이지네이션을 적용한다.

  • page와 size를 쿼리 파라미터(@RequestParam)로 받는다.

  • page는 1인 아닌 0부터 시작하기 때문에 page-1 해준다.

  • MemberService의 findMembers() 메서드를 통해 Page 객체를 리턴받는다.

  • Page 객체로부터 Page에 대한 정보를 얻어, PageInfo를 생성한다.

  • getContent()를 통해서 데이터를 List로 받아온다.

  • mapper.membersToMemberResponseDtos()를 통해서 List<Member>List<MemberResponseDto>로 변환한다.


시행착오

1. import 에러

https://velog.io/@qwd101/JPA-Repository%EC%97%90%EC%84%9C-Paging-query-needs-to-have-a-Pageable-parameter-%EC%97%90%EB%9F%AC-%EB%B0%9C%EC%83%9D-%ED%95%B4%EA%B2%B0

Pageable을 import 할 때, 두 가지 선택지가 있었다.

  1. import java.awt.print.Pageable;
  2. import org.springframework.data.domain.Pageable;

2번을 import 해야하는데, 1번을 import하여 문제가 발생했다.

2. getter의 부재

페어님께서 실습을 진행하시다가 Postman에서 Error가 발생했다.
분명 코드의 로직은 맞는 거 같은데 왜 오류가 발생했는지 서로 고민해보다가 원인이 getter를 작성하지 않았기 때문임을 알게 되었다.

정확히는 "PaginationResponseDto에 getter를 사용하지 않아서" 이다.

✅ DTO 클래스를 만들 때, getter 메서드가 없으면
Response Body에 해당 멤버 변수의 값이 포함되지 않거나, Mapper 사용 시에 맵핑이 안 되는 문제가 발생한다.

따라서 DTO 클래스를 만들 때, 무조건 getter는 작성해줄 것! (setter 메서드는 필수 항목은 아니다!)


[참고]
https://velog.io/@2yeseul/Spring-Jpa-Pagination-%EC%B2%98%EB%A6%AC
https://velog.io/@bagt/0704-Spring-Pagination-API-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98
https://velog.io/@jyleedev/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-JPA-Pageable-Page
https://jaime-note.tistory.com/52

0개의 댓글