Pagination is widely used to split a large number of data entries into discrete pages, allowing users to easily toggle through data entries. In this brief tutorial, we’ll learn to implement pagination in a Spring Boot and Thymeleaf based application. We will display a list of customers in Thymeleaf with pagination.

Getting started

For this tutorial, I assume that you know how to create a Spring Boot project that uses Thymeleaf templating engine. You can also use Spring Initializr to quickly create a Spring Boot project with Thymeleaf and Spring Data JPA dependencies.

Spring Data Models

Our application has only one model (also called domain in Spring Data JPA) named Customer. The model has three attributes: id, name and address.

@Entity
public class Customer {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private String address;

    // all-agrument contructor, getters and setters
}

Spring Data Repositories

For our Customer domain, we will create the following repository to load a page of Customers from the database:

public interface CustomerRepository extends JpaRepository<Customer, Long> {
    Customer findByName(String name);
}

JpaRepository extends PagingAndSortingRepository interface which provides methods to retrieve entities using the pagination and sorting abstraction.

Spring Controller

Let’s create a controller which declares /customers end-point to render the customers. The controller method takes optional page and size query parameters to retrieve a list of customers from the database. If no parameters are available, it uses the default values.

@Controller
public class CustomerController {
    private CustomerRepository customerRepository;
    
    public CustomerController(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }
    
    @GetMapping("/customers")
    public String customersPage(HttpServletRequest request, Model model) {
        
        int page = 0; //default page number is 0 (yes it is weird)
        int size = 10; //default page size is 10
        
        if (request.getParameter("page") != null && !request.getParameter("page").isEmpty()) {
            page = Integer.parseInt(request.getParameter("page")) - 1;
        }

        if (request.getParameter("size") != null && !request.getParameter("size").isEmpty()) {
            size = Integer.parseInt(request.getParameter("size"));
        }
        
        model.addAttribute("customers", customerRepository.findAll(PageRequest.of(page, size)));
        return "customers";
    }
}

Thymeleaf template

The final step is to create a Thymeleaf template customers.html which displays the list of customers with pagination based on a model attribute customers from our CustomerController class.

For styling, we are going to use Bootstrap 4 pagination component. It provides utility classes to nicely display the pagination links. We will first iterate over the list to display the customers in a table. Then we will add the pagination right below the table.

<table class="table table-bordered">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Address</th>
        </tr>
    </thead>
    <tbody>
        <tr th:each="customer : ${customers}">
            <td th:text="${customer.id}"></td>
            <td th:text="${customer.name}"></td>
            <td th:text="${customer.address}"></td>
        </tr>
    </tbody>
</table>

<!-- customers pagination -->
<nav aria-label="Pagination" th:if="${customers.totalPages gt 0}">
    <ul class="pagination justify-content-center font-weight-bold">
        <li class="page-item" th:classappend="${customers.number eq 0} ? 'disabled'">
            <a class="page-link"
               th:href="@{/customers?page={id}(id=${customers.number lt 2 ? 1 : customers.number})}"
               aria-label="Previous" title="Previous Page" data-toggle="tooltip">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        <li class="page-item" th:classappend="${i eq customers.number + 1} ? 'active'"
            th:each="i : ${#numbers.sequence( 1, customers.totalPages, 1)}">
            <a class="page-link" th:href="@{/customers?page={id}(id=${i})}" th:text="${i}"
               th:title="${'Page '+ i}" data-toggle="tooltip"></a>
        </li>
        <li class="page-item" th:classappend="${customers.number + 1 eq customers.totalPages} ? 'disabled'">
            <a class="page-link"
               th:href="@{/customers?page={id}(id=${customers.number + 2})}"
               aria-label="Next" title="Next Page" data-toggle="tooltip">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

When you will click on any page link, it will display the corresponding list of customers with the current page link highlighted.

Follow @attacomsian on Twitter to stay up-to-date with posts on this blog. You can also subscribe via RSS or follow me on DEV.


Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.