Dev./Spring

[Spring] Pageable+Page 사용해 Pagination 적용해보기

limitation01 2025. 11. 18. 17:54

왜 Pagination을 사용해야 할까?

데이터가 많아질수록 한 번에 모든 데이터를 불러오면 성능저하, 네트워크낭비, 응답 지연 문제가 생긴다.

그래서 일정 개수만 잘라서 가져오는 페이지네이션을 사용한다.

Spring Data JPA는 Pageable, Page 기능을 제공해주어 페이지네이션을 쉽게 구현할 수 있게 해준다.

Page<T>

  • 실제 조회된 결과 + 페이지 정보
  • 레포지토리에서 조회하면 페이지 객체 반환
Page<Schedule> pagination = scheduleRepository.findAll(pageable);

단순히 데이터 리스트가 아니라 페이지 정보를 함께 담고 있다.

Page 객체가 제공하는 정보

메서드   의미
getContent() 현재 페이지의 실제 데이터 List
getNumber() 현재 페이지 번호
getTotalPages() 전체 페이지 수
getTotalElements() 전체 데이터 개수
getSize() 페이지 크기(size)
isFirst() 첫 페이지 여부
isLast() 마지막 페이지 여부
hasNext() 다음 페이지 유무
hasPrevious() 이전 페이지 유무

Pageable

  • 페이지 요청 정보를 담는 인터페이스
GET /schedules?page=1&size=10&sort=createdAt,desc

이 요청을 Spring MVC는 자동으로 Pageable로 변환해준다

적용해보기

1. Controller에서 Pageable 받기

스프링은 ?page=0&size=20 같은 쿼리 파라미터를 자동으로 Pageable로 변환해준다

@GetMapping
public ResponseEntity<PageScheduleResponse<GetAllScheduleResponse>> getAllSchedules(
        Pageable pageable
) {
    return ResponseEntity
            .status(HttpStatus.OK)
            .body(scheduleService.findAll(pageable));
}

이런 요청이 가능하다

GET /schedules?page=0&size=10

2. Service 에서 Page 객체 받기

Spring Data JPA로 페이지네이션은 한 줄로 가능하다

Page<Schedule> pagination = scheduleRepository.findAllByOrderByCreatedAtDesc(pageable);

 

3. 엔티티를 응답 DTO로 변환

페이지 내부 데이터는 엔티티이다. API 응답으로 반환하기 위해 DTO로 변환해서 사용해야 한다.

List<GetAllScheduleResponse> responses = pagination.getContent().stream()
        .map(schedule -> new GetAllScheduleResponse(
                schedule,
                commentRepository.countAllByScheduleId(schedule.getId())
        ))
        .toList();
  • 각 일정의 개수(countAllByScheduleId)도 함께 내려주기 위해 추가 쿼리 수행

4. 커스텀 페이징 응답 만들기

페이지네이션에서 프론트엔드가 필요한 데이터가 있다. 나는 다음과 같은 정보만 커스텀 응답 DTO 필드로 넣어주었다.

 

  • 데이터 목록
  • 현재 페이지
  • 전체 페이지
  • 전체 데이터 수
  • 첫 페이지 여부
  • 마지막 페이지 여부
return new PageScheduleResponse<>(
        responses,
        pagination.getNumber(),
        pagination.getTotalPages(),
        pagination.getTotalElements(),
        pagination.isFirst(),
        pagination.isLast()
);

 

요약

  1. 클라이언트는 ?page=0&size=10 같이 요청
  2. Spring이 자동으로 Pageable로 변환
  3. Repository에서 findAll(Pageable) 또는 커스텀 메서드 호출
  4. 결과는 Page<T>로 반환
  5. Page의 content → DTO 변환
  6. 페이지 정보 + DTO 리스트를 묶어 커스텀 응답 생성
  7. Controller에서 응답