[Toy Project] JPA Pageable를 사용한 pagination 처리

최지나·2023년 11월 18일
2

목록 페이지를 구현할 때 목록에 속한 요소의 개수가 너무 많거나, 이력 관련 페이지인 경우 모든 요소들을 한 번에 보여주지 않고 페이지를 나눠서 제공한다. JPA에서는 한 페이지 당 표출할 데이터의 크기, 조회하고 싶은 페이지가 몇 페이지인지, 정렬 방식등을 받아 쉽게 원하는 페이지를 표출하게 할 수 있도록 Pagable 객체를 사용한다

토이 프로젝트 진행 중, 아래과 같은 화면에서 전체 제품 목록을 조회할 때, Pagable 객체를 사용하여 Pagination을 적용해 보았다
가방 너무 귀엽다👛👝


코드

  • ProductController.java
  @Operation(summary = "Get All Product List")
  @ApiResponse(
    content = @Content(schema = @Schema(implementation = Page.class))
  )
  @GetMapping
  public ResponseEntity<ProductRes> getProductList(
    @PageableDefault(
      size = 10,
      page = 0,
      sort = "productCode",
      direction = Sort.Direction.ASC
    ) Pageable pageable
  ) {
    return ResponseEntity
      .status(HttpStatus.OK)
      .body(productService.getProducts(pageable));
  }

@PageableDefault
API 요청시 Pageable 객체에 대한 파라미터를 넘겨주지 않더라도 자동으로 기본값을 가진 Pagable 타입 파라미터를 생성

  • @PageableDefault 없이 API 요청 시
{
  "page": 0,
  "size": 1,
  "sort": [
    "productCode"
  ]
}

위와 같은 객체를 보내야 하지만, @PageableDefault 덕분에{}만 input으로 보내도, default 설정이 반영되게 할 수 있다

  • ProductRes.java
@Getter
@Setter
public class ProductRes extends CommonRes {

  private List<Product> content;
  private SimplePageInfo pageable;

  @Getter
  @Setter
  public static class SimplePageInfo {

    private boolean last;
    private int page;
    private int size;
    private int totalPages;
    private long totalElements;
  }

  public ProductRes(
    int status,
    String message,
    List<Product> content,
    SimplePageInfo pageable
  ) {
    super(status, message);
    this.content = content;
    this.pageable = pageable;
  }

SimplePageInfo를 사용하지 않고, Page<Product> 이런 식으로 Page 객체 자체를 return하게 되면, 지나치게 많은 항목들(number, size, totalElements, totalPages, sort, first, last, ...) 이 return되게 된다. 따라서 pagination 시 필요한 변수들만 return 할 수 있도록 새로 SimplePageInfo 객체를 정의하였다

  • ProductService.java
  public ProductRes getProducts(Pageable pageable) {
    Page<Product> page = productRepository.findAll(pageable);
    List<Product> content = page.getContent();

    SimplePageInfo simplePageInfo = new SimplePageInfo();
    simplePageInfo.setLast(page.isLast());
    simplePageInfo.setPage(page.getNumber());
    simplePageInfo.setSize(page.getSize());
    simplePageInfo.setTotalPages(page.getTotalPages());
    simplePageInfo.setTotalElements(page.getTotalElements());

    return new ProductRes(
      HttpStatus.OK.value(),
      "PRODUCTS ARE RETRIEVED",
      content,
      simplePageInfo
    );
  }
  • ProductRepository.java
  Page<Product> findAll(Pageable pageable);

API 요청

1. {} 로 요청시

: @PageableDefault에서 설정한 값들이 반영된다

{
  "timestamp": "2023-11-18T15:06:51.446592200",
  "status": 200,
  "message": "PRODUCTS ARE RETRIEVED",
  "content": [
    {
      "productCode": "product_10",
      "category": {
        "categoryCode": "category_15",
        "parentCategory": null,
        "name": "과일",
        "description": "string"
      },
      "name": "신선한오렌지",
      "price": 1300,
      "stock": 10,
      "img": null,
      "barcode": "",
      "description": ""
    },
    {
      "productCode": "product_11",
      "category": {
        "categoryCode": "category_17",
        "parentCategory": {
          "categoryCode": "category_15",
          "parentCategory": null,
          "name": "과일",
          "description": "string"
        },
        "name": "덜익은망고",
        "description": "string"
      },
      "name": "망마라망고",
      "price": 1200,
      "stock": 11,
      "img": null,
      "barcode": "",
      "description": ""
    },
    # ...(2 more products)
  ],
  "pageable": {
    "last": true,
    "page": 0,
    "size": 10,
    "totalPages": 1,
    "totalElements": 4
  }
}

2. 사용자 설정 값으로 요청 시

  • request
{
  "page": 1,
  "size": 1
}
  • response
{
  "timestamp": "2023-11-18T15:10:14.826372600",
  "status": 200,
  "message": "PRODUCTS ARE RETRIEVED",
  "content": [
    {
      "productCode": "product_11",
      "category": {
        "categoryCode": "category_17",
        "parentCategory": {
          "categoryCode": "category_15",
          "parentCategory": null,
          "name": "과일",
          "description": "string"
        },
        "name": "덜익은망고",
        "description": "string"
      },
      "name": "망마라망고",
      "price": 1200,
      "stock": 11,
      "img": null,
      "barcode": "",
      "description": ""
    }
  ],
  "pageable": {
    "last": false, # 4 페이지 중 2번째 (index 1) 페이지이므로 마지막 페이지가 아님
    "page": 1,
    "size": 1,
    "totalPages": 4,
    "totalElements": 4
  }
}
profile
의견 나누는 것을 좋아합니다 ლ(・ヮ・ლ)

0개의 댓글