Jpa에서 제공해주는 pagination을 이용한 커서 기반 페이지네이션 구현하기

김가빈·2023년 9월 5일
0

jpa

목록 보기
1/2

구조


  • 위의 사진에서 보다시피 JpaRepository 인터페이스는 PagingAndSortingRepository를 확장하고 있다.
  • 따라서 jpa에서 기본적으로 제공해 주는 pagination을 사용할 수 있다.

pagination 사용법

package com.springdatejpa.springboot.repository;

import java.util.List;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import com.springdatejpa.springboot.entity.Product;

@SpringBootTest
public class PaginationAndSortingTest {

	@Autowired
	private ProductRepository productRepository;
	
	@Test
	void pagination() {
		
		int pageNo = 0;
		int pageSize = 5;
		
		// create pageable object
		Pageable pageable = PageRequest.of(pageNo, pageSize);
		
		// findAll method and pass pageable instance
		Page<Product> page = productRepository.findAll(pageable);
		
		List<Product> products = page.getContent();
		
		products.forEach((product) -> System.out.println(product));
		
		// total pages
		int totalPage = page.getTotalPages();
		// total elements
		long totalElements = page.getTotalElements();
		// number of elements
		int numberOfElements = page.getNumberOfElements(); 
		// size
		int size = page.getSize();
		// last
		boolean isLast = page.isLast();
		// first
		boolean isFirst = page.isFirst();
		
		System.out.println("totalPage : " + totalPage);
		System.out.println("totalElements : " + totalElements);
		System.out.println("numberOfElements : " + numberOfElements);
		System.out.println("size : " + size);
		System.out.println("isLast : " + isLast);
		System.out.println("isFirst : " + isFirst);
	}
}

커서기반 페이지네이션

  • 커서기반 페이지 네이션이란, 마지막 요소를 기준으로 그 다음 요소들을 지정한 size에 맞게 가지고 오는 방식이다.
  • 이를 구현하기 위해서는 현재 페이지가 첫 페이지인지, 그리고 첫 페이지가 아니라면 마지막 요소를 기준으로 그 다음 size를 가지고 오는 방식을 취해야한다.

예제

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/products")
public class ProductController {

    @Autowired
    private ProductRepository productRepository;

    @GetMapping
    public Page<Product> getProducts(Pageable pageable, @RequestParam(required = false) Long lastItemId) {
        if (lastItemId != null) {
            // 이전 페이지의 마지막 아이템을 기준으로 다음 페이지를 요청합니다.
            return productRepository.findByIdGreaterThanOrderByPriceAsc(lastItemId, pageable);
        } else {
            // 첫 번째 페이지 요청입니다.
            return productRepository.findAllByOrderByPriceAsc(pageable);
        }
    }
}
  • if (lastItemId != null) 대신 page객체의 isFirst를 사용할 수도 있다. 이럴 경우 다음처럼 코드가 바뀐다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/products")
public class ProductController {

    @Autowired
    private ProductRepository productRepository;

    @GetMapping
    public Page<Product> getProducts(Pageable pageable, @RequestParam(name = "lastItemId", required = false) Long lastItemId) {
        if (!pageable.isFirst()) {
            // 이전 페이지가 아닌 경우, 이전 페이지의 마지막 아이템을 기준으로 다음 페이지를 요청합니다.
            return productRepository.findByIdGreaterThanOrderByPriceAsc(lastItemId, pageable);
        } else {
            // 첫 번째 페이지 요청입니다.
            return productRepository.findAllByOrderByPriceAsc(pageable);
        }
    }
}
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

public interface ProductRepository extends CrudRepository<Product, Long> {
    Page<Product> findAllByOrderByPriceAsc(Pageable pageable);
    Page<Product> findByIdGreaterThanOrderByPriceAsc(Long lastItemId, Pageable pageable);
}
  • 참고로 findByIdGreaterThanOrderByPriceAsc은 아마 이런 쿼리의 형태로 나올 것이다
SELECT * FROM product WHERE id > :lastItemId ORDER BY price ASC LIMIT :pageSize
profile
신입 웹개발자입니다.

0개의 댓글