article thumbnail image
Published 2022. 9. 2. 15:09

PageRequest of 

of() 설명
PageRequest.of(int page, int size) 페이지 번호(0부터 시작), 페이지당 데이터의수
PageRequest.of
(int page, int size, Sort.Direction direction, String ...props)
페이지 번호, 페이지당 데이터의 수, 정렬 방향, 속성(칼럼)
PageRequest.of(int page, int size, Sort sort) 페이지 번호, 페이지당 데이터의 수, 정렬방향

 

 

Page 객체 구성

메소드 설명
int getNumber() 현재 페이지의 정보
int getSize() 한 페이지의 크기
int getTotalPages 전체 페이지의 수
int getNumberOfElements() 결과 데이터 수
boolean hasPreviousPage() 이전 페이지의 존재 여부
boolean hasNextPage() 다음 페이지의 존재 여부
boolean isLastPage() 마지막 페이지 여부
Pageable nextPageable() 다음 페이지 객체
Pageable previousPageable() 이전 페이지 객체
List<T> getContent() 조회된 데이터
boolean hasContent() 결과 존재 여부
Sort getSort() 검색 시 사용된 Sort 정보

 

 

@RestController
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping("/users")
    public Page<User> getAllUsers() {
        PageRequest pageRequest = PageRequest.of(0, 5);
        return userRepository.findAll(pageRequest);
    }

    @PostConstruct
    public void initializing() {
        for (int i = 0; i < 100; i++) {
            User user = User.builder()
                    .username("User " + i)
                    .address("Korea")
                    .age(i)
                    .build();
            userRepository.save(user);
        }
    }
}

getAllUsers() 메서드에 보면 PageRequest 객체가 존재한다.

 

PageRequest 객체는 Pageable 인터페이스를 상속받는다.

 

쉽게 Paging 을 위한 정보를 넘길 수 있는데, 이 정보에는 정렬 정보, 페이지 offset, page와 같은 정보가 담겨있다.

 

initializing() 을 이용해서 100명의 데이터를 추가해주고 api 호출을 해보자.

 

api 호출을 브라우저에서 직접 url 로 해도 좋고 curl 을 해도 좋지만 나는 Postman을 이용할 것이다.

 

결과

"content":[
{
    "content": [
        {"id": 1, "username": "User 0", "address": "Korea", "age": 0},
        // 중간 생략
        {"id": 5, "username": "User 4", "address": "Korea", "age": 4}
    ],
    "pageable": {
        "sort": {
            "sorted": false, // 정렬 상태
            "unsorted": true,
            "empty": true
        },
        "pageSize": 5, // 한 페이지에서 나타내는 원소의 수 (게시글 수)
        "pageNumber": 0, // 페이지 번호 (0번 부터 시작)
        "offset": 0, // 해당 페이지에 첫 번째 원소의 수
        "paged": true,
        "unpaged": false
    },
    "totalPages": 20, // 페이지로 제공되는 총 페이지 수
    "totalElements": 100, // 모든 페이지에 존재하는 총 원소 수
    "last": false,
    "number": 0,
    "sort": {
        "sorted": false,
        "unsorted": true,
        "empty": true
    },
    "size": 5,
    "numberOfElements": 5,
    "first": true,
    "empty": false
}

 

 

쿼리 메서드에서 페이징 사용하기

public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findByAddress(String address, Pageable pageable);
}

이렇게 사용자의 주소로 조회하는 쿼리 메서드를 만들고 두 번째 파라미터로 Pageable 을 넘겨주면 된다.

 

그리고 컨트롤러에 가서 다시 PageRequest 를 만들어주자.

 

 

 쿼리 파라미터로 넘어온 값을 페이지 정보로 

@RestController
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping("/users")
    public Page<User> getAllUserWithPageByQueryMethod(@RequestParam("page") Integer page, @RequestParam("size") Integer size) {
        PageRequest pageRequest = PageRequest.of(page, size);
        return userRepository.findByAddress("Korea", pageRequest);
    }


    @PostConstruct
    public void initializing() {
        for (int i = 0; i < 100; i++) {
            User user = User.builder()
                    .username("User " + i)
                    .address("Korea")
                    .age(i)
                    .build();
            userRepository.save(user);
        }
    }
}

이렇게 만들고 http://localhost:8080/users/?page=3&size=4 로 요청을 보내면 다음과 같은 결과가 출력된다.

 

{
  "content": [
    { "id": 13, "username": "User 12", "address": "Korea", "age": 12 },
    { "id": 14, "username": "User 13", "address": "Korea", "age": 13 },
    { "id": 15, "username": "User 14", "address": "Korea", "age": 14 },
    { "id": 16, "username": "User 15", "address": "Korea", "age": 15 }
  ],
  "pageable": {
    "sort": { "sorted": false, "unsorted": true, "empty": true },
    "pageNumber": 3,
    "pageSize": 4,
    "offset": 12,
    "paged": true,
    "unpaged": false
  },
  "totalPages": 25,
  "totalElements": 100,
  "last": false,
  "numberOfElements": 4,
  "number": 3,
  "sort": { "sorted": false, "unsorted": true, "empty": true },
  "size": 4,
  "first": false,
  "empty": false
}

 

 

반환 타입에 따른 페이징 결과

 

Spring Data JPA 에는 반환 타입에 따라서 각기 다른 결과를 제공한다.

 

  1. Page<T> 타입
  2. Slice<T> 타입
  3. List<T> 타입

각자 다른 결과를 반환해준다.

 

Page<T> 는 일반적인 게시판 형태의 페이징에서 사용된다.

 

여기서 중요한 정보는 총 페이지 수 이다.

 

그 정보를 포함하여 반환한다.

 

 

Page<T> 타입은 count 쿼리를 포함하는 페이징으로 카운트 쿼리가 자동으로 생성되어 함께 나간다.

Slice<T> 타입

Slice<T> 타입을 반환 타입으로 받게 된다면 더보기 형태의 페이징에서 사용된다.

 

{
  "content": [
    { "id": 13, "username": "User 12", "address": "Korea", "age": 12 },
    { "id": 14, "username": "User 13", "address": "Korea", "age": 13 },
    { "id": 15, "username": "User 14", "address": "Korea", "age": 14 },
    { "id": 16, "username": "User 15", "address": "Korea", "age": 15 }
  ],
  "pageable": {
    "sort": { "sorted": false, "unsorted": true, "empty": true },
    "pageNumber": 3,
    "pageSize": 4,
    "offset": 12,
    "paged": true,
    "unpaged": false
  },
  "number": 3,
  "numberOfElements": 4,
  "first": false,
  "last": false,
  "size": 4,
  "sort": { "sorted": false, "unsorted": true, "empty": true },
  "empty": false
}

Page<T> 타입의 반환에 없는 것들이 존재한다.


number과 numberOfElements 그리고 Page<T> 에 존재하던 totalPages, totalElements 가 없어졌다.

 

Slice<T> 타입은 추가 count 쿼리 없이 다음 페이지 확인 가능하다. 내부적으로 limit + 1 조회를 해서 totalCount 쿼리가 나가지 않아서 성능상 조금 이점을 볼 수도 있다.

 

 

 

List<T> 타입

@GetMapping("/users")
public List<User> getAllUsers(Pageable pageable) {
  return userRepository.findAll(pageable);
}

List 반환 타입은 가장 기본적인 방법으로 count 쿼리 없이 결과만 반환한다.

 

 

Spring Web MVC 에서 더 편하게 페이징하기

Spring Data JPA의 페이징과 정렬 기능보다 훨씬 간편하게 MVC 에서 사용할 수 있게 한다.

 

즉, 다음과 같이 사용자가 정의한 파라미터에 따라서도 페이징이 가능하다는 소리이다.

 

@GetMapping("/users")
public Page<User> getAllUsers(Pageable pageable) {
    return userRepository.findAll(pageable);
}

컨트롤러에서 @GetMapping 에 파리미터로 Pageable 을 추가하면 된다.

 

그럼 페이징 관련 쿼리가 나온다.

 

Springboot 내부에서 url 파라미터가 컨트롤러에 바인딩이 될 때, Pageable이 존재하면 PageRequest 객체를 생성한다.

 

해당 객체에서 역시 정렬도 제공하는데, url을 다음과 같이 치면 정렬과 페이징이 동시에 수행되게 할 수 있다.

 

  • http://localhost:8080/members?page=0
    • 0번 페이지 부터 20개 조회한다.
      • default 가 20개로 default를 수정하는 방법도 존재한다.
  • http://localhost:8080/members?page=0&size=5
    • 0번 페이지부터 5개 조회한다.
  • http://localhost:8080/members?page=0&size=5&sort=id.desc
    • 0번 페이지부터 5개 조회 하는데, id의 역순으로 조회한다.

'JPA' 카테고리의 다른 글

JPA - Jpa를 이용한 페이지 처리 및 검색  (0) 2022.09.09
JPA - Jpa를 이용한 RESTful API 만들기  (0) 2022.09.08
JPA - Paging  (0) 2022.09.01
JPQL - 벌크 연산  (0) 2022.07.10
JPQL - Named 쿼리  (0) 2022.07.10
복사했습니다!