📢 장정우님이 지음,
[스프링부트 핵심가이드 : 스프링 부트를 활용한 애플리케이션 개발 실무] 책을 읽고 정리한 글입니다.
애플리케이션에서 자주 사용되는 정렬과 페이징 처리는 앞서 소개한 쿼리 메서드를 작성하는 방법을 기반으로 수행할 수 있다. 물론 기본 쿼리 메서드인 이름을 통한 정렬과 페이징 처리도 가능하지만 다른 방법들도 많이 쓰인다. 이번 장에서는 기본적으로 정렬과 페이징 처리 방법을 알아보겠다.
일반적인 쿼리문에서 정렬을 사용할 때는 ORDER BY 구문을 사용한다. 쿼리 메서드도 정렬 기능에 동일한 키워드가 사용된다. 아래와 같이 작성하면 정렬 기능을 사용할 수 있다.
// Asc : 오름차순, Desc : 내림차순
List<Product> findByNameOrderByNumberAsc(String name);
List<Product> findByNameOrderByNumberDesc(String name);
위와 같이 기본 쿼리 메서드를 작성한 후 OrderBy 키워드를 삽입하고 정렬하고자 하는 칼럼과 오름차순/내림차순을 설정하면 정렬이 수행된다. 2번 줄의 쿼리 메서드를 해석하면 ‘상품정보를 이름으로 겅색한 후 상품 번호로 오름차순 정렬을 수헹’한다는 뜻이다. 오름차순으로 정렬하려면 Asc 키워드를, 내림차순으로 정렬하려면 Desc 키워드를 사용한다.
// And룰 붙이지 않음
List<Product> findByNameOrderByPriceAscStockDesc(String name);
다른 쿼리 메서드들은 조건 구문에서 조건을 여러 개 사용하기 위해 And와 Or 키워드를 사용했다. 하지만 정렬 구문은 And나 Or 키워드를 사용하지 않고 아래와 같이 우선순위를 기준으로 차례대로 작성하면 된다.
List<Product> findByName(String name, Sort sort);
위 코드는 앞서 소개한 정렬 키워드가 들어간 메서드와 거의 동일한 기능을 수행한다. 다만 이 메서드는 이름에 키워드를 넣지 않고 Sort 객체를 활용해 매개변수로 받아들인 정렬 기준을 가지고 쿼리문을 작성하게 된다.
매개변수를 활용한 쿼리 메서드를 사용하면 쿼리 메서드를 정의하는 단계에서 코드가 줄어드는 장점이 있다. 그러나 호출하는 위치에서는 여전히 정렬 기준이 길어져 가독성이 떨어진다. 해당 코드는 정렬 기준을 설정하기 위한 필수적인 구문이기 때문에 코드의 양을 줄이기는 어렵다. 하지만 아래와 같이 Sort 부분을 하나의 메서드로 분리해서 쿼리 메서드를 호출하는 코드를 작성하는 방법도 가능하다.
페이징이란 데이터베이스의 레코드를 개수로 나눠 페이지를 구분하는 것을 의미한다. 예를 들면, 25개의 레코드가 있다면 레코드를 7개씩, 총 4개의 페이지로 구분하고 그중에서 특정 페이지를 가져오는 것이다. 흔히 볼 수 있는 웹 페이지에서 각 페이지를 구분해서 데이터를 제공할 때 그에 맞게 데이터를 요청하는 것이라고 생각하면 된다.
JPA에서는 이 같은 페이징 처리를 위해 Page 와 Pageable을 사용한다. 아래와 같이 페이징 처리가 가능한 쿼리 메서드를 작성할 수 있다.
Page<Product> findByName(String name, Pageable pageable);
위와 같이 리턴 타입으로 Page를 설정하고 매개변수에는 Pageable 타일의 객체를 정의한다. 해당 메서드를 사용하기 위해서는 아래와 같이 호출한다.
Page<Product> productPage = productRepository.findByName("펜", PageRequest.of(0, 2));
위 코드에서는 메서드를 호출할 때 리턴 타입으로 Page 객체를 받아야 하기 때문에 Page로 타입을 선언해서 객체를 리턴받았다. 그리고 Pageable 파라미터를 전달하기 위해 PageRequest 클래스는 사용했다. PageRequest는 Pageable의 구현체이다.
일반적으로 PageRequest는 of 메서드를 통해 PageRequest 객체를 생성한다. of 메서드는 매개변수에 따라 다양한 형태로 오버로딩돼 있는데 다음과 같은 매개변수 조합을 지원한다.
Page객체를 그대로 출력하면 해당 객체의 값을 보여주지 않고 위와 같이 몇 번째 페이지에 해당하는지만 확인할 수 있다. 각 페이지를 구성하는 세부적인 값을 보려면 아래와 같이 작성한다.
Page<Product> productPage = productRepository.findByName("펜", PageRequest.of(0, 2));
System.out.println(productPage.getContent());