😊 spring data JPA에서 페이징을 적용하려면 Pageable
파라미터를 사용하여 메서드 시그니처를 변경하면 된다.
Pageable
을 통해 페이징된 결과를 얻을 수 있다. Controller
에서 요청을 처리할 때 Pageable
을 파라미터로 받아서 사용하면 된다.page 개수와 size를 매개변수로 받아 pageRequest 객체를 생성하여 repository로 반환한다.
PageRequest는 Pageable을 구현하며, Sort 객체를 매개변수로 받아 정렬조건을 설정할 수 있다.
Service 계층에서 반환한 Page객체에서 제공하는 페이지 개수, 페이지 당 데이터 개수, 총 데이터 수 등의 정보를 이용해 페이지 정보를 담고 있는 PageInfo 객체를 만들어라. (page는 0부터 시작하기 때문에 page -1)
이후 Page 객체의 getContent와 페이지 정보를 함께 반환
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
/**
* 페이징 관련 통합 Response
*/
public class PageResponse<T> {
private T content;
private PageInfo pageInfo;
}
PageRequest
클래스는 Pageable
인터페이스의 구현체 중 하나
😁 PageRequest
클래스는 생성자로 페이지 번호, 페이지 크기 및 정렬 정보를 생성할 수 있다. 하지만 특이하게도 접근 제어자가 protected
로 선언되어 있기 때문에 new
를 이용할 수 없어 of() 메서드를 이용해야 한다.
❤️ of(int page, int size)
: 페이지 번호와 페이지 크기를 인자로 받아 PageRequest
객체를 생성, 이 때 정렬은 지정되지 않는다.
❤️ of(int page, int size, Sort sort)
: 페이지 번호, 페이지 크기, 정렬 방향 및 정렬 속성을 인자로 받아 PageRequest
객체를 생성
❤️ of(int page, int size, Direction direction, String... properties)
: 페이지 번호, 페이지 크기 및 정렬 관련 정보를 담고 있는 Sort
객체를 인자로 받아 PageRequest
객체를 생성
Pageable pageable = PageRequest.of(0,10)
: 1페이지에 데이터를 10개씩 가져온다.Page<Member> result = memberRepository.findAll(pageable);
: member 테이블의 데이터를 모두 조회. 이 때 pageable
의 페이징 설정 적용spring boot에서는 JPA를 통해 페이징 처리를 쉽게 활용할 수 있다.
page
, pageSize
, sortBy
Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.by(sortBy).descending);
Page<TodoEntity> todoPage = todoRepository.findAll(pageable);
// or
Page<TodoResponse> todoDtoPage = todoRepository.findAll(pageable).map(this::mapToDto);
findAll(pagable); => Page<Entity> -> getContent(); ->List<Entity>
-> mapping(stream) -> List<Dto>
✅ Response DTO를 만들어줘야 하는 이유!(Page정보 외에도 많이 있음)
❤️ Page<Entity>
의 content 를 따로 List<PostResponse>
로 처리하는 것을 잊으면 안된다!!
front단에 보내주는 Dto 필드에 Paging 내용을 넣어줄 것!
totalElements
totalPages
last
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PageResponse {
private List<TodoResponse> content;
private int pageNo;
private int pageSize;
private long totalElements;
private int totalPages;
private boolean last;
}
@Override
public PageResponse searchAllPaging(int pageNo, int pageSize, String sortBy) {
// create Pageable instance
Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.by(sortBy).descending());
Page<TodoEntity> todoPage = todoRepository.findAll(pageable);
// .map()을 더 추가해서 바로 Page<TodoResponse> 값으로 시작할 수 있어!
// Page<TodoResponse> todoDtoPage = todoRepository.findAll(pageable).map(this::mapToDto);
List<TodoEntity> listTodos = todoPage.getContent();
List<TodoResponse> content = listTodos.stream().map(TodoEntity -> mapToDto(TodoEntity)).collect(Collectors.toList());
return PageResponse.builder()
.content(content) // todoDtoPage.getContent()
.pageNo(pageNo)
.pageSize(pageSize)
.totalElements(todoPage.getTotalElements())
.totalPages(todoPage.getTotalPages())
.last(todoPage.isLast())
.build();
}
page 개수와 size(page별 데이터 개수)를 매개변수로 받아 PageRequest
객체를 생성하여 repository로 반환.
PageRequest
는 Pageable을 구현하며, Sort
객체를 매개변수로 받아 정렬조건을 설정할 수도 있다.😊 즉, Controller 단에서 page와 size를 파라미터로 받기
Service 계층에서 반환한 Page 객체에서 제공하는 페이지 개수
, 페이지 당 데이터 개수
, 총 데이터 개수
등의 정보를 이용해 페이지 정보를 담고 있는 pageInfo객체를 만들자.
😊 즉, dto + pageInfo 함께 반환
실무에서는 Page
를 통한 페이징은 잘 하지 않는다.
⚽ 그래서 count 쿼리를 분리 !!! - @Query
어노테이션을 통해 가능
@Query(value = "select m from Member m",
countQuery = "select count(m.username) from Member m")
Page<Member> findMemberAllCountBy(Pageable pageable);
또한 절대로 페이징 처리한 데이터를 그대로 반환해서는 안돼!! 엔티티는 절대 노출하면 안되고 DTO로 변환해서 반환할 것.
Page<Member> page = memberRepository.findByAge(10, pageRequest);
Page<MemberDto> toMap = page.map(member -> new MemberDto(member.getId(), member.getUsername(), "null"));
이런 식으로 DTO로 매핑해서(변환해서) 해줘야함!!