리뷰 글을 특정 조건으로 뽑아서 정렬 기준을 선택하여 조회하는 기능을 구현하고자 한다.
전체 리뷰글을 조회하거나, 내가 좋아요를 누른 리뷰글만 조회하거나, 내가 쓴 리뷰글만 조회하거나, 원하는 카테고리의 글만 조회하고 싶다면? → Spring Data JPA를 사용하여 구현할 수 있다!
게시글을 조회할 때 정렬 기준(최신순, 좋아요순)과 정렬방식(오름차순, 내림차순)을 선택하여 조회를 하고 싶다면? → 페이지네이션을 사용하면 쉽게 구현할 수 있다!
지금부터 Pageable 인터페이스를 사용하여 Spring Data JPA에서 페이지네이션을 구현해보자!
Pageable
인터페이스를 제공한다.getPageNumber()
: 현재 페이지 번호를 반환(0부터 시작)getPageSize()
: 한 페이지당 최대 항목 수를 반환getOffset()
: 현재 페이지의 시작 위치를 반환getSort()
: 정렬 정보를 반환next()
: 다음 페이지 정보를 반환previous()
: 이전 페이지 정보를 반환Pageable
을 이용해서 페이지 번호, 페이지당 항목 수, 필요에 따라 정렬 정보를 추가로 지정할 수 있다.Pageable
로 지정한 정보들을 가지고 Page
객체를 반환할 수 있고, Page
객체는 조회된 데이터와 페이지 정보를 함께 갖게 된다.Pageable
구현체 중 하나로, 페이지 정보를 생성하는 클래스이다.Pageable
인터페이스를 구현한다.page
: 조회할 페이지 번호(0부터 시작)size
: 한 페이지당 최대 항목 수sort
: 정렬 정보(생략 가능)direction
: 정렬 방향(ASC, DESC)properties
: 정렬 대상 속성명PageRequest
객체를 생성하고 JpaRepository 메서드 파라미터로 전달하면, Page
객체를 반환하므로, Pagination을 구현할 수 있다.// 생성자
PageRequest(int page, int size)
PageRequest(int page, int size, Sort sort)
PageRequest(int page, int size, Sort.Direction direction, String... properties)
// 객체 생성
PageRequest pageRequest = PageRequest.of(0, 10, Sort.by("id").ascending());
/api/reviews?pageNo=1&criteria=likeCount
@GetMapping("/api/reviews")
public SuccessResponseDto<List<ReviewResponseDto>> getReviews(@RequestParam(required = false, defaultValue = "0", value = "page") int pageNo,
@RequestParam(required = false, defaultValue = "createdAt", value = "criteria") String criteria) {
return reviewService.getReviews(pageNo, criteria);
}
Pageable
객체를 만들어서 reviewRepository.findAll
메서드 파라미터로 전달한다.page
객체로 리턴 받아서 ReviewResponseDto
로 변환한 후, getContent()
로 List만 추출해서 리턴한다.//전체 게시글 조회
@Transactional(readOnly = true)
public SuccessResponseDto<List<ReviewResponseDto>> getReviews(int pageNo, String criteria) {
Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.by(Sort.Direction.DESC, criteria));
Page<ReviewResponseDto> page = reviewRepository.findAll(pageable).map(ReviewResponseDto::from);
return ResponseUtils.ok(page.getContent());
}
findAll
전체 데이터를 조회한 후, page로 만든다.public interface ReviewRepository extends JpaRepository<Review, Long> {
Page<Review> findAll(Pageable pageable);
}
api/myreviews?pageNo=1&criteria=createdAt
@AuthenticationPrincipal UserDetailsImpl userDetail
가 파라미터로 필요하다.@GetMapping("/api/myreviews")
public SuccessResponseDto<List<ReviewResponseDto>> getMyReviews(@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestParam(required = false, defaultValue = "0", value = "page") int pageNo,
@RequestParam(required = false, defaultValue = "createdAt", value = "criteria") String criteria) {
return reviewService.getMyReviews(pageNo, criteria, userDetails.getUser());
}
Pageable
객체를 만들어서 reviewRepository.findAllByUser
메서드 파라미터로 전달한다.page
객체로 리턴 받아서 ReviewResponseDto
로 변환한 후, getContent()
로 List만 추출해서 리턴한다.@Transactional(readOnly = true)
public SuccessResponseDto<List<ReviewResponseDto>> getMyReviews(int pageNo, String criteria, User user) {
Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.by(Sort.Direction.DESC, criteria));
Page<ReviewResponseDto> page = reviewRepository.findAllByUser(user, pageable).map(ReviewResponseDto::from);
return ResponseUtils.ok(page.getContent());
}
findAllByUser
: Review
의 User
가 파라미터와 일치하는 데이터를 찾는다.Pageable
을 같이 넣어주면 Page
객체로 리턴할 수 있다.public interface ReviewRepository extends JpaRepository<Review, Long> {
Page<Review> findAllByUser(User user, Pageable pageable);
}
api/reviews/likes?pageNo=1&criteria=likeCount
@AuthenticationPrincipal UserDetailsImpl userDetail
가 파라미터로 필요하다.@GetMapping("/api/reviews/likes")
public SuccessResponseDto<List<ReviewResponseDto>> getMyLikeReviews(@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestParam(required = false, defaultValue = "0", value = "page") int pageNo,
@RequestParam(required = false, defaultValue = "createdAt", value = "criteria") String criteria) {
return reviewService.getMyLikeReviews(pageNo, criteria, userDetails.getUser());
}
Pageable
객체를 만들어서 reviewRepository.findAllByLikeReviewListUser
메서드 파라미터로 전달한다.page
객체로 리턴 받아서 ReviewResponseDto
로 변환한 후, getContent()
로 List만 추출해서 리턴한다.@Transactional(readOnly = true)
public SuccessResponseDto<List<ReviewResponseDto>> getMyLikeReviews(int pageNo, String criteria, User user) {
Pageable pageable = PageRequest.of(pageNo, PAGE_SIZE, Sort.by(Sort.Direction.DESC, criteria));
Page<ReviewResponseDto> page = reviewRepository.findAllByLikeReviewListUser(user, pageable).map(ReviewResponseDto::from);
return ResponseUtils.ok(page.getContent());
}
findAllByLikeReviewListUser
: Review
의 LikeReviewList
안에 있는 User
와 일치하는 데이터를 찾는다.Pageable
을 같이 넣어주면 Page
객체로 리턴할 수 있다.public interface ReviewRepository extends JpaRepository<Review, Long> {
Page<Review> findAllByLikeReviewListUser(User user, Pageable pageable);
}
Spring Data JPA 의 Query Method를 통해서 원하는 조건의 데이터를 조회하고 페이지로 보여줄 수 있도록 Page 객체를 만들어주는 것을 확인해보았다. 조건들이 더 복잡해지면 쿼리를 직접 작성해야겠지만, 메서드 하나로 원하는 조건의 데이터를 찾을 수 있다는 것이 참 편하고 신기하다. 다음엔 직접 쿼리를 써서 리턴하는 것을 시도해봐야겠다!