Người dịch: Lê Trung Kiên lớp java 08
Bài viết gốc: https://www.baeldung.com/spring-data-jpa-pagination-sorting

1.Mở đầu

Việc phân trang thường hữu ích khi chúng ta có một lượng dữ liệu lớn và hiển thị nó cho người dùng theo từng phần nhỏ hơn. Bên cạnh đó, ta cũng sắp xếp lượng dữ liệu đó theo một số tiêu chí nhất trong khi đang phân trang.
Trong bài viết này, chúng ta sẽ học cách phân trang và sắp xếp dữ liệu một cách dễ dàng với Spring Data JPA.

2. Thiết lập ban đầu

Đầu tiên, ta cần có một entity Product với những trường dữ liệu như sau:

@Entity 
public class Product {
    
    @Id
    private long id;
    private String name;
    private double price; 

    // constructors, getters and setters 

}

Với mỗi Product có trường id là duy nhất và không trùng lặp, cùng với đó là tên (“name”) và giá (“price”) của chúng.

3. Tạo Repository

Để truy cập vào các Products, chúng ta cần có nơi lưu trữ nó, ở đây sẽ là ProductRepository:

public interface ProductRepository extends PagingAndSortingRepository<Product, Integer> {

    List<Product> findAllByPrice(double price, Pageable pageable);
}

Bằng cách extend tới PagingAndSortingRepository, ta có phương thức findAll(Pageable pageable)findAll(Sort sort) để phân trang và sắp xếp.

Hoặc bạn cũng có thể extend thẳng đến JpaRepository, cũng đã bao gồm cả PagingAndSortingRepository bên trong nó.

Khi đã extend đến PagingAndSortingRepository, ta có thể định nghĩa lại và sử dụng phương thức phân trang và sắp xếp làm tham số, ví dụ như phương thức tìm sản phẩm theo giá tiền findAllByPrice sẽ làm ngay sau đây.

4. Phân trang

Khi đã có repository extend đến PagingAndSortingRepository, việc ta cần làm bây giờ là:

  • Tạo hoặc lấy đối tượng PageRequest, đây là một implement của Pageable interface.
  • Truyền PageRequest đó làm đối số cho phương thức chúng ta sẽ sử dụng.

Ta có thể tạo một đối tượng PageRequest bằng cách truyền vào số trang yêu cầu và kích thước trang.

Ở đây, số trang bắt đầu từ 0:

Pageable firstPageWithTwoElements = PageRequest.of(0, 2);

Pageable secondPageWithFiveElements = PageRequest.of(1, 5);

Khi đã có đối tượng PageRequest, ta có thể chuyển nó vào phương thức trong Repository mà ta tự định nghĩa lại:

Page<Product> allProducts = productRepository.findAll(firstPageWithTwoElements);

List<Product> allTenDollarProducts = 
  productRepository.findAllByPrice(10, secondPageWithFiveElements);

Phương thức findAll(Pageable pageable) mặc định trả về một đối tượng dạng Page.
Tuy nhiên, ta có thể chọn kiểu đối tượng dữ liệu trả về như Page, Slice hoặc List từ bất kỳ phương thức nào trả về dữ liệu phân trang mà chúng ta định nghĩa lại.

  1. Phân trang và sắp xếp
    Tương tự, để sắp xếp các kết quả, ta chỉ cần truyền một instance Sort vào trong phương thức:
Page<Product> allProductsSortedByName = productRepository.findAll(Sort.by("name"));

Tuy nhiên, nếu tôi muốn vừa sắp xếp, vừa phân trang dữ liệu cùng lúc thì làm sao?
Ta có thể truyền cả truyền thêm tham số sắp xếp vào đối tượng PageRequest ở trên:

Pageable sortedByName = 
  PageRequest.of(0, 3, Sort.by("name"));

Pageable sortedByPriceDesc = 
  PageRequest.of(0, 3, Sort.by("price").descending());

Pageable sortedByPriceDescNameAsc = 
  PageRequest.of(0, 5, Sort.by("price").descending().and(Sort.by("name")));

Dựa trên các yêu cầu sắp xếp khác nhau, ta có thể chỉ định các trường sắp xếp (“name”, “price”) và hướng sắp xếp (tăng dần, giảm dần) trong khi tạo ra các PageRequest.

Sau đó ta có thể truyền các Pageable này vào các phương thức trong Repository.

6.Kết luận

Trong bài viết này, ta đã học được cách phân trang và sắp xếp dữ liệu trả về với Spring Data JPA. Pageable là một cách tiếp cận rất tiện lợi, tuy nhiên, khi các hàm sử dụng Pageable sẽ thực hiện truy vấn hai lần vào DB. Một lần để lấy danh sách các bản ghi, một lần lấy ra tổng số page hiện có. Để tối ưu hiệu năng, bạn có thể chọn trả về Slice hoặc List.