페이지네이션

Seunghyeon·2025년 4월 15일
0

Spring정리

목록 보기
2/2
post-thumbnail

다른 프로젝트를 하게 되면서 게시판 파트를 맡았고
게시글 리스트를 불러오게 되었다.

1. Pageable이란


pageable은 Spring Data JPA 에서 목록을 불러올 때 쉽게 가져올 수 있도록 객체로 구현해 둔 클래스이다.

특정 게시판의 1) 몇 번째 페이지를 2) 몇 개 만큼 3) 어떤 기준으로 불러올 것인지를 결정할 수 있다.

또한 정렬 기준을 정할 수 있어서 다양한 게시판의 종류에 맞게 사용할 수 있다.
(좋아요 100개 이상의 글, 가장 최신 글 등... )



2. 사용법


1.PageRequest

Pageable pageable = PageRequest.of(페이지번호, 한페이지에몇개);

Pageable pageable = PageRequest.of(페이지번호, 한페이지에몇개, 정렬조건);

Pageable을 사용하기 위해서는 PageRequest 객체를 통해 생성한다.

  • 페이지 번호는 0 부터 시작하고 0이 첫번째 페이지이다.

  • 페이지 당 몇개 는 원하는 개수만큼 불러올 수 있다.

  • 마지막으로 정렬 조건은 Sort라는 객체를 통해 추가할 수 있다.

2. Sort

Sort는 흔히 SQL의 orderby의 역할을 한다.

Sort sort = Sort.by("createdAt");

이렇게 Sort를 만들었다면 정렬 기준은 페이지네이션 할 엔티티의 createdAt 필드의 오름차순으로 정렬하게 된다.

내림차순으로 하려면?

Sort sort = Sort.by(Sort.Direction.DESC, "createdAt");

혹은

Sort sort = Sort.by("createdAt").descending();

Sort sort = Sort.by("createdAt").descending().and(Sort.by("likes").descending());

이렇게 체이닝(Chaining) 방식을 통해 표현할 수 있다.

나는 아래의 방법을 자주 사용할 것 같다. ( 읽기 편하기 때문 )

Repository 에서는?


public interface BoardRepository extends JpaRepository<Board, Long> {

    Page<Board> findAll(Pageable pageable);
}

메서드에 Pageable을 넣어주고 원하는 객체 타입의 Page를 가져가면 된다!

-> 만약 추가적인 쿼리가 필요하다면?


	@Query("SELECT b FROM BOARD b WHERE b.status = :status")
	Page<Board> findAllByStatus(Pageable pageable, @Param("status") String status);

JPQL에 파라미터로 추가해주면 된다

이렇게 만들어진 Page<T> 객체는 어떻게 쓸 수 있을까?

일반적으로는 .getContent()를 통해서 '현재 페이지 목록' List를 가져올 수 있다.

해당 List는 무엇으로 이루어져있나?

Page에 받은 Entity 객체 타입이다. 즉 위 예시에서는 Board를 받아온다.



3. 활용


1. page 객체의 정보

page 객체에서 가져올 수 있는 정보는 다음과 같다.

page.getTotalElements();  => 전체 항목 수
page.getTotalPages();  => 전체 페이지 수
page.getNumber();  => 현재 페이지 번호
page.getSize();  => 한 페이지당 개수

이런 정보들을 넘겨주면 프론트에서 받아서 페이지네이션에 사용할 수 있다.

2. 무한스크롤

무한 스크롤은 프론트에서 요청할 때 다음 페이지에 대한 정보를 주면서 요청하는 것이다.


@Query("""
    SELECT b FROM Board b
    WHERE (:lastLikes IS NULL OR 
          (b.likes < :lastLikes OR (b.likes = :lastLikes AND b.id < :lastId)))
    ORDER BY b.likes DESC, b.id DESC
""")
List<Board> findNextPageByLikes(
    @Param("lastLikes") Integer lastLikes,
    @Param("lastId") Long lastId,
    Pageable pageable
);

좋아요 기준으로 무한스크롤을 한다고 하면 위와 같이 구현하게 된다.

중요한것은 프론트에서 다음 좋아요 개수(lastLikes)로 다음 페이지를 요청할 때,
분명 좋아요 개수가 겹치는 글들이 많을것이다.

이를 제대로 처리해주지 않으면 중복되는 글들이 섞여서 나오겠지?

그렇기 때문에 게시글 id를 받아와서 사용한다.

3. enum 클래스

미리 enum 클래스에 선언해놓고 가져다 쓰는 방식으로 사용할 수 있다.

이렇게 쓰면 매번 Sort를 만드는데 필드명을 직접 적을 필요가 없다. (오타 방지)

자주 쓰는 정렬 방식은 enum 클래스로 정의해두고 사용하면 좋다.


@Getter
@RequiredArgsConstructor
public enum BoardSort {

    // 인기순: 좋아요 내림차순, 동일한 좋아요 수면 최신순
    POPULAR(Sort.by("likes").descending().and(Sort.by("createdAt").descending())),

    // 최신순
    RECENT(Sort.by("createdAt").descending());

    private final Sort sort;
}

아래에서는 컨트롤러 부분인데 여기서 BoardSort가 enum 클래스이기 때문에 자동으로 valueOf() 가 동작해서 매핑한다.

orderby=POPULAR로 요청이 들어오면 orderby=BoardSort.valueOf("RECENT") 가 동작한다는 뜻


@GetMapping("/boards")
public ResponseEntity<List<BoardMetadata>> getBoardList(
    @RequestParam int pgno,
    @RequestParam int count,
    @RequestParam(defaultValue = "RECENT") BoardSort orderby
) {
    List<BoardMetadata> boards = boardService.getBoards(pgno, count, orderby.getSort());
    return ResponseEntity.ok(boards);
}

-끝-

profile
그냥 합니다.

0개의 댓글