Spring Data JPA를 활용한 데이터 정렬 구현(JPA method & Pageable, Page)

Doyeon·2023년 2월 8일
0
post-thumbnail

Spring Data JPA를 활용한 데이터 정렬 구현

DB에 저장된 게시글을 조회할 때, 필드 값 기준에 따라 정렬을 구현하고자 한다.

현재 조회할 때 반환되는 게시글 response Dto 는 { title, contents, author, createdAt, modifiedAt } 필드 값을 가지고 있다.

클라이언트에서 정렬 기준이 될 필드 값과 정렬 방식(DESC, ASC)을 요청에 담아 보내면, 서버에서는 기준과 방식에 맞게 정렬된 데이터를 반환해야 한다.

두 가지 방식을 사용해서 정렬 기능을 구현할텐데,

첫번째는 Repository에 JPA Query method 기능을 사용하는 것이고,

두번째는 Pagination을 활용하는 것이다.

지금부터 하나씩 구현해보자!


정렬 기준을 담은 JPA Query method 사용

Repository

@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
    List<Board> findAllByOrderByModifiedAtDesc();
    List<Board> findAllByOrderByTitleDesc();
    List<Board> findAllByOrderByAuthorDesc();
}
  • 스프링 데이터 JPA는 쿼리 메서드 기능을 제공한다. 메서드의 이름을 분석해서 JPQL 쿼리를 실행해준다.
  • findAllByOrderByModifiedAtDesc()
    • findAllBy : DB에 들어있는 모든 객체를 찾는다.
    • OrderByModifiedAt : { modifiedAt } 필드 값을 기준으로
    • Desc : 내림차순 방식

Controller

@GetMapping("/api/posts")
		public List<BoardResponseDto> getPosts(@RequestParam(required = false, defaultValue = "modifiedAt", value = "orderby") String criteria) {
		    return boardService.getPosts(criteria);
}
  • Controller 에서는 @RequestParam 정렬 기준을 받아온다.
    • required = false : 해당 query param은 요청시 안 보낼 수도 있다.
    • defaultValue = “modifiedAt” : 안 보낸다면 디폴트 값은 “modifiedAt” 이다.
    • value = "orderby" : query 부분에서 Key 값은 “orderby” 다.

Service

public List<BoardResponseDto> getPostsOrderBy(String criteria) {
    return switch (criteria) {
        case "title" -> boardRepository.findAllByOrderByTitleDesc().stream().map(BoardResponseDto::new).toList();
        case "author" -> boardRepository.findAllByOrderByAuthorDesc().stream().map(BoardResponseDto::new).toList();
        default -> boardRepository.findAllByOrderByModifiedAtDesc().stream().map(BoardResponseDto::new).toList();
    };
}
  • Controller에서 보낸 정렬 기준(criteria)을 보고 알맞은 JPA 메서드를 만들어 선언해준다.
    • “title”인 경우는 title 필드 값 기준으로 내림차순
    • “author”인 경우는 author 필드 값 기준으로 내림차순
    • 그 외의 경우는 모두 ModifiedAt 필드 값 기준으로 내림차순

실행결과

  • orderby=title 이므로, title 필드 값 기준으로 내림차순된 결과를 확인할 수 있다.

JPA 메서드를 Repository에서 선언만 해주면, 원하는 조건으로 정렬된 데이터를 얻을 수 있다.

하지만, 정렬 기준마다, 정렬 방식마다, 하나씩 모두 메서드를 선언해주어야 한다.

모든 정렬 기준을 생각하면 하나씩 만들기 번거로워서 우선 title, author 일 경우만 내림차순으로 생각하고 구현했다.

이제 조금 더 편하게 정렬된 데이터를 얻을 수 있는 Pagination 기능을 살펴보자!


Pagination 기능(Pageable, Page)

Pagination

  • 게시글을 보여줄 때 페이지별로 나누어 글을 보여준다.
  • 한 페이지에 나타낼 게시글을 정하려면 정렬 기준이 필요하다.
  • 요청한 페이지의 숫자와 총 페이지의 수, 정렬 방식 등 요청에 따른 정보를 보여준다.

Pageable

  • Pagination 기능을 편리하게 사용할 수 있도록 JPA는 Pageable이라는 객체를 제공한다.
  • Pageable 객체는 PageRequest.of() 메서드로 생성이 가능하다.
    • page(조회하고자 하는 페이지 번호), size(페이지 당 보여질 글의 수)를 파라미터로 받으며, 오버로딩을 통해 sort(정렬 기준 컬럼 정보, Sort 객체) 파라미터를 함께 사용할 수도 있다.

Controller

@GetMapping("/api/posts")
		public Page<BoardResponseDto> getPostsPage(@RequestParam(required = false, defaultValue = "0", value = "page") int pageNo,
		                                           @RequestParam(required = false, defaultValue = "modifiedAt", value = "orderby") String criteria,
		                                           @RequestParam(required = false, defaultValue = "DESC", value = "sort") String sort) {
		    return boardService.getPostsPage(pageNo, criteria, sort);
}
  • 클라이언트로부터 Pageable 객체를 만들기 위해 필요한 페이지 번호, 정렬 기준, 정렬 방식을 받는다.
  • 쿼리스트링에서 key를 담당하는 page, orderby, sort의 값이 없을 경우 default 값을 각각 정해주었다.

Service

public Page<BoardResponseDto> getPostsPage(int pageNo, String criteria, String sort) {
    Pageable pageable = (sort.equals("ASC")) ? 
												PageRequest.of(pageNo, 5, Sort.by(Sort.Direction.ASC, criteria)) 
											: PageRequest.of(pageNo, 5, Sort.by(Sort.Direction.DESC, criteria));

    return boardRepository.findAll(pageable).map(BoardResponseDto::new);
}
  • PageRequest.of() 를 사용하여 pageable 객체를 생성해주고 findAll에 pageable을 넣으면, DB에서 찾은 값들이 설정했던 pagination 기능에 맞게 들어온다.
    • page : 현재 페이지 번호 (pageNo)
    • size : 5로 설정
    • sort : 정렬기준(criteria)으로 오름차순, 내림차순

Repository

@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
    Page<Board> findAll(Pageable pageable);
}
  • 이미 정렬된 pageable 객체를 파라미터로 사용하면 findAll 로 전체 데이터를 가져왔을 때 정렬된 데이터를 얻을 수 있다.
  • 정렬 기준, 정렬 방식별로 여러 개의 메서드를 선언하지 않아도 된다.

실행결과

  • page=1 : 1번 페이지(0번부터 시작한다.)
  • orderby=author : author 필드가 정렬 기준이다.
  • sort=ASC : 오름차순으로 정렬한다.
profile
🔥

0개의 댓글