Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 6 | Pagination using Spring Data JPA


In this PART 6, we will implement Pagination for our employee list page using Spring Data JPA and Thymeleaf.

Use the below links to navigate different parts of this tutorial:

1. Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 1
  • Create and Setup Spring Boot Project in Eclipse STS
  • Database Setup
7. Spring Boot Thymeleaf CRUD Database Real-Time Project - PART 7
  • Implement Sorting Feature

Understand Spring Data JPA’s Pagination APIs

To use paging and sorting APIs provided by Spring Data JPA, your repository interface must extend the PagingAndSortingRepository interface which defines the following couple of methods (T refers to an entity class):
@NoRepositoryBean
public interface PagingAndSortingRepository < T, ID > extends CrudRepository < T, ID > {

    /**
     * Returns all entities sorted by the given options.
     *
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable < T > findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     *
     * @param pageable
     * @return a page of entities
     */
    Page < T > findAll(Pageable pageable);
}
JpaRepository interface extends PagingAndSortingRepository interface so if your repository interface is of type JpaRepository, you don’t have to make a change to it.
For example, use the following to get the first page from the database, with 5 items per page:
int pageNumber = 1;
int pageSize = 5;
Pageable pageable = PageRequest.of(pageNumber, pageSize);
 
Page<Product> page = repository.findAll(pageable);
Then you can get the actual content as follows:
List<Employee> listEmployees = page.getContent();
With a Page object you can know the total rows in the database and the total pages according to the given page size:
long totalItems = page.getTotalElements();
int totalPages = page.getTotalPages();
This information is useful for implementing pagination in the view with the Thymeleaf template.

1. Back-end changes

EmployeeService.java interface changes

Add below method to this interface:
Page<Employee> findPaginated(int pageNo, int pageSize);
The complete code:
package net.javaguides.springboot.service;

import java.util.List;

import org.springframework.data.domain.Page;

import net.javaguides.springboot.model.Employee;

public interface EmployeeService {
    List < Employee > getAllEmployees();
    void saveEmployee(Employee employee);
    Employee getEmployeeById(long id);
    void deleteEmployeeById(long id);
    Page < Employee > findPaginated(int pageNo, int pageSize);
}

EmployeeServiceImpl.java class changes

Add below method to EmployeeServiceImpl class:
@Override
public Page<Employee> findPaginated(int pageNo, int pageSize) {
 Pageable pageable = PageRequest.of(pageNo - 1, pageSize);
 return this.employeeRepository.findAll(pageable);
}

EmployeeController.java class changes

Add below handler method to EmployeeController class to perform pagination:
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable(value = "pageNo") int pageNo, Model model) {
    int pageSize = 5;

    Page < Employee > page = employeeService.findPaginated(pageNo, pageSize);
    List < Employee > listEmployees = page.getContent();

    model.addAttribute("currentPage", pageNo);
    model.addAttribute("totalPages", page.getTotalPages());
    model.addAttribute("totalItems", page.getTotalElements());
    model.addAttribute("listEmployees", listEmployees);
    return "index";
}
Also, we need to make a change to an existing method as below:
// display list of employees
@GetMapping("/")
public String viewHomePage(Model model) {
 return findPaginated(1, model);  
}

2. Front-end changes

Add below pagination code to index.html:
<div th:if="${totalPages > 1}">
    <div class="row col-sm-10">
        <div class="col-sm-2">
            Total Rows: [[${totalItems}]]
        </div>
        <div class="col-sm-1">
            <span th:each="i: ${#numbers.sequence(1, totalPages)}">
      <a th:if="${currentPage != i}" th:href="@{'/page/' + ${i}}">[[${i}]]</a>
      <span th:unless="${currentPage != i}">[[${i}]]</span> &nbsp; &nbsp;
            </span>
        </div>
        <div class="col-sm-1">
            <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${currentPage + 1}}">Next</a>
            <span th:unless="${currentPage < totalPages}">Next</span>
        </div>

        <div class="col-sm-1">
            <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}}">Last</a>
            <span th:unless="${currentPage < totalPages}">Last</span>
        </div>
    </div>
</div>
The complete code:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="ISO-8859-1">
    <title>Employee Management System</title>

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

</head>

<body>

    <div class="container my-2">
        <h1>Employees List</h1>

        <a th:href="@{/showNewEmployeeForm}" class="btn btn-primary btn-sm mb-3"> Add Employee </a>

        <table border="1" class="table table-striped table-responsive-md">
            <thead>
                <tr>
                    <th>Employee First Name</th>
                    <th>Employee Last Name</th>
                    <th>Employee Email</th>
                    <th> Actions </th>
                </tr>
            </thead>
            <tbody>
                <tr th:each="employee : ${listEmployees}">
                    <td th:text="${employee.firstName}"></td>
                    <td th:text="${employee.lastName}"></td>
                    <td th:text="${employee.email}"></td>
                    <td> <a th:href="@{/showFormForUpdate/{id}(id=${employee.id})}" class="btn btn-primary">Update</a>
                        <a th:href="@{/deleteEmployee/{id}(id=${employee.id})}" class="btn btn-danger">Delete</a>
                    </td>
                </tr>
            </tbody>
        </table>

        <div th:if="${totalPages > 1}">
            <div class="row col-sm-10">
                <div class="col-sm-2">
                    Total Rows: [[${totalItems}]]
                </div>
                <div class="col-sm-1">
                    <span th:each="i: ${#numbers.sequence(1, totalPages)}">
      <a th:if="${currentPage != i}" th:href="@{'/page/' + ${i}}">[[${i}]]</a>
      <span th:unless="${currentPage != i}">[[${i}]]</span> &nbsp; &nbsp;
                    </span>
                </div>
                <div class="col-sm-1">
                    <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${currentPage + 1}}">Next</a>
                    <span th:unless="${currentPage < totalPages}">Next</span>
                </div>

                <div class="col-sm-1">
                    <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}}">Last</a>
                    <span th:unless="${currentPage < totalPages}">Last</span>
                </div>
            </div>
        </div>
    </div>
</body>

</html>

3. Run Spring boot application and demo

This PART explained very well with demo in below YouTube video:




Comments