오늘은 Spring에서 페이징(Paging) 처리를 하는 방법에 대해 알아보려 한다.
List 목록을 반환할 때 페이징 처리가 자주 사용되기 때문에 이 참에 알아두는 것이 좋을 것 같았다.
Paging
페이징은
속도는 빠르게,부하는 적게하기 위해 지금 당장 필요한 데이터만 가져올 수 있도록 데이터를 분리하는 작업이다.
ex) 게시판 목록, 댓글 목록..
Spring에서는 데이터를 페이지 단위로 처리하기 위해
Pageable인터페이스와Page인터페이스를 제공한다.
- Pageable : 요청된 페이지와 페이지당 데이터 수 등을 포함하는 객체
- Page : 요청된 페이지에 해당하는 데이터를 담고 있는 객체
Pageable 인터페이스는 다음과 같다.
public interface Pageable {
int getPageNumber();
int getPageSize();
long getOffset();
Sort getSort();
Pageable next();
Pageable previousOrFirst();
Pageable first();
boolean hasPrevious();
default Sort getSortOr(Sort sort) {
return getSort().isSorted() ? getSort() : sort;
}
}
Pageable 인터페이스를 사용하여 데이터를 조회하면 Page 객체가 반환된다. Page 객체는 다음과 같이 선언된다.
public interface Page<T> extends Slice<T> {
int getTotalPages();
long getTotalElements();
<U> Page<U> map(Function<? super T, ? extends U> converter);
boolean hasPrevious();
boolean isFirst();
boolean isLast();
boolean hasNext();
Pageable nextPageable();
Pageable previousPageable();
Iterator<T> iterator();
List<T> getContent();
boolean hasContent();
Sort getSort();
}
getTotalPages() : 전체 페이지 수getTotalElements() : 전체 데이터 수getContent() : 요청된 페이지의 데이터를 리스트로 반환Pageable과 Page 에 대해 알았으니, 바로 구현으로 넘어가보자.
예시 Controller를 하나 생성해보자.
// Controller
@GetMapping("/list")
public ResponseEntity<?> getLists(
@PageableDefault(size=10) Pageable pageable
) {
Page<Dto> result = testService.getLists(pageable);
return ResponseEntity.ok(result);
}
Spring Data에서 제공하는 애노테이션 중 하나로, Pageable 객체의 디폴트 값을 설정할 때 사용된다.
Pageable 인터페이스를 구현한 객체를 생성하는 과정에서, 디폴트 값으로 사용되는 요청 파라미터를 지정한다.
(size = 10) : 페이지당 최대 10개의 데이터를 반환하도록다음과 같은 파라미터를 가질 수 있다.
size: 페이지당 결과 수의 디폴트 값. 기본값은 20page: 요청한 페이지 번호의 디폴트 값. 기본값은 0sort: 정렬 기준의 디폴트 값.
@PageableDefault를 사용하면,Pageable 객체의 기본 값을 쉽게 설정할 수 있어 편리합니다.
다음으로 Service 메서드와 Repository를 구현해보자.
// Service
public Page<Dto> getLists(Pageable pageable) {
return testRepository.findAll(pageable).map(Dto::new);
}
// testRepository (JPA)
Page<User> findAll(Pageable pageable);
그리고 요청을 보낼 때 파라미터와 함께 보내면 된다.
/list?page= &size= &sort=
위에선 JPA 메서드 파라미터에 Pageable을 던지고 결과 목록을 Page로 감싸서 반환받은게 끝이었다.
하지만 만약 Service 로직 내에서 가공된 List를 Paging 하고 싶다면?
PageImpl을 사용하자.
PageImpl
Spring Data JPA에서Page 인터페이스의 구현 클래스중 하나이다. 생성자를 통해List 객체,Pageable 객체,전체 데이터의 총 개수를 받아 Page 객체를 생성한다.
즉 PageImpl(List + Pageable) -> Page 라는 것이다.
한번 사용해보자.
Controller는 그대로 사용하고, Service 로직만 수정해보자.
// Service
public Page<Dto> getLists(Pageable pageable) {
List<Dto> result = new ArrayList<>();
... // result에 값 넣는 로직
int start = (int) pageable.getOffset();
int end = Math.min((start + pageable.getPageSize()), result.size());
return new PageImpl<>(result.subList(start, end), pageable, result.size());
}
new PageImpl<List, Pageable, 데이터 총 개수>(); => Page 객체로 반환이제부터 List를 반환할 때 성능 향상을 위해 Page로 감싸서 반환하자.