Open In App

Spring MVC – Building Pagination and Sorting in Web Applications

Last Updated : 25 Nov, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In modern web applications, the data can often be too large to be displayed in a single format. The use of pagination and sorting is essential to enhance the user experience and handle large datasets efficiently. Pagination breaks down into manageable chunks or pages, while sorting allows users to view data sequentially.

In this article, we will learn the process of the implementing pagination and sorting in the Spring MVC application.

Prerequisites:

  • Basic knowledge of the Java and Spring Framework.
  • Basic understanding of the MVC architecture.
  • Maven for building dependency management.
  • JDK and IntelliJ IDEA should have installed in the system.

Pagination

Paging is the process of dividing large data into smaller chunks or pages. In Spring MVC applications, the Pageable interface can be used, which allows dynamic data retrieval based on the requested page number and size

Sorting

Sorting enables the users to order the data on the specific fields, such as names, dates, or any other attributes. The Sort class in the Spring Data JPA provides various options for sorting data.

Implement Pagination and Sorting in a Spring MVC Application

This example project demonstrate the pagination and sorting in the Spring MVC application. This project will allow the user to navigate through the list of the products sorted by specified field (such as name or price), and display the data in pages.

Step 1: Create a new Spring Boot Project

Create a new Spring Boot Project using the IntelliJ IDEA. Choose the following options:

  • Name: spring-pagination-sorting-example
  • Language: Java
  • Type: Maven
  • Packaging: Jar

Click on the Next button.

Project Metadata

Step 2: Add the Dependencies

Add the following dependencies into the Spring Boot Project:

  • Spring Web
  • Spring DevTools
  • Spring Data JPA
  • MySQL Driver
  • Lombok
  • Thymeleaf

Click on the Create button.

Add Dependencies

Step 3: Configure Application Properties

Open the application.properties file and add the following MySQL and Hibernate configurations.

spring.application.name=spring-pagination-sorting-example
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=mypassword
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

Step 4: Create the Product Class

Create the Product entity. This class will represent the data to be paginated and sorted.

Product.java:

Java
package com.gfg.springpaginationsortingexample;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;
}

Step 5: Create the ProductRepository Interface

Create the ProductRepository interface. This interface extends the JpaRepository interface and enables the pagination and sorting of the Product entities.

ProductRepository.java:

Java
package com.gfg.springpaginationsortingexample;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
}

Step 6: Create the ProductService Class

Create the ProductService class. This service class will handle the business logic for retrieving pagination and sorted data from the database.

ProductService.java:

Java
package com.gfg.springpaginationsortingexample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public Page<Product> findPaginatedAndSorted(int pageNo, int pageSize, String sortField, String sortDirection) {
        Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name()) ?
                Sort.by(sortField).ascending() :
                Sort.by(sortField).descending();

        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
        return productRepository.findAll(pageable);
    }
}

Step 7: Create the ProductController Class

Create the ProductController class. This controller handles the requests for the pagination and sorting and forward the data to the view layer.

ProductController.java:

Java
package com.gfg.springpaginationsortingexample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller
public class ProductController {

    @Autowired
    private ProductService productService;

    /**
     * Method to display the products page with pagination and sorting.
     * @param pageNo The current page number.
     * @param sortField The field to sort the products by.
     * @param sortDir The direction of the sort (ascending or descending).
     * @param model The model to pass attributes to the view.
     * @return The name of the view to render.
     */
    @GetMapping("/products")
    public String viewProductsPage(
            @RequestParam(value = "pageNo", defaultValue = "1") int pageNo,
            @RequestParam(value = "sortField", defaultValue = "name") String sortField,
            @RequestParam(value = "sortDir", defaultValue = "asc") String sortDir,
            Model model) {

        int pageSize = 10;
        Page<Product> page = productService.findPaginatedAndSorted(pageNo, pageSize, sortField, sortDir);
        List<Product> productList = page.getContent();

        model.addAttribute("currentPage", pageNo);
        model.addAttribute("totalPages", page.getTotalPages());
        model.addAttribute("totalItems", page.getTotalElements());

        model.addAttribute("sortField", sortField);
        model.addAttribute("sortDir", sortDir);
        model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");

        model.addAttribute("products", productList);

        return "products";
    }
}

Step 8: Main Class

No changes are required in the main class.

Java
package com.gfg.springpaginationsortingexample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringPaginationSortingExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringPaginationSortingExampleApplication.class, args);
    }

}

Step 9: View Layer

This thymeleaf template will render the paginated and sorted product list along with the pagination controls and sorting options.

products.html:

HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Paginated and Sorted Products</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f9f9f9;
        }

        h2 {
            color: #4CAF50;
        }

        table {
            width: 100%;
            border-collapse: collapse;
        }

        table, th, td {
            border: 1px solid #ddd;
        }

        th, td {
            padding: 12px;
            text-align: left;
        }

        th {
            background-color: #f2f2f2;
        }

        a.sort-link {
            text-decoration: none;
            color: #4CAF50;
        }

        a.sort-link:hover {
            text-decoration: underline;
        }

        ul {
            list-style-type: none;
            padding: 0;
        }

        ul li {
            display: inline;
            margin-right: 10px;
        }

        ul li a {
            text-decoration: none;
            color: #4CAF50;
        }

        ul li a:hover {
            text-decoration: underline;
        }

        .pagination {
            margin-top: 20px;
        }

    </style>
</head>
<body>

<h2>Products</h2>

<table>
    <thead>
    <tr>
        <th>
            <!-- Toggle sorting for Product Name -->
            <a th:href="@{/products(pageNo=${currentPage}, sortField='name', sortDir=${reverseSortDir})}"
               class="sort-link">
                Product Name
                <!-- Display ▲ if ascending, ▼ if descending -->
                <span th:text="${sortField == 'name' ? (sortDir == 'asc' ? '▲' : '▼') : ''}"></span>
            </a>
        </th>
        <th>
            <!-- Toggle sorting for Price -->
            <a th:href="@{/products(pageNo=${currentPage}, sortField='price', sortDir=${reverseSortDir})}"
               class="sort-link">
                Price
                <!-- Display ▲ if ascending, ▼ if descending -->
                <span th:text="${sortField == 'price' ? (sortDir == 'asc' ? '▲' : '▼') : ''}"></span>
            </a>
        </th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="product : ${products}">
        <td th:text="${product.name}">Product Name</td>
        <td th:text="${product.price}">Price</td>
    </tr>
    </tbody>
</table>

<!-- Pagination -->
<div class="pagination">
    <ul>
        <li th:if="${currentPage > 1}">
            <a th:href="@{/products(pageNo=${currentPage - 1}, sortField=${sortField}, sortDir=${sortDir})}">Previous</a>
        </li>
        <li th:if="${currentPage < totalPages}">
            <a th:href="@{/products(pageNo=${currentPage + 1}, sortField=${sortField}, sortDir=${sortDir})}">Next</a>
        </li>
    </ul>
</div>

</body>
</html>

pom.xml file:

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>spring-pagination-sorting-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-pagination-sorting-example</name>
    <description>spring-pagination-sorting-example</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Step 10: Run the Application

Once the project is completed, run the project, and it will start at port 8080.

Application Runs


Application Logs:

Application Logs

Step 11: Testing the Application

Now, type the below URL in any browser, and it will display the below output.

http://localhost:8080/products

Output Video:


This setup provides a complete example of how to implement the pagination and sorting in the Spring MVC application with Thymeleaf.



Next Article
Article Tags :

Similar Reads