많은 글을 여러 페이지로 나누어 볼 수 있는
페이지 처리
Spring Data JPA에서는 페이징 처리가 존재하는데,
페이징이 무엇인지, 어떻게 사용할 수 있는지 살펴보고자 한다.
페이징(Paging)이란?
검색된 결과 혹은 대용량의 데이터를 페이지 단위로 데이터를 분할하여 가져오는 기능을 말한다.
그럼 페이징 처리를 하기 위해 기본적으로 알아야 하는 것,
알면 좋은 것에 대해 이야기 해보고 사용법을 알아보고자 한다.
Pageable이란?
Spring Data에서 페이징 및 정렬을 처리하기 위한 인터페이스로,
데이터를 한 페이지 단위로 가져오고 정렬하는 작업에 필요한 정보들(페이지 번호, 페이지 크기, 정렬 방법)을 담고 있는데,
Pageable 객체를 사용해 Repository에 페이징과 정렬 조건을 전달하고, Page/Slice 객체를 반환받아 사용한다.
Page랑 Slice는 무엇인가?
1. Slice란?
Slice는 다음 페이지만 확인이 가능한 인터페이스로 전체 페이지 개수를 알지 못하며,
내부적으로 limit + 1을 수행하여 페이지 당 보여줄 데이터 수를 9로 지정했다면 페이지 당 가져오는 데이터가 10개가 되는 객체이다.
전체 페이지 수를 모르기 때문에 성능 낭비가 발생하지는 않는다나는 장점이 존재한다.
예) 모바일 더보기 기능, 무한 스크롤
2. Page란?
Page는 Slice를 상속받은 인터페이스로 Slice의 기본적인 기능을 가지며,
그 이외의 추가적인 기능(전체 페이지 및 데이터 수)를 가진다.
예) 게시판
그럼 둘의 차이는 무엇일까?
위의 설명을 보면 알겠지만, 결국은 전체 페이지와 데이터의 수를 알고 있는지 아닌지의 차이이다.
결국, Page가 전체 페이지 및 데이터 수를 계산하기 위한 쿼리를 추가로 호출한다는 것을 의미하게 된다.
어떤식으로 사용해야 할까?
1. PageRequest 객체 생성
pageRequest.of() 메서드를 사용해 페이지 번호/페이지크기/(정렬방법)을 전달하여 PageRequest 객체를 생성한다.
Pageable pageRequest = PageRequest.of(0, 10, Sort.by("id").descendging);
* 페이지 순서는 0부터 시작한다.
* 정렬은 Spring Data JPA에서 Sort를 사용하여 수행한다.
2. Repository에 Pageable(pageRequest 객체)를 전달
Pageable 객체를 Repository 메서드의 매개변수로 전달하여 페이징 처리를 적용한다.
매개변수로 여러 개의 인자를 담을 수 있는데, page만 담을 경우 Repository에서 조회하는 모든 데이터에 대한 페이지 처리를 하며,
조건을 같이 인자로 전달할 경우 해당 인자에 해당하는 것만 데이터를 가져와 페이지 처리를 하게된다.
// 계좌주가 "홍길동"인 모든 계좌 조회를 하여 페이징 처리
Page<Account> account = accountRepository.findByName("홍길동", pageRequest);
// 타입과 키워드를 이용한 게시글 검색
Page<Board> findByTypeAndContentContaining(String type, String keyword, pageRequest);
3. 결과 사용
Repository에서 반환한 Page 객체를 사용해 결과 정보와 페이징 데이터를 다룰 수 있는데,
엔티티를 직접 조회하지 않고 DTO로 변환하여 사용해야 안전하다.
Page<AccountDto> accountDtos = page.map(m->new AccountDto(m.getId(), m.getName());
int totalPage = accountDtos.getTotalPages(); // 총 페이지 수
int pageNumber = accountDtos.getNumber(); // 현재 페이지 번호
List<AccountDto> accountList = accountDtos.getContent(); // 조회 데이터 리스트로 얻기
* 페이지를 리스트로 변경하는 방법은 위의 처럼 Page에서 제공하는 메서드(.getContent)를 사용하면 되지만,
리스트를 페이지로 변경하는 방법은 조금 복잡한데, 방법은 아래와 같다. (조금이 아니라 많이 복잡하다,,,)
(예시는 타입과 키워드를 이용한 검색이다)
List<Post> posts = postRepository.findByTypeAndContentContaining("제목", "Spring");
Pageable pageable = PageRequest.of(0, 10);
int start = (int) pageable.getOffset();
int end = (start + pageable.getPageSize()) > posts.size() ? posts.size() : (start + pageable.getPageSize());
Page<Post> postPage = new PageImpl<>(posts.subList(start, end), pageable, posts.size());
기타 메서드
// slice, page 메서드
int getNumber(); //현재 페이지
int getSize(); //페이지 크기
int getNumberOfElements(); //현재 페이지에 나올 데이터 수
List<T> getContent(); //조회된 데이터
boolean hasContent(); //조회된 데이터 존재 여부
Sort getSort(); //정렬 정보
boolean isFirst(); //현재 페이지가 첫 페이지 인지 여부
boolean isLast(); //현재 페이지가 마지막 페이지 인지 여부
boolean hasNext(); //다음 페이지 여부
boolean hasPrevious(); //이전 페이지 여부
Pageable getPageable(); //페이지 요청 정보
Pageable nextPageable(); //다음 페이지 객체
Pageable previousPageable();//이전 페이지 객체
<U> Slice<U> map(Function<? super T, ? extends U> converter); //변환기
// Page 메서드
int getTotalPages(); //전체 페이지 수
long getTotalElements(); //전체 데이터 수
<U> Page<U> map(Function<? super T, ? extends U> converter); //변환기
Spring Data JPA에서는 Pageable을 이용해 좀 더 편하게 페이지 처리가 가능한 것을 알 수 있었다.
필요에 따라 페이징 처리를 하고,
다양한 메서드을 이용하여 원하는 정보를 얻을 수 있을 것이다!
'공부 자료 > Spring' 카테고리의 다른 글
[Spring] @AllArgsConstructor, @NoArgsConstructor를 지양하자? (0) | 2023.11.21 |
---|---|
[Spring] @CreatedDate&@LastModifiedDate vs @CreationTimeStamp&@UpdateTimeStamp, 둘은 뭐가 다를까? (1) | 2023.11.21 |
[Spring] Getter/Setter를 지양하자? (1) | 2023.11.21 |
[Spring] CORS란? (CORS에 대해 알고 설정하기) (2) | 2023.11.20 |
[Spring Boot] ResponseEntity란? (0) | 2023.11.20 |