{"id":1993,"date":"2021-12-17T12:00:00","date_gmt":"2021-12-17T11:00:00","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/part-2-how-to-implement-pagination-in-spring-boot-with-thymeleaf\/"},"modified":"2026-07-06T18:42:11","modified_gmt":"2026-07-06T16:42:11","slug":"part-2-how-to-implement-pagination-in-spring-boot-with-thymeleaf","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/part-2-how-to-implement-pagination-in-spring-boot-with-thymeleaf\/","title":{"rendered":"Part 2 \u2013 How to Implement Pagination in Spring Boot with Thymeleaf"},"content":{"rendered":"<p>We would not complete this series on How to Implement Pagination in Spring Boot. You can find<a href=\"https:\/\/kindsonthegenius.com\/blog\/how-to-implement-pagination-in-spring-boot-with-thymeleaf\/\" target=\"_blank\" rel=\"noopener\"> Part 1 here<\/a>.<\/p>\n<p>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.<\/p>\n<p>&nbsp;<\/p>\n<h4><strong>1. The Pagination Layout<\/strong><\/h4>\n<p>We would use the pagination layout available in Bootstrap. This is shown below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;nav<\/span> <span style=\"color: #0000cc;\">aria-label=<\/span><span style=\"background-color: #fff0f0;\">\"Page navigation example\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n    Total Items [[${totalItems}]] : Page [[${currentPage}]] of [[${totalPages}]]\r\n    \r\n    <span style=\"color: #007700;\">&lt;ul<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"pagination\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n        <span style=\"color: #007700;\">&lt;li<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-item\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n            First\r\n        <span style=\"color: #007700;\">&lt;\/li&gt;<\/span>\r\n\r\n        <span style=\"color: #007700;\">&lt;li<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-item\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n            Previous\r\n        <span style=\"color: #007700;\">&lt;\/li&gt;<\/span>\r\n\r\n        <span style=\"color: #007700;\">&lt;li<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-item\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n             1 2 3 4 ...\r\n        <span style=\"color: #007700;\">&lt;\/li&gt;<\/span>\r\n\r\n        <span style=\"color: #007700;\">&lt;li<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-item\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n            Next\r\n        <span style=\"color: #007700;\">&lt;\/li&gt;<\/span>\r\n\r\n        <span style=\"color: #007700;\">&lt;li<\/span> <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-item\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n            Last\r\n        <span style=\"color: #007700;\">&lt;\/li&gt;<\/span>\r\n    <span style=\"color: #007700;\">&lt;\/ul&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;\/nav&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>2. First Page<\/strong><\/h4>\n<p>This would be a link if\u00a0 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:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;a<\/span>  <span style=\"color: #0000cc;\">class=<\/span><span style=\"background-color: #fff0f0;\">\"page-link\"<\/span> <span style=\"color: #0000cc;\">th:if=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &gt; 1}\"<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{\/parameters\/countries\/page\/1}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>First<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:unless=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &gt; 1}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>First<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>3. Previous Page<\/strong><\/h4>\n<p>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 &#8211; 1. See the code below:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:if=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &gt; 1}\"<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{'\/parameters\/countries\/page\/' + ${currentPage - 1}}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Previous<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:unless=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &gt; 1}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Previous<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>4. Page Number Links<\/strong><\/h4>\n<p>The page number links would exactly as we have it before but now inside the &lt;li&gt;&lt;\/li&gt; tags.<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><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:if=<\/span><span style=\"background-color: #fff0f0;\">\"${i != currentPage}\"<\/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: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:unless=<\/span><span style=\"background-color: #fff0f0;\">\"${i != currentPage}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>[[${i}]]<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>5. Next Page<\/strong><\/h4>\n<p>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<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:if=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &lt; totalPages}\"<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{'\/parameters\/countries\/page\/' + ${currentPage + 1}}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Next<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:unless=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &lt; totalPages}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Next<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>6. Last Page<\/strong><\/h4>\n<p>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.<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:if=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &lt; totalPages}\"<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{'\/parameters\/countries\/page\/' + ${totalPages}}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Last<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\r\n<span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:unless=<\/span><span style=\"background-color: #fff0f0;\">\"${currentPage &lt; totalPages}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Last<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<h4><strong>7. Combining Paging and Sorting<\/strong><\/h4>\n<p>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&#8217;t work. We&#8217;ll fix this by combining pagination and sorting.<\/p>\n<p>First, note the following points:<\/p>\n<ul>\n<li>pagination takes precedence over sorting. So we&#8217;ll focus on making sorting work<\/li>\n<li>to sort, we&#8217;ll need to provide the page number to sort. This can be done via path variable<\/li>\n<li>paging to another page could undo existing sort status<\/li>\n<\/ul>\n<p>You have to make the following changes:<\/p>\n<p><strong>Change 1<\/strong> &#8211;\u00a0In the html template, adjust the head links to includes the page to sort. In this case, it would be the current page like so:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:href=<\/span><span style=\"background-color: #fff0f0;\">\"@{'\/parameters\/countries\/page\/' + ${currentPage} + '\/description?sortDir=' + ${reverseSortDir}}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Change 2<\/strong> &#8211; In the controller, create a new method getPageWithSort() that derives from getAllWithSort()<\/p>\n<p><strong>Change 3<\/strong> &#8211; The GetMapping for this method would be:<\/p>\n<pre style=\"margin: 0; line-height: 125%;\">@GetMapping(\"\/parameters\/page\/{pageNumber}\/countries\/{field}\")\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Change 4<\/strong> &#8211; Add the pageNumber as parameter to the method. Name it currentPage<\/p>\n<p><strong>Change 5<\/strong> &#8211; 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:<br \/>\n<!-- HTML generated using hilite.me --><\/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;\">findCountryWithSorting2<\/span><span style=\"color: #333333;\">(<\/span>String field<span style=\"color: #333333;\">,<\/span> String direction<span style=\"color: #333333;\">,<\/span> <span style=\"color: #333399; font-weight: bold;\">int<\/span> pageNumber<span style=\"color: #333333;\">){<\/span>\r\n    Sort sort <span style=\"color: #333333;\">=<\/span> direction<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">equalsIgnoreCase<\/span><span style=\"color: #333333;\">(<\/span>Sort<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">Direction<\/span><span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">ASC<\/span><span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">name<\/span><span style=\"color: #333333;\">())?<\/span>\r\n            Sort<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">by<\/span><span style=\"color: #333333;\">(<\/span>field<span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">ascending<\/span><span style=\"color: #333333;\">():<\/span> Sort<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">by<\/span><span style=\"color: #333333;\">(<\/span>field<span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">descending<\/span><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> sort<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>&nbsp;<\/p>\n<h4><strong>8. Modify the Controller Method<\/strong><\/h4>\n<p>Currently, in the controller, we have the getAllWithSort() function that takes two parameters: sortField and sortDirection. Now we would do three things:<\/p>\n<ul>\n<li>change the name of the function from getAllWithSort() to getPageWithSort()<\/li>\n<li>make the function accept one more parameter, that is the page number to get<\/li>\n<li>pass the page number across as well to the findAllWithSort() which is in the service.<\/li>\n<\/ul>\n<p>The new getPageWithSort() 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}\/{field}\"<\/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;\">getPageWithSort<\/span><span style=\"color: #333333;\">(<\/span>Model model<span style=\"color: #333333;\">,<\/span>\r\n                              <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                              <span style=\"color: #555555; font-weight: bold;\">@PathVariable<\/span> String field<span style=\"color: #333333;\">,<\/span>\r\n                              <span style=\"color: #555555; font-weight: bold;\">@PathParam<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"sortDir\"<\/span><span style=\"color: #333333;\">)<\/span> String sortDir<span style=\"color: #333333;\">){<\/span>\r\n\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;\">findCountryWithSorting2<\/span><span style=\"color: #333333;\">(<\/span>field<span style=\"color: #333333;\">,<\/span> sortDir<span style=\"color: #333333;\">,<\/span> currentPage<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    <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\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\r\n    model<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">addAttribute<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"sortDir\"<\/span><span style=\"color: #333333;\">,<\/span> sortDir<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;\">\"reverseSortDir\"<\/span><span style=\"color: #333333;\">,<\/span> sortDir<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">equals<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"asc\"<\/span><span style=\"color: #333333;\">)?<\/span><span style=\"background-color: #fff0f0;\">\"desc\"<\/span><span style=\"color: #333333;\">:<\/span><span style=\"background-color: #fff0f0;\">\"asc\"<\/span><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>I do recommend that you watch the <a href=\"https:\/\/youtu.be\/APlCxqMK9eY\" target=\"_blank\" rel=\"noopener\">video tutorial here<\/a> for clarification.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &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-1993","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1993","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=1993"}],"version-history":[{"count":2,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1993\/revisions"}],"predecessor-version":[{"id":2193,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1993\/revisions\/2193"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=1993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=1993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=1993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}