반응형

오늘은 Spring Boot에서 Pagination(페이징)과 Sorting(정렬)을 구현하는 방법을 학습합니다. 대규모 데이터 처리 시 페이징과 정렬은 효율적인 데이터 조회를 위해 꼭 필요한 기능입니다.


1. Pagination과 Sorting의 필요성

  • Pagination(페이징)
    데이터를 페이지 단위로 나누어 클라이언트에 반환하여 서버 부하를 줄이고 사용자의 편의성을 제공합니다.
  • Sorting(정렬)
    데이터를 특정 필드 기준으로 정렬하여 원하는 순서대로 결과를 반환합니다.

2. Spring Data JPA에서 제공하는 페이징과 정렬

Spring Data JPA는 Pageable과 Sort를 활용해 페이징과 정렬을 간단히 구현할 수 있습니다.


3. Pagination과 Sorting 설정하기

(1) 데이터베이스 엔터티 생성

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Double price;

    // Getter, Setter
}

(2) 레포지토리 인터페이스 작성

Spring Data JPA의 JpaRepository를 상속받아 페이징과 정렬 기능을 제공합니다.

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
    Page<Product> findByNameContaining(String name, Pageable pageable);
}

(3) 서비스 로직 작성

Pageable 객체를 사용하여 페이징과 정렬을 구현합니다.

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class ProductService {

    private final ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public Page<Product> getProducts(String name, Pageable pageable) {
        return productRepository.findByNameContaining(name, pageable);
    }
}

(4) 컨트롤러 작성

클라이언트로부터 페이지 번호, 크기, 정렬 조건을 받아 데이터를 반환합니다.

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/products")
    public Page<Product> getProducts(
        @RequestParam(defaultValue = "") String name,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size,
        @RequestParam(defaultValue = "id") String sortBy,
        @RequestParam(defaultValue = "asc") String direction
    ) {
        Sort sort = direction.equalsIgnoreCase("asc") ? Sort.by(sortBy).ascending() : Sort.by(sortBy).descending();
        Pageable pageable = PageRequest.of(page, size, sort);
        return productService.getProducts(name, pageable);
    }
}

4. 페이징 응답 데이터 구조

Spring Data JPA는 Page 객체를 통해 아래와 같은 구조로 데이터를 반환합니다.

{
  "content": [
    {
      "id": 1,
      "name": "Product A",
      "price": 100.0
    },
    {
      "id": 2,
      "name": "Product B",
      "price": 200.0
    }
  ],
  "pageable": {
    "sort": {
      "sorted": true,
      "unsorted": false,
      "empty": false
    },
    "pageNumber": 0,
    "pageSize": 10,
    "offset": 0,
    "paged": true,
    "unpaged": false
  },
  "totalPages": 5,
  "totalElements": 50,
  "last": false,
  "first": true,
  "sort": {
    "sorted": true,
    "unsorted": false,
    "empty": false
  },
  "size": 10,
  "number": 0,
  "numberOfElements": 10,
  "empty": false
}

5. Postman으로 테스트

  1. 기본 요청: GET /products?page=0&size=5&sortBy=price&direction=asc
    • 결과: 가격 순으로 오름차순 정렬된 데이터 반환.
  2. 검색 조건 추가: GET /products?name=Product&page=1&size=5&sortBy=name&direction=desc
    • 결과: 이름에 "Product"가 포함된 데이터 반환.

6. 주요 사항 및 주의점

  1. 기본 정렬 설정
    PageRequest.of에서 기본 정렬 설정을 잘못하면 예상치 못한 결과가 나올 수 있으니 유의합니다.
  2. Pageable 객체 재사용
    컨트롤러에서 Pageable 객체를 서비스로 넘길 때 매번 새로 생성해 성능에 유의합니다.
  3. 무한 스크롤 대응
    페이지 크기를 작게 설정하고 클라이언트에서 무한 스크롤 방식으로 데이터를 불러오도록 설계하면 사용자 경험이 향상됩니다.
반응형

+ Recent posts