221110 Pageable 사용해서 페이지네이션 구현하기

오늘은 게시판에서 게시글이 많을 때 게시판의 가독성적인 부분이나 정리된 화면을 위한 페이지네이션 기능을 구현했다. 

 

페이지네이션(Pagination)이란?

게시판에서 모든 게시글을 한 화면에 모두 보여준 게 아니라 페이지를 나눠서 제공하는 것을 의미한다. 정렬 방식과 페이지의 크기, 그리고 몇 번째 페이지인지의 요청에 따라 정보를 전달해주는 것이 Pagination이다.

 

구현 목표 화면

네이버 카페

한 화면에 게시글은 총 10개만 출력이 되고 넘어갈 시 다음 페이지 버튼이 생성된다.

한 화면에 보여주는 페이지 버튼은 총 10개(게시글 100개) 게시글이 100개가 넘어갈 시 다음 페이지(11페이지)로 이동할 수 있는 "다음"버튼이 생성된다. 만약 게시글이 100개가 존재하지 않는다면 다음 버튼은 생성되지 않는다.

11페이지에서는 이전 페이지(1페이지)로 이동할 수 있는 "이전"버튼이 생성된다.


위의 내용이 총 요구사항이다.
이전에 과제를 진행하면서 페이지네이션을 구현했던 적이 있었지만 다음 페이지 버튼과 이전 페이지 버튼(예를 들어 1페이지에서 다음 페이지 버튼을 누르면 11페이지로 가는 버튼)을 구현하지 못했었는데 이번에는 그 기능까지 구현하는 것을 목표로 진행했다.

 

Pageable

JPA에서 지원하는 Pageable객체를 이용해서 구현해봤다.



pagination을 할 Controller에서 위와 같은 방식으로 Pageable 설정하면 /posts로 요청할 때 page를 같이 넘겨주면 pageable객체를 자동으로 만들어진다. 

@PageableDefault 어노테이션을 Pageable앞에 붙여주면 정렬 방식, 페이지 크기 등 설정을 바꿔줄 수 있다. 붙여주지 않고 사용하면 기본값을 설정된 것을 사용한다.

 

@PageableDefault 내부를 보면서 기본 설정이 어떻게 되어있는지 한번 살펴보자.

size : 한 페이지에 표시할 게시글(데이터) 개수는 10이 기본값이다.

page : 현재 페이지는 0부터 시작된다.

sort : 정렬은 기본적으로 설정되어 있다.

direction : 오름차순 정렬 방식이 기본이다.

우선 테스트를 위해 설정값을 id기준으로 오름차순 정렬하고 한 페이지에 2개의 게시글만 노출되도록 설정해주었다.

 

PostService에 pageable객체를 파라미터로 넘겨주고 서비스는 다시 JpaRepository의 상속을 받고 있는 PostRepository에 정의된 메서드인 findAll로 게시글들을 모두 찾아온다.

여기서 findAll에 Pageable객체를 넘겨주기 때문에 아래와 같이 PostRepository에서 findAll메서드를 구현해줘야 한다.

public interface PostRepository extends JpaRepository<Post, Long> {
    Page<Post> findAll(Pageable pageable);
}

 

요구사항에 충족하기 위해 필요한 정보들은 시작 페이지 번호, 마지막 페이지 번호, 전체 게시글(데이터) 수, 현재 페이지 번호가 필요했다.

여기서 pageable객체로 받아올 수 있는 정보는 현재 페이지 번호와, 전체 게시글 수를 알 수 있었다.

시작 페이지 번호와 마지막 페이지 번호는 알고 있는 현재 페이지 번호와 전체 게시글 수로 구할 수 있다.

 

마지막 페이지 구하는 로직

네이버 카페

여기서 말하는 마지막 페이지는 위 화면에서 보이는 마지막 페이지(10페이지)를 말한다

Math.ceil(현재 페이지 번호 / 10.0) * 10

Math.ceil() 메서드를 이용해서 현재 페이지 번호를 10으로 나누고 올림 해서 10을 곱하면 현재 화면에서 보이는 마지막 페이지 수를 구할 수 있다.

예를 들어 현재 페이지가 14페이지라고 가정하자 14페이지 화면에서 보이는 마지막 페이지 번호는 20페이지 일 것이다. 

1. 14 / 10 = 1.4

2. 1.4 올림 -> 2

3. 2 * 10 = 20

마지막 페이지인 20페이지가 구해진다.

 

시작 페이지 구하는 로직

시작 페이지도 마지막 페이지와 같이 화면에서 보이는 시작페이지를 의미한다 (1, 11, 21 등등)

시작 페이지 = 마지막 페이지 번호 - 9;

시작 페이지는 마지막 페이지 번호를 알고 있으면 간단히 구할 수 있다.

마지막 페이지에서 9를 빼면 시작페이지가 나온다.

아까 14페이지 일 때 마지막 페이지가 20이었는데 20에서 9를 빼면 11이 나와 11이 시작페이지인 것을 알 수 있다.

 

 

이제 리액트에서 게시글을 확인할 때 확인하고 싶은 페이지의 번호를 param으로 같이 전달해주면 해당하는 페이지의 게시글만 화면에 출력되는 것을 확인할 수 있다. 

아까 size를 2로 설정해주었기 때문에 화면에 2개의 게시글만 보이는 것을 확인할 수 있고 게시글 데이터가 총 21개가 있기 때문에 11페이지까지 생겨서 다음 버튼이 생긴 것을 확인할 수 있다.

 

다음 페이지를 눌러서 11페이지에 가보면 마지막 게시글이기 때문에 12페이지 버튼과 다음 페이지 버튼이 존재하지 않고 이전 페이지로 갈 수 있는 버튼이 생긴 것을 확인할 수 있다.

 

기존에 했던 방식이 아닌 새로운 방식으로 페이지네이션을 구현했더니 원래 페이지네이션 기능 구현에 계획했던 시간보다 더 사용하게 되었다. 그리고 게시판의 페이지네이션뿐만 아니라 댓글창에서도 페이지네이션 기능을 구현해줘야 해서 추가적인 작업이 필요해 너무 오래 걸리지 않을까 걱정했었는데 사실 이미 했던걸 또 하는 단순 반복 작업이라 오래 걸리지 않고 구현할 수 있었다.