{"id":1992,"date":"2021-12-15T12:00:00","date_gmt":"2021-12-15T11:00:00","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/how-to-implement-pagination-in-spring-boot-with-thymeleaf\/"},"modified":"2026-07-05T03:26:15","modified_gmt":"2026-07-05T01:26:15","slug":"how-to-implement-pagination-in-spring-boot-with-thymeleaf","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/how-to-implement-pagination-in-spring-boot-with-thymeleaf\/","title":{"rendered":"Part 1 \u2013 How to Implement Pagination in Spring Boot with Thymeleaf"},"content":{"rendered":"<p>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.<\/p>\n<p>I assume you already know how to get list of items from a repository and display them on a page using Thymeleaf.\u00a0 You can review this here.<\/p>\n<p>In this tutorial, we would adjust the Countries page to include pagination<\/p>\n<p>The following is covered:<\/p>\n<ol>\n<li><a href=\"#t1\">What we Currently Have<\/a><\/li>\n<li><a href=\"#t2\">Modify the Service<\/a><\/li>\n<li><a href=\"#t3\">Write the GetOnePage Method<\/a><\/li>\n<li><a href=\"#t4\">Write the GetFirstPage Method<\/a><\/li>\n<li><a href=\"#t5\">Next Steps<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t1\">1. What we Currently Have<\/strong><\/h4>\n<p>This is what is going to change<\/p>\n<p><strong>CountryService.java<\/strong> &#8211; this class has the findAll() method as shown below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008800; font-weight: bold;\">public<\/span> List<span style=\"color: #333333;\">&lt;<\/span>Country<span style=\"color: #333333;\">&gt;<\/span> <span style=\"color: #0066bb; font-weight: bold;\">findAll<\/span><span style=\"color: #333333;\">(){<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">return<\/span> countryRepository<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">findAll<\/span><span style=\"color: #333333;\">();<\/span>\r\n<span style=\"color: #333333;\">}<\/span>\r\n<\/pre>\n<p>we would modify this<\/p>\n<p><strong>CountryController.java<\/strong> &#8211; we would modify this as well<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@GetMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/parameters\/countries\"<\/span><span style=\"color: #333333;\">)<\/span>\r\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> String  <span style=\"color: #0066bb; font-weight: bold;\">getAll<\/span><span style=\"color: #333333;\">(<\/span>Model model<span style=\"color: #333333;\">,<\/span> String keyword<span style=\"color: #333333;\">){<\/span>\r\n    List<span style=\"color: #333333;\">&lt;<\/span>Country<span style=\"color: #333333;\">&gt;<\/span> countries<span style=\"color: #333333;\">;<\/span>\r\n    countries <span style=\"color: #333333;\">=<\/span> keyword <span style=\"color: #333333;\">==<\/span> <span style=\"color: #008800; font-weight: bold;\">null<\/span><span style=\"color: #333333;\">?<\/span> countryService<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">findAll<\/span><span style=\"color: #333333;\">():<\/span>countryService<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">findByKeyword<\/span><span style=\"color: #333333;\">(<\/span>keyword<span style=\"color: #333333;\">);<\/span>\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"countries\"<\/span><span style=\"color: #333333;\">,<\/span> countries<span style=\"color: #333333;\">);<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">return<\/span> <span style=\"background-color: #fff0f0;\">\"\/parameters\/countries\"<\/span><span style=\"color: #333333;\">;<\/span>\r\n<span style=\"color: #333333;\">}<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>countries.html<\/strong> &#8211; this file contains the table markup. We would simply adjust the markup to include a footer in the table with pagination links.<\/p>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t2\">2. Modify the Service<\/strong><\/h4>\n<p>The changes we would make here is quite simple.<\/p>\n<p>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&lt;&gt; and not List&lt;&gt;. 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.<\/p>\n<p>Note that a Page&lt;&gt; object contains a number of useful information including totalPages, content (list of items) and totalElements.<\/p>\n<p>The complete method is given below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008800; font-weight: bold;\">public<\/span> Page<span style=\"color: #333333;\">&lt;<\/span>Country<span style=\"color: #333333;\">&gt;<\/span> <span style=\"color: #0066bb; font-weight: bold;\">findPage<\/span><span style=\"color: #333333;\">(<\/span><span style=\"color: #333399; font-weight: bold;\">int<\/span> pageNumber<span style=\"color: #333333;\">){<\/span>\r\n    Pageable pageable <span style=\"color: #333333;\">=<\/span> PageRequest<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">of<\/span><span style=\"color: #333333;\">(<\/span>pageNumber <span style=\"color: #333333;\">-<\/span> <span style=\"color: #0000dd; font-weight: bold;\">1<\/span><span style=\"color: #333333;\">,<\/span><span style=\"color: #0000dd; font-weight: bold;\">5<\/span><span style=\"color: #333333;\">);<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">return<\/span> countryRepository<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">findAll<\/span><span style=\"color: #333333;\">(<\/span>pageable<span style=\"color: #333333;\">);<\/span>\r\n<span style=\"color: #333333;\">}<\/span>\r\n<\/pre>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t3\">3. Modify the Controller &#8211; GetOnePage() Method<\/strong><\/h4>\n<p>So here, instead of findAll(), we would get one page at a time.<\/p>\n<p>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.<\/p>\n<p>The pageNumber would come as a PathVariable.<\/p>\n<p>Then once we have the page, we would extract the following:<\/p>\n<ul>\n<li>Total Pages &#8211; total pages in available<\/li>\n<li>Total Elements &#8211; total elements in the page (it&#8217;s possible the last page would have less elements than other pages)<\/li>\n<li>Content &#8211; the actual list of items. In this case, it&#8217;s list of Countries<\/li>\n<\/ul>\n<p>Then we send all of this together with the currentPage to the UI as model attributes.<\/p>\n<p>Finally as before, we return the countries template page.<\/p>\n<p>The complete method is given below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@GetMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/parameters\/countries\/page\/{pageNumber}\"<\/span><span style=\"color: #333333;\">)<\/span>\r\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> String <span style=\"color: #0066bb; font-weight: bold;\">getOnePage<\/span><span style=\"color: #333333;\">(<\/span>Model model<span style=\"color: #333333;\">,<\/span> <span style=\"color: #555555; font-weight: bold;\">@PathVariable<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"pageNumber\"<\/span><span style=\"color: #333333;\">)<\/span> <span style=\"color: #333399; font-weight: bold;\">int<\/span> currentPage<span style=\"color: #333333;\">){<\/span>\r\n    Page<span style=\"color: #333333;\">&lt;<\/span>Country<span style=\"color: #333333;\">&gt;<\/span> page <span style=\"color: #333333;\">=<\/span> countryService<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">findPage<\/span><span style=\"color: #333333;\">(<\/span>currentPage<span style=\"color: #333333;\">);<\/span>\r\n    <span style=\"color: #333399; font-weight: bold;\">int<\/span> totalPages <span style=\"color: #333333;\">=<\/span> page<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">getTotalPages<\/span><span style=\"color: #333333;\">();<\/span>\r\n    <span style=\"color: #333399; font-weight: bold;\">long<\/span> totalItems <span style=\"color: #333333;\">=<\/span> page<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">getTotalElements<\/span><span style=\"color: #333333;\">();<\/span>\r\n    List<span style=\"color: #333333;\">&lt;<\/span>Country<span style=\"color: #333333;\">&gt;<\/span> countries <span style=\"color: #333333;\">=<\/span> page<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">getContent<\/span><span style=\"color: #333333;\">();<\/span>\r\n\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"currentPage\"<\/span><span style=\"color: #333333;\">,<\/span> currentPage<span style=\"color: #333333;\">);<\/span>\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"totalPages\"<\/span><span style=\"color: #333333;\">,<\/span> totalPages<span style=\"color: #333333;\">);<\/span>\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"totalItems\"<\/span><span style=\"color: #333333;\">,<\/span> totalItems<span style=\"color: #333333;\">);<\/span>\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"countries\"<\/span><span style=\"color: #333333;\">,<\/span> countries<span style=\"color: #333333;\">);<\/span>\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">return<\/span> <span style=\"background-color: #fff0f0;\">\"\/parameters\/countries\"<\/span><span style=\"color: #333333;\">;<\/span>\r\n<span style=\"color: #333333;\">}<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t4\">4. Modify the Controller &#8211; GetFirstPage() Method<\/strong><\/h4>\n<p>This is the method that would be called when the page loads for the first time.<\/p>\n<p>So basically, this method would simply call the getOnePage() method which we already have. The page number argument would be 1.<\/p>\n<p>The complete method is given below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@GetMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/parameters\/countries\"<\/span><span style=\"color: #333333;\">)<\/span>\r\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> String <span style=\"color: #0066bb; font-weight: bold;\">getAllPages<\/span><span style=\"color: #333333;\">(<\/span>Model model<span style=\"color: #333333;\">){<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">return<\/span> <span style=\"color: #0066bb; font-weight: bold;\">getOnePage<\/span><span style=\"color: #333333;\">(<\/span>model<span style=\"color: #333333;\">,<\/span> <span style=\"color: #0000dd; font-weight: bold;\">1<\/span><span style=\"color: #333333;\">);<\/span>\r\n<span style=\"color: #333333;\">}<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>4. Add Pagination Footer to HTML Template<\/strong><\/h4>\n<p>In the footer, we would like to have three features<\/p>\n<ul>\n<li>a text like: Page 1 of 5<\/li>\n<li>page numbers as links<\/li>\n<\/ul>\n<p>The code below is added as a footer to the Countries table in the HTML page<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;footer<\/span> <span style=\"color: #0000cc;\">style=<\/span><span style=\"background-color: #fff0f0;\">\"font-size: large\"<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"panel-footer\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n    Total Items [[${totalItems}]] : Page [[${currentPage}]] of [[${totalPages}]]\r\n    <span style=\"color: #880000; font-weight: bold;\">&amp;nbsp;<\/span> <span style=\"color: #880000; font-weight: bold;\">&amp;nbsp;<\/span> - <span style=\"color: #880000; font-weight: bold;\">&amp;nbsp;<\/span>\r\n    <span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:each=<\/span><span style=\"background-color: #fff0f0;\">\"i: ${#numbers.sequence(1, totalPages)}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n        <span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{'\/parameters\/countries\/page\/' + ${i}}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>[[${i}]]<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\r\n        <span style=\"color: #880000; font-weight: bold;\">&amp;nbsp;<\/span> <span style=\"color: #880000; font-weight: bold;\">&amp;nbsp;<\/span>\r\n    <span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;\/footer&gt;<\/span>\r\n<\/pre>\n<p>You can now test to make sure everything works well!<\/p>\n<p>But we are not done yet<\/p>\n<p>&nbsp;<\/p>\n<h4><strong id=\"t5\">5. Next Steps<\/strong><\/h4>\n<p>If you have used pagination feature before, you will see that there are alway four additional buttons:<\/p>\n<p><strong>First, Next, Previous and Last<\/strong><\/p>\n<p>We would implement this in the next part.<\/p>\n<p>Then you&#8217;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.<\/p>\n<p>Let&#8217;s move on to Part 2. By the way, I recommend you watch the video tutorial if it&#8217;s clearer for you. Available in <a href=\"https:\/\/www.youtube.com\/c\/KindsonTheTechPro\" target=\"_blank\" rel=\"noopener\">my YouTube Channel (Kindson The Tech Pro).<\/a><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[414],"tags":[],"class_list":["post-1992","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1992","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=1992"}],"version-history":[{"count":1,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1992\/revisions"}],"predecessor-version":[{"id":2160,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1992\/revisions\/2160"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=1992"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=1992"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=1992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}