PageNation은 문서를 개별 페이지로 나누는 프로세스를 말한다.
어떠한 데이터의 목록을 불러올 때, 무한 스크롤을 사용해 목록을 꾸리면 가독성이 떨어지고 한 페이지가 담는 정보의 양도 수없이 많아질 것이다. 이런 경우를 방지하고자, 적절한 순서를 매겨 적당량의 데이터를 한 페이지에 보일 수 있도록 해야 한다.
클라이언트의 요청을 제일 먼저 캐치해서 적절한 메서드에 Mapping 하는 일은 API계층인 Controller
에서 진행한다.
클라이언트의 요청을 받은 Controller
는 비즈니스 로직이 담긴 Service
에게 해당 요청과 요청에 필요한 파라미터 값을 넘겨준다.
Service
는 해당 요청에 대한 데이터를 Repository
에서 불러온다. 이때 사용하는 Repository
메서드는 findAll()이다!
Repository
는 구현된 로직 하나 없지만, JpaRepository
를 상속 받고 있어 JpaRepository
의 메서드를 사용할 수 있다.
🧐 JpaRepository<Member, Long>
Member는 JpaRepository를 상속 받고 있는 Repository가 다루는 Entity 클래스를 가르키고, Long은 해당 Entity 클래스의 @Id 애너테니션이 붇은 필드 변수의 타입을 의미한다.
JpaRepository
의 메서드인 findAll()를 살펴보면 어디서, 어떻게 Pagenation를 구현해야 하는지 전혀 감이 오지 않는다.
그치만 두 눈 크게 뜨고 살펴보면 답이 보인다.🤓
(나는 몰랐지만..누가 알려줘서 깨달았지만..다음의 나는 잘 찾겠지..)
JpaRepository
는 PagingAndSortingRepository
를 상속 받고 있다.
🤔 pagenation...PagingAndSortingRepository...☝️😯..
Pageable 객체를 파라미터로 넣어 findAll()를 호출하면 Page<Member>를 얻을 수 있다!
최종적으로 Repository
에서 findAll()
을 호출하기 위해서는 Pageable 객체를 생성해야 한다.
그러나 Pageable은 인터페이스로 객체를 생성할 수 없고, 구현체의 도움을 받아야 한다!
Pageable에 대해 살펴보면 ofSize()
는 new Pageable
반환하는 메서드로 정의되어 있으며, PageRequest.of(0, pageSize)
을 리턴한다.
즉, PageRequest.of(0, pageSize)
는 Pageable의 객체라는 의미가 된다.
PageRequest 는 AbstractPageRequest를 상속 받은 클래스이고, AbstractPageRequest는 Pageable 인터페이스를 구현한 추상 클래스였다.
PageRequest는 Pageable의 하위 클래스나 마찬가지이므로 PageRequest로 Pageable의 객체를 생성할 수 있다!(다형성!)
🤓☝️
of()
메서드를 통해 PageRequest 객체를 생성할 수 있음을 알 수 있다!
PageRequest의 of()
메서드는 공통적으로 int page, int size
를 파라미터로 받고 있다는 것을 알 수 있다.
그렇다면 이 파라미터의 값을 우리는 어디서 받아와야 할까?
🤓☝️
당연 클라이언트의 요청으로부터 받아와야 한다! 그러면 클라이언트가 요청할 때마다, 페이지수와 페이지 마다 입력될 데이터의 개수를 하나하나 적어줘야 하나?
URI의 구조를 보면 url-path 다음에 붙은 것이 query, 웹 서버에 보내는 추가적인 질문을 옵션으로 보낼 수 있다.
우리가 사용할 int page, int size
는 이 query로 불러와 사용하게 할 것이다.
URI에서 query의 값을 멤버 변수의 값으로 지정해주는 애너테이션.
만약 query에서의 이름과, 변수의 이름이 다를 경우에는 @RequestParam("쿼리 이름")
으로 사용할 수 있다.
🧐 @PathVariable
이름에서 알 수 있듯이 url-path의 값을 지정하는 애너테이션이다.
Controller
는 클라이언트의 요청에서 받은 int page, int size
를 파라미터로 담아 Service
의 findMembers()
메서드를 호출한다.
Service 클래스
에서는 파라미터로 받은 값으로 PageRequest의 of()
메서드를 호출해 Pageable 객체를 생성한다.
Member 객체의 memberId
의 이름을 가진 변수에 따라 정렬하겠다는 의미!
🧐 page는 왜 -1를 해줄까?
배열과 마찬가지로 Page의 index도 0부터 시작하기 때문이다!
이제 생성된 Pageable 객체를 파라미터로 Repository
의 findAll()
메서드를 호출해 Page<Member>를 생성한다.
제네릭 타입의 클래스 객체들을 Page화 해주는 일종의 List.
Repository
에서 Page<Member> 로 찾은 회원 목록 데이터를 Service
의 메서드를 호출했던 Controller
에게 반환한다.
반환한 Page<Member>를 이용해 페이지 정보와, 멤버 정보를 ResponseEntity에 담아 클라이언트에게 응답을 보낸다.
Pagenation 구현 완🤓☝️