JPA 페이징
개요
JPA에서 페이징을 사용하기 위해 JPQL로 작성해보면,
@Query("SELECT ue FROM UserEntity AS ue LIMIT=:limit")
List<UserEntity> findAllByPage(@Param("limit") int limit);
문제가 발생한다. 즉, JPQL에서 LIMIT을 동적쿼리로는 사용하지 못한다는 것이다.
페이징을 가능하게 하는 객체들
1. Page
페이징된 데이터 결과 집합을 나타내는 인터페이스
org.springframework.data.domain.Page
- Pageable을 파라미터로하여 가져온 결과물은
Page<T>
형태로 반환된다. Page
인터페이스는 데이터 페이지와 관련된 다양한 메서드를 제공한다.getCount()
: 현재 페이지에 있는 엔티티 목록을 반환getTotalPage()
: 전체 페이지 수를 반환getTotalElements()
: 전체 엔티티 수 반환getNumber()
: 현재 페이지 번호 반환getSize()
: 페이지당 엔티티 수 반환
2. Pageable
데이터를 가져오는데 사용되는 페이징 및 정렬 정보를 나타내는 인터페이스
org.springframework.data.domain.Pageable
- JPA에서 사용할 때 자동으로
Pageable
타입을 넘겨주면 자동으로 검색 조건을 붙여준다. - Controller단에서
@PageableDefault
메서드 파라미터를 사용하면 Pageable 객체에 대한 파라미터를 넘기지 않아도 자동으로 기본값을 가진 Pageable 타입 파라미터를 제공한다. - Pageable 객체에서는 다양한 검색 관련한 메서드를 제공한다.
getPageNumber()
: 가져올 페이지 번호를 반환getPageSize()
: 페이지당 엔티티 수를 반환getOffset()
: 현재 페이지의 시작 위치(오프셋) 반환getSort()
: 데이터 정렬 정보를 나타내는Sort
객체를 반환
3. PageRequest
PageRequest
는 Pageable 생성하기 위한 구현 클래스 중 하나이다.
org.springframework.data.domain.PageRequest
PageRequest
를 사용하면 페이지 번호, 페이지 크기, 정렬 조건을 지정하여Pageable
객체를 생성할 수 있다.- 주요 생성자는 아래와 같다.
PageRequest.of(int page, int size)
: 페이지 번호와 페이지당 수를 지정하여Pageable
객체를 생성PageRequest(int page, int size, Sort sort)
: 페이지 번호, 페이지당 수, 정렬 조건을 지정하여pageable
객체를 생성
분석해보기
PagingAndSortingRepository
JpaRepository
인터페이스는 ListPagingAndSortingRepository
를 확장하고 있으며, 그 안에는 PageingAndSortingRepository
를 확장받고 있다.
(PagingAndSortingRepository
→ ListPagingAndSortingRepository
→ JpaRepository
)
PagingAndSortingRepository
안에는 Sort
, Pageable
객체를 파라미터로 받는 메서드가 존재한다.
즉, JpaRepository를 사용할 경우, PagingAndSortingRepository를 확장받아, 페이지 및 정렬 가능하게 한다는 것이 핵심이다
활용해보기
다양한 활용 방법이 있겠지만, 직접 PageRequest를 이용한 예를 들어 정리해보려 한다.
1. Cotroller
// UserController.class
@GetMapping("/list")
public Page<User> getUserListController(@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int pageSize) {
Pageable pages = PageRequest.of(page-1, pageSize);
return userService.getUserListService(pages));
}
- 페이지 번호, 페이지당 건수를 요청 파라미터로 받는다.
PageRequest.of
를 사용하여 페이징 검색 정보를 담은Pageable
타입인 객체를 받아 service단으로 넘긴다.- 컨트롤러의 response 타입은
Page
타입이다.
2. Service
// UserSerivce.class
// 2-1
public Page<User> getUserListService(Pageable pages) {
return userRepository.findAll(pages);
}
// 2-2
public Page<User> getUserListService1(Pageable pages) {
return userRepository.findAllByJpa(pages);
}
// 2-3
public Page<User> getUserListService2(Pageable pages) {
return userRepository.findAllByJpql(pages);
}
- 메서드 파라미터로
Pageable
타입을 받고, 해당 파라미터를 Repository로 전달한다. findAll
(2-1)에서는 Pageable 타입을 받아 해당 페이징 검색을 기반으로 쿼리를 변환해서 DB에 요청한다findAllByJpa
및findAllByJpql
같은 경우는 직접 Repository에 작성해보고자 한다.
3. Repository
// UserRepository.class
// 3-2
Page<WordEntity> findAllByJpa(Pageable pages);
// 3-3
@Query("SELECT ue FROM UserEntity AS ue")
Page<UserEntity> findAllByJpql(Pageable pages);
- JPA나 JPQL 둘 다 사용하는데 큰 차이는 없다.
- 추가 파라미터를 사용하더라도, Pageable의 선언 순서는 상관없다.
응답 데이터
"content": [
{
// ...생략
// DB 엔티티 내용
}
],
"pageable": {
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageNumber": 0,
"pageSize": 10,
"paged": true,
"unpaged": false
},
"last": true,
"totalPages": 1,
"totalElements": 1,
"size": 10,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"number": 0,
"first": true,
"numberOfElements": 1,
"empty": false
}
Ref :
https://velog.io/@albaneo0724/Spring-Pagination%EA%B3%BC-Page-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Pageable