Pagination in SpringBoot With Thymeleaf

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

In this tutorial, you will learn how to easily implement pagination in Spring Boot with Thymeleaf page and JpaRepository. This would be a step-by-step tutorial with all the code snippets you need.

I assume you already know how to get list of items from a repository and display them on a page using Thymeleaf.  You can review this here.

In this tutorial, we would adjust the Countries page to include pagination

The following is covered:

  1. What we Currently Have
  2. Modify the Service
  3. Write the GetOnePage Method
  4. Write the GetFirstPage Method
  5. Next Steps

 

1. What we Currently Have

This is what is going to change

CountryService.java – this class has the findAll() method as shown below:

public List<Country> findAll(){
    return countryRepository.findAll();
}

we would modify this

CountryController.java – we would modify this as well

@GetMapping("/parameters/countries")
public String  getAll(Model model, String keyword){
    List<Country> countries;
    countries = keyword == null? countryService.findAll():countryService.findByKeyword(keyword);
    model.addAttribute("countries", countries);
    return "/parameters/countries";
}

 

countries.html – this file contains the table markup. We would simply adjust the markup to include a footer in the table with pagination links.

 

2. Modify the Service

The changes we would make here is quite simple.

We would write a new method called findPage(int pageNumber). This method takes an int parameter which would be that page to return. The return type is Page<> and not List<>. Then using this page number, we would create a Pageable object. Finally, we just call the repository findAll() method and pass it the Pageable object we created.

Note that a Page<> object contains a number of useful information including totalPages, content (list of items) and totalElements.

The complete method is given below:

public Page<Country> findPage(int pageNumber){
    Pageable pageable = PageRequest.of(pageNumber - 1,5);
    return countryRepository.findAll(pageable);
}

Here, the PageRequest.of() takes the pageNumber-1 (because the page number is zero-based) as first argument. The second argument is the size. Also notice that the findAll() method can also take a Pageable as argument.

 

3. Modify the Controller – GetOnePage() Method

So here, instead of findAll(), we would get one page at a time.

Now we need to write a new method that takes the pageNumber as second parameter. Remember the first parameter is the Model object. Then, we call the findPage() method, giving it the pageNumber/currentPage as argument.

The pageNumber would come as a PathVariable.

Then once we have the page, we would extract the following:

  • Total Pages – total pages in available
  • Total Elements – total elements in the page (it’s possible the last page would have less elements than other pages)
  • Content – the actual list of items. In this case, it’s list of Countries

Then we send all of this together with the currentPage to the UI as model attributes.

Finally as before, we return the countries template page.

The complete method is given below:

@GetMapping("/parameters/countries/page/{pageNumber}")
public String getOnePage(Model model, @PathVariable("pageNumber") int currentPage){
    Page<Country> page = countryService.findPage(currentPage);
    int totalPages = page.getTotalPages();
    long totalItems = page.getTotalElements();
    List<Country> countries = page.getContent();

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

    return "/parameters/countries";
}

 

4. Modify the Controller – GetFirstPage() Method

This is the method that would be called when the page loads for the first time.

So basically, this method would simply call the getOnePage() method which we already have. The page number argument would be 1.

The complete method is given below:

@GetMapping("/parameters/countries")
public String getAllPages(Model model){
    return getOnePage(model, 1);
}

 

4. Add Pagination Footer to HTML Template

In the footer, we would like to have three features

  • a text like: Page 1 of 5
  • page numbers as links

The code below is added as a footer to the Countries table in the HTML page

<footer style="font-size: large" class="panel-footer">
    Total Items [[${totalItems}]] : Page [[${currentPage}]] of [[${totalPages}]]
    &nbsp; &nbsp; - &nbsp;
    <span th:each="i: ${#numbers.sequence(1, totalPages)}">
        <a th:href="@{'/parameters/countries/page/' + ${i}}">[[${i}]]</a>
        &nbsp; &nbsp;
    </span>
</footer>

You can now test to make sure everything works well!

But we are not done yet

 

5. Next Steps

If you have used pagination feature before, you will see that there are alway four additional buttons:

First, Next, Previous and Last

We would implement this in the next part.

Then you’ll also notice that when we are in a current page, the page number is still hyperlinked. This has to be fixed. When in current page, then the page number should not be a link.

Let’s move on to Part 2. By the way, I recommend you watch the video tutorial if it’s clearer for you. Available in my YouTube Channel (Kindson The Tech Pro).

 

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 *