
Pageable, PageRequest, Page Spring 에서 개발을 하다보면 한번 쯤 본적있는 코드?
한번 쯤 본적있는 코드가 아니라 제대로 알고 쓰기위해서 글을 적어본다.
Page, Pageable, PageRequest는 Spring Data JPA의 페이징 기능을 위한 핵심 3요소이다.
페이징 요청 정보 인터페이스
클라이언트 에서 어떤 페이지를 보고 싶은지 전달할 때 쓰는 인터페이스이다.
page, size, sort 같은 정보를 담고 있다.
❗️ ex) Pageable pageable = PageRequest.of(0, 10); // 0번째 페이지, 10개
package org.springframework.data.domain;
import java.util.Optional;
import org.springframework.util.Assert;
public interface Pageable {
static Pageable unpaged() {
return unpaged(Sort.unsorted());
}
static Pageable unpaged(Sort sort) {
return Unpaged.sorted(sort);
}
static Pageable ofSize(int pageSize) {
return PageRequest.of(0, pageSize);
}
default boolean isPaged() {
return true;
}
default boolean isUnpaged() {
return !this.isPaged();
}
int getPageNumber();
int getPageSize();
long getOffset();
Sort getSort();
default Sort getSortOr(Sort sort) {
Assert.notNull(sort, "Fallback Sort must not be null");
return this.getSort().isSorted() ? this.getSort() : sort;
}
Pageable next();
Pageable previousOrFirst();
Pageable first();
Pageable withPage(int pageNumber);
boolean hasPrevious();
default Optional<Pageable> toOptional() {
return this.isUnpaged() ? Optional.empty() : Optional.of(this);
}
default Limit toLimit() {
return this.isUnpaged() ? Limit.unlimited() : Limit.of(this.getPageSize());
}
default OffsetScrollPosition toScrollPosition() {
if (this.isUnpaged()) {
throw new IllegalStateException("Cannot create OffsetScrollPosition from an unpaged instance");
} else {
return this.getOffset() > 0L ? ScrollPosition.offset(this.getOffset() - 1L) : ScrollPosition.offset();
}
}
}
주요 함수
int getPageNumber(); - 몇 번째 페이지인지int getPageSize(); - 한 페이지에 몇 개 담을지Sort getSort(); - 정렬 조건Pageable 구현체
Pageable 인터페이스를 구현한 구현체로
페이징 요청을 만들기 위해 항상 사용하는 클래스이다.
❗️ ex) PageRequest pageRequest = PageRequest.of(0, 20, [Sort.by](http://sort.by/)("createdAt").descending());
package org.springframework.data.domain;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
public class PageRequest extends AbstractPageRequest {
private static final long serialVersionUID = -4541509938956089562L;
private final Sort sort;
protected PageRequest(int pageNumber, int pageSize, Sort sort) {
super(pageNumber, pageSize);
Assert.notNull(sort, "Sort must not be null");
this.sort = sort;
}
public static PageRequest of(int pageNumber, int pageSize) {
return of(pageNumber, pageSize, Sort.unsorted());
}
public static PageRequest of(int pageNumber, int pageSize, Sort sort) {
return new PageRequest(pageNumber, pageSize, sort);
}
public static PageRequest of(int pageNumber, int pageSize, Sort.Direction direction, String... properties) {
return of(pageNumber, pageSize, Sort.by(direction, properties));
}
public static PageRequest ofSize(int pageSize) {
return of(0, pageSize);
}
public Sort getSort() {
return this.sort;
}
public PageRequest next() {
return new PageRequest(this.getPageNumber() + 1, this.getPageSize(), this.getSort());
}
public PageRequest previous() {
return this.getPageNumber() == 0 ? this : new PageRequest(this.getPageNumber() - 1, this.getPageSize(), this.getSort());
}
public PageRequest first() {
return new PageRequest(0, this.getPageSize(), this.getSort());
}
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
} else if (!(obj instanceof PageRequest)) {
return false;
} else {
PageRequest that = (PageRequest)obj;
return super.equals(that) && this.sort.equals(that.sort);
}
}
public PageRequest withPage(int pageNumber) {
return new PageRequest(pageNumber, this.getPageSize(), this.getSort());
}
public PageRequest withSort(Sort.Direction direction, String... properties) {
return new PageRequest(this.getPageNumber(), this.getPageSize(), Sort.by(direction, properties));
}
public PageRequest withSort(Sort sort) {
return new PageRequest(this.getPageNumber(), this.getPageSize(), sort);
}
public int hashCode() {
return 31 * super.hashCode() + this.sort.hashCode();
}
public String toString() {
return String.format("Page request [number: %d, size %d, sort: %s]", this.getPageNumber(), this.getPageSize(), this.sort);
}
}
페이징된 결과 객체
Spring Data JPA에서 findAll(Pageable pageable) 같은 메서드로 조회하면 반환되는 결과
내부에 데이터 리스트 + 페이징 메타데이터가 들어 있음
❗️ ex)
Page<Post> postPage = postRepository.findAll(pageRequest);
List<Post> posts = postPage.getContent(); int totalPages = postPage.getTotalPages();
package org.springframework.data.domain;
import java.util.Collections;
import java.util.function.Function;
public interface Page<T> extends Slice<T> {
static <T> Page<T> empty() {
return empty(Pageable.unpaged());
}
static <T> Page<T> empty(Pageable pageable) {
return new PageImpl(Collections.emptyList(), pageable, 0L);
}
int getTotalPages();
long getTotalElements();
<U> Page<U> map(Function<? super T, ? extends U> converter);
}
주요함수
List<T> getContent(); - 실제 데이터 리스트int getTotalPages(); - 전체 페이지 수long getTotalElements(); - 전체 데이터 수int getNumber(); - 현재 페이지 번호boolean hasNext(); - 다음 페이지 존재 여부boolean isFirst(); - 첫 페이지 여부