Book/스프링부트 핵심가이드

정렬과 페이징 처리 방법과 예시

블로그 주인장 2023. 11. 9.

정렬과 페이징 처리

애플리케이션에서 자주 사용되는 정렬과 페이징 처리는 쿼리 메서드를 작성하는 방법을 기반으로 수행할 수 있다.

기본 쿼리 메서드를 통해서도 가능하다. 기본적인 정렬과 페이징 처리 방법을 알아보겠습니다.


정렬 처리하기


일반적인 쿼리문에서는 정렬을 사용할 때 ORDER BY 구문을 사용한다.

쿼리 메서드도 정렬 기능에 동일한 키워드가 사용된다.

// Asc : 오름차순, Desc : 내림차순
List<Product> findByOrderByNumberAsc(String name);
List<Product> findByOrderByNumberDesc(String name);
  • 기본 쿼리 메서드를 작성한 후에 OrderBy 키워드를 삽입한다.
  • 정렬하고자 하는 컬럼과 오름차순/내림차순을 설정하면 정렬이 수행된다.

 

쿼리 메서드에서 여러 정렬 기준 사용

// And를 붙이지 않는다.
List<Product> findByNameOrderByPriceAscStockDesc(String name);
  1. Price를 기준으로 오름 차순 정렬한다.
  2. 후순위로 stock(재고수량)을 기준으로 내림차순 정렬한다.

 

매개변수를 활용한 쿼리 정렬

// And를 붙이지 않는다.
List<Product> findByName(String name, Sort sort);
  • 해당 메서드는 이름에 키워드를 넣지 않고 Sort 객체를 활용한다.
  • 매개변수로 받아들인 정렬 기준을 가지고 쿼리문을 작성하게 된다.

 

코드 정렬 테스트


Sort 객체 테스트 코드 예시

@SpringBootTest
class ProductRepositoryTest {

    @Autowired
    ProductRepository productRepository;

    @Test
    void sortingAndPagingTest() {
        Product product1 = Product.builder()
                .name("pen")
                .price(1000)
                .stock(100)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();

        Product product2 = Product.builder()
                .name("pen")
                .price(5000)
                .stock(500)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();

        Product product3 = Product.builder()
                .name("pen")
                .price(500)
                .stock(50)
                .createdAt(LocalDateTime.now())
                .updatedAt(LocalDateTime.now())
                .build();

        Product savedProduct1 = this.productRepository.save(product1);
        Product savedProduct2 = this.productRepository.save(product2);
        Product savedProduct3 = this.productRepository.save(product3);
    }
}

 

쿼리 메서드 Sort 객체 전달

productRepository.findByName("pen", Sort.by(Order.asc("price")));
productRepository.findByName("pen", Sort.by(Order.asc("price"), Order.desc("stock")));
  • Sort 클래스는 내부 클래스로 정의되어 있는 Order 객체를 활용하여 정렬 기준을 생성한다.
  • Order 객체에는 asc와 desc 메서드가 포함되어 있어, 오름차순과 내림차순을 지정한다.
  • 여러 정렬 기준을 사용할 경우 콤마(,)를 사용하여 구분한다.

 

쿼리 메서드에서 정렬 부분을 분리

@SpringBootTest
class ProductRepositoryTest {

    @Autowired
    ProductRepository productRepository;

    @Test
    void sortingAndPagingTest() {
        
        //.. 상단 코드 생략..//
              
        System.out.println(productRepository.findByName("pen", getSort()));
    }
    
    private Sort getSort() {
        return Sort.by(
                Order.asc("price"),
                Order.desc("stock")
        );
    }
}

 

페이징 처리


  • 데이터베이스의 로코드를 개수로 나눠 페이지를 구분하는 것을 의미한다.
  • ex) 25개의 레코드가 있다면 레코드를 7개씩, 총 4개의 페이지로 구분하고 그 중에서 특정 페이지를 가져오는 것이다.
  • 흔히 볼 수 있는 웹 페이지에서 각 페이지를 구분해서 데이터를 제공할 때, 그에 맞는 데이터를 요청하는 것이다.
  • JPA에서는 이 같은 페이징 처리를 위해 Page와 Pagable을 사용한다.

 

페이징 처리를 위한 쿼리 메서드 예시

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByName(String name, Pageable pageable);
}
  • 리턴 타입으로 Page를 설정하고, 매개변수에는 Pagable 타입의 객체를 정의한다.
 

 

페이징 쿼리 메서드를 호출하는 방법

Page<Product> productPage = productRepository,findByName("pen", PageRequest.of(0, 2));
  • 리턴 타입을 Page 객체로 받아야하기 때문에 Page<Product>로 타입을 선언하여 객체를 리턴받는다.
  • Pagable 파라미터를 전달하기 위해 PageRequest 클래스를 사용한다.

 

PageRequest 사용을 위한 매개변수 조합

of 메서드 매개변수 설명 비고
of(int page, int size) 페이지 번호(0부터 시작), 페이지당 데이터 개수 데이터를 정렬하지 않는다.
of(int page, int size, Sort) 페이지 번호, 페이지당 데이터 개수, 정렬 sort에 의한 정렬
of(int page, int size, 
Direction, String ··· properties)
페이지 번호, 페이지당 데이터 개수, 정렬 방향, 속성(컬럼) Sort.by(direction, properties)
에 의해 정렬

 

Page 쿼리(Hibernate)

  • 쿼리 로그에는 select 쿼리에 limit 쿼리가 포함되어 있다.
  • 페이지 번호를 0이 아닌 1 이상의 숫자로 설정하면 offset 키워드도 포함되어 레코드 목록을 구분해서 가져오게 된다.
Hibernate:
	select
		product0_.number as number1_0_,
		product0_.created_at as created_2_0_,
		product0_.name as name3_0_,
		product0_.price as price4_0_,
		product0_.stock as stock5_0_,
		product0_.updated_at as updated_6_0_
	from
    	product product0_
	where
		product0_.name=? limit?
Hibernate:
	select
		count(product0_.number) as col_0_0_
	from
		product product0_
	where
		product0_.name=?

 

페이지 객체의 데이터 출력

Page<Product> productPage = productRepository,findByName("pen", PageRequest.of(0, 2));
System.out.println(productPage.getContent());
  • Page 객체를 그대로 출력하면 해당 객체의 값을 보여주지 않는다.
  • 몇 번째 페이지에 해당하는지만 확인할 수 있다.
  • getContent() 메서드를 사용해 출력하면 배열 형태로 값이 출력된다.
반응형

댓글