Part 2 – How to Implement Pagination in Spring Boot with Thymeleaf

We would not complete this series on How to Implement Pagination in Spring Boot. You can find Part 1 here.

In this part we would add the Page Number links to the table footer. We would also add the links for the First, Previous, Next and Last pages.

 

1. The Pagination Layout

We would use the pagination layout available in Bootstrap. This is shown below:

<nav aria-label="Page navigation example">
    Total Items [[${totalItems}]] : Page [[${currentPage}]] of [[${totalPages}]]
    
    <ul class="pagination">
        <li class="page-item">
            First
        </li>

        <li class="page-item">
            Previous
        </li>

        <li class="page-item">
             1 2 3 4 ...
        </li>

        <li class="page-item">
            Next
        </li>

        <li class="page-item">
            Last
        </li>
    </ul>
</nav>

 

2. First Page

This would be a link if  the current page is greater than 1. In other words, it would be a plain text unless the current page is greater than 1. It makes a request for page number of 1. The code is given below:

<a  class="page-link" th:if="${currentPage > 1}" th:href="@{/parameters/countries/page/1}">First</a>
<span th:unless="${currentPage > 1}">First</span>

 

3. Previous Page

Just like the first page, the text would be a link if the current page is greater than 1. However, it makes a request for page number of currentPage – 1. See the code below:

<a th:if="${currentPage > 1}" th:href="@{'/parameters/countries/page/' + ${currentPage - 1}}">Previous</a>
<span th:unless="${currentPage > 1}">Previous</span>

 

4. Page Number Links

The page number links would exactly as we have it before but now inside the <li></li> tags.

<span th:each="i: ${#numbers.sequence(1, totalPages)}">
        <a th:if="${i != currentPage}" th:href="@{'/parameters/countries/page/' + ${i}}">[[${i}]]</a>
        <span th:unless="${i != currentPage}">[[${i}]]</span>
</span>

 

5. Next Page

In case of the next page, the Next displays a link if the current page is less than the total pages. Otherwise, it displays a plain text. It request for currentPage + 1

<a th:if="${currentPage < totalPages}" th:href="@{'/parameters/countries/page/' + ${currentPage + 1}}">Next</a>
<span th:unless="${currentPage < totalPages}">Next</span>

 

6. Last Page

In this case, a link would be displayed if the current page is less than the total pages. Otherwise, it displays a plain text. It simply request for the page number of totalPages.

<a th:if="${currentPage < totalPages}" th:href="@{'/parameters/countries/page/' + ${totalPages}}">Last</a>
<span th:unless="${currentPage < totalPages}">Last</span>

 

7. Combining Paging and Sorting

Now, if you we have the pagination working as expected. But if you try to do sorting by clicking on the column headers, it doesn’t work. We’ll fix this by combining pagination and sorting.

First, note the following points:

  • pagination takes precedence over sorting. So we’ll focus on making sorting work
  • to sort, we’ll need to provide the page number to sort. This can be done via path variable
  • paging to another page could undo existing sort status

You have to make the following changes:

Change 1 – In the html template, adjust the head links to includes the page to sort. In this case, it would be the current page like so:

<a th:href="@{'/parameters/countries/page/' + ${currentPage} + '/description?sortDir=' + ${reverseSortDir}}">

 

Change 2 – In the controller, create a new method getPageWithSort() that derives from getAllWithSort()

Change 3 – The GetMapping for this method would be:

@GetMapping("/parameters/page/{pageNumber}/countries/{field}")

 

Change 4 – Add the pageNumber as parameter to the method. Name it currentPage

Change 5 – Add the currentPage as third argument to the findCountryWithSorting() function call. This means the findAll() method would then take pageable as argument instead of sort. The modified findAllWithSort() is given below:

public Page<Country> findCountryWithSorting2(String field, String direction, int pageNumber){
    Sort sort = direction.equalsIgnoreCase(Sort.Direction.ASC.name())?
            Sort.by(field).ascending(): Sort.by(field).descending();
    Pageable pageable = PageRequest.of(pageNumber - 1,5, sort);
    return countryRepository.findAll(pageable);
}

 

8. Modify the Controller Method

Currently, in the controller, we have the getAllWithSort() function that takes two parameters: sortField and sortDirection. Now we would do three things:

  • change the name of the function from getAllWithSort() to getPageWithSort()
  • make the function accept one more parameter, that is the page number to get
  • pass the page number across as well to the findAllWithSort() which is in the service.

The new getPageWithSort() is given below:

@GetMapping("/parameters/countries/page/{pageNumber}/{field}")
public String getPageWithSort(Model model,
                              @PathVariable("pageNumber") int currentPage,
                              @PathVariable String field,
                              @PathParam("sortDir") String sortDir){

    Page<Country> page = countryService.findCountryWithSorting2(field, sortDir, currentPage);
    List<Country> countries = page.getContent();
    int totalPages = page.getTotalPages();
    long totalItems = page.getTotalElements();

    model.addAttribute("currentPage", currentPage);
    model.addAttribute("totalPages", totalPages);
    model.addAttribute("totalItems", totalItems);

    model.addAttribute("sortDir", sortDir);
    model.addAttribute("reverseSortDir", sortDir.equals("asc")?"desc":"asc");
    model.addAttribute("countries", countries);
    return "/parameters/countries";
}

 

I do recommend that you watch the video tutorial here for clarification.

kindsonthegenius

kindsonthegenius

Kindson Munonye is currently completing his doctoral program in Software Engineering in Budapest University of Technology and Economics

View all posts by kindsonthegenius →

Leave a Reply

Your email address will not be published. Required fields are marked *