스프링 데이터 JPA는 매우 편리하게 표준화된 페이징 및 정렬 방식을 제공한다.
org.springframework.data.domain.Sort
: 정렬 인터페이스org.springframework.data.domain.Pageable
: 페이징 인터페이스 (내부에 Sort 포함)CrudRepository
를 상속받은 인터페이스페이징 인터페이스
Pageable을 사용할 때 반환 타입
Page
: 전체 데이터의 갯수를 세는 count 쿼리 결과를 포함하는 객체Slice
를 상속한다.Slice
: count 쿼리 없이 다음 페이지만 확인 가능한 객체List
: count 쿼리 없이 결과만 반환✅
List
⊂Slice
⊂Page
Page<Member> findByUsername(String username,Pageable pageable); // count 쿼리 포함
Slice<Member> findByUsername(String username,Pageable pageable); // 결과 + 다음 페이지
List<Member> findByUsername(String username,Pageable pageable); // 결과만 반환
limit + 1
까지의 데이터를 가져온다.✔️ 언제 사용하나요?
- Page : 게시판처럼 데이터의 갯수가 파악되어야 하는 경우 사용된다.
- Slice : 무한 스크롤 등 데이터의 갯수가 필요없는 상황에서 사용된다.
page-1
해줘야 한다.PageRequest.of()
: PageRequest를 생성해주는 메소드✔️ 목표
회원 정보 목록 조회 기능에 페이지네이션(Pagination) 기능을 적용하는 실습
✔️ 조건
인메모리 데이터베이스인 H2의 MEMBER 테이블에 20건의 데이터가 저장되어 있다.
MEMBER 테이블의 데이터를 Pagination을 적용하여 memberId 기준 내림차순(최신순)으로 클라이언트에게 전달한다.
✔️ 전체 코드
Github
Pagination을 적용한 데이터를 담을 DTO 클래스가 필요하다.
=>PaginationResponseDto
생성
pageInfo
)와, 해당 페이지에 존재하는 Member 리스트에 대한 데이터(data
)를 포함해야한다.
MemberRepository
에 paging 기능을 위한 별도의 메서드 생성해야 한다.
기존 CrudRepository 인터페이스 내에는 Iterable<T> findAll()
만 있다.
Paging을 수행해주는 Page<Member> findAll(Pageable pageable);
를 추가해준다.
매개변수로 Pageable 타입의 객체(PageRequest
)를 넘겨주면, PageRequest
의 정보를 읽어 Member 객체를 담은 Page 객체를 리턴해준다.
Pageable의 구현체인 PageRequest 객체를 생성하여, findAll 메서드에 전달한다.
Sort.by(Sort.Direction.DESC, "memberId")
: memberId
를 기준으로 내림차순 정렬getMembers() 메서드에 페이지네이션을 적용한다.
page와 size를 쿼리 파라미터(@RequestParam
)로 받는다.
page는 1인 아닌 0부터 시작하기 때문에 page-1
해준다.
MemberService의 findMembers()
메서드를 통해 Page
객체를 리턴받는다.
Page 객체로부터 Page에 대한 정보를 얻어, PageInfo를 생성한다.
getContent()
를 통해서 데이터를 List로 받아온다.
mapper.membersToMemberResponseDtos()
를 통해서 List<Member>
를 List<MemberResponseDto>
로 변환한다.
Pageable을 import 할 때, 두 가지 선택지가 있었다.
import java.awt.print.Pageable;
import org.springframework.data.domain.Pageable;
2번을 import 해야하는데, 1번을 import하여 문제가 발생했다.
페어님께서 실습을 진행하시다가 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