Spring with Thymeleaf Pagination for a List(Phân trang với spring và thymeleaf)

09 tháng 09, 2022 - 2316 lượt xem

Phân trang với spring và thymeleaf

Người dịch: Dương Xuân Long - Học viên lớp Java10
Email liên hệ: linesco218@gmail.com
Bài viết gốc: baeldung.com
Link Source code: github.com

1. Tổng quan

Trong hướng dẫn nhanh này, chúng ta sẽ viết code để phân trang cho một list sử dụng Spring và Thymeleaf.

2. Maven Dependencies

Bên cạnh việc sử dụng Spring dependencies,chúng ta sẽ thêm dependencies cho Thymeleaf and Spring Data Commons:

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
    <version>2.3.2.RELEASE</version>
</dependency>

Chúng ta có thể tìm thymeleaf-spring5 và spring-data-commons dependencies mới nhất ở Maven Central repository.

3. Models

Phần ứng dụng của chúng ta sẽ trình bày một danh sách khóa học(course list).

package com.example.templatecourseadmin.model;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    private int id;
    private String title;
    private String description;
    private String type;
    private String image;
    private List<String> topics;
    private int supporterId;
}

4. Service

Sau đó chúng ta sẽ tạo ra một service để tạo ra danh sách khóa học được phân trang cho trang được yêu cầu sử dụng Spring Data Commons library:

public Page<Course> findPaginated(Pageable pageable) {
        int pageSize = pageable.getPageSize();
        int currentPage = pageable.getPageNumber();
        int startItem = currentPage * pageSize;
        List<Course> list;

        if (FakeDB.courses.size() < startItem) {
            list = Collections.emptyList();
        } else {
            int toIndex = Math.min(startItem + pageSize, FakeDB.courses.size());
            list = FakeDB.courses.subList(startItem, toIndex);
        }

        Page<Course> coursePage
                = new PageImpl<Course>(list, PageRequest.of(currentPage, pageSize), FakeDB.courses.size());

Trong service trên,chúng ta đã tạo một method trả lại trang được chọn dựa trên trang được yêu cầu(là trang được đại diện bởi Pageable interface).Class PageImpl giúp lọc ra danh sách khóa học đã được phân trang.

FakeDB.courses là danh sách khóa học đọc thêm ở phầm source code ở đầu trang.

5. Spring Controller

Để dùng giá tri mặc định cho trang được chọn và kích thước trang, chúng ta đơn giản có thể truy cập nguồn ở FakeDB.courses,không dùng tham số nào.

Nếu bất kì kích thước trang hoặc trang cụ thể nào được yêu cầu, chúng ta có thể thêm tham số page và size.

Ví dụ: /listBooks?page=2&size=6 sẽ lấy ra trang 2 với 6 mục trên một trang.

@RequestMapping(value = "/", method = RequestMethod.GET)
    public String listBooks(
            Model model,
            @RequestParam("page") Optional<Integer> page,
            @RequestParam("size") Optional<Integer> size) {
        int currentPage = page.orElse(1);
        int pageSize = size.orElse(5);

        Page<Course> coursePage = courseService.findPaginated(PageRequest.of(currentPage - 1, pageSize));

        model.addAttribute("coursePage", coursePage);

        int totalPages = coursePage.getTotalPages();
        if (totalPages > 0) {
            List<Integer> pageNumbers = IntStream.rangeClosed(1, totalPages)
                    .boxed()
                    .collect(Collectors.toList());
            model.addAttribute("pageNumbers", pageNumbers);
        }

        return "course-list";
    }

6. Thymeleaf Template

Đây là phần thymeleaf.Chúng ta sẽ tạo trang “course-lít.html”:

<table>
   ...
<tbody>
                        <tr th:each="course,state:${coursePage.content}" >
                                <td th:text="${coursePage.size*(coursePage.number)+(state.index+1)}">1</td>
                            <td>
                                <a th:href="@{/edit/{id}(id=${course.id})}" th:text="${course.title}">SpringBoot - Web Back End</a>
                            </td>
                            <td th:text="${course.type}"
                                th:classappend="${course.type=='onlab'?'text-info':'text-warning'}">onlab</td>
                            <td th:text="${#strings.listJoin(course.topics, ', ')}"></td>
                        </tr>
                    </tbody>
                </table>

                <nav aria-label="Page navigation example">
                    <ul class="pagination justify-content-center pagination-sm">
                        <li  th:if="${coursePage.totalPages > 0}" class="page-link"
                              th:each="pageNumber : ${pageNumbers}">
                            <a th:href="@{/(size=${coursePage.size}, page=${pageNumber})}"
                               th:text=${pageNumber}
                               th:class="${pageNumber==coursePage.number + 1} ? active"
                               class="page-link"
                            ></a>
                        </li>
                    </ul>
                </nav>

Phần html trên có dùng bootstrap để phần link phân trang đẹp hơn.

7.Kết quả

Đây là hình ảnh kết quả đạt được:
Kết quả phân trang

8.Kết luận

Phần phân trang với spring và thymeleaf hơi phức tạp và có nhược điểm là không thể trình bày kiểu “…” khi số trang quá nhiều nhưng số trang ít thì được.

Bình luận

avatar
Trịnh Minh Cường 2022-09-10 04:42:39.31138 +0000 UTC

Bài hay đấy bạn.

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  0 Thích
0