Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to…

Follow publication

A Comprehensive Guide to Pagination and Sorting in Spring Boot Applications

Here’s a straightforward and comprehensive guide on implementing Pagination and Sorting in Spring Boot apps. Using a Post app as an example, we’ll first implement Pagination and then move on to Sorting. Throughout, we’ll delve into the workings of the Pageable interface as well as PagingAndSortingRepository.

What exactly is Pagination and why does it hold importance?

Pagination is a technique used in web applications to divide and display a large set of data into smaller, more manageable parts known as pages. It is commonly seen in applications where extensive data needs to be presented to users, such as search results, long lists, or tables of records. Pagination divides the content into separate pages, allowing users to navigate through the data in a structured and digestible manner.

Importance and Benefits of Pagination:

  • Enhanced User Experience: Large volumes of data can overwhelm users. Pagination breaks down the information into more manageable sections, improving the user experience.
  • Faster Loading Times: Loading an entire dataset at once can slow down the application. By fetching and displaying data in smaller, bite-sized portions, each page can load more quickly.
  • Improved Readability and Accessibility: Dividing content into pages makes it easier for users to read and navigate through the information, especially in tables or lists.
  • Efficient Use of Resources: When dealing with massive datasets, fetching and processing everything at once can be resource-intensive. Pagination helps in reducing the load on the server and optimizes resource consumption.
  • Easier Navigation and Contextual Understanding: Users can navigate through the dataset one page at a time, providing context and continuity when understanding the relationship between different elements of the data.

What exactly is Sorting and why does it hold importance?

Sorting refers to the arrangement of data in a specific order, usually ascending or descending, based on certain criteria. In the context of web applications, sorting allows users to reorder data according to their preferences, making it easier to find, analyze, and understand information. This feature is particularly valuable when dealing with large datasets.

Importance and Benefits of Sorting:

  • Data Organization: Sorting arranges data in a logical order, making it easier to find specific information. For example, in a list of names or numbers, sorting ensures a predictable and organized arrangement.
  • Ease of Understanding: A sorted dataset helps users comprehend and analyze information more effectively, especially in tables, lists, or search results.
  • Quick Access to Relevant Data: Users can quickly find the most relevant or significant information by arranging data according to their needs.
  • Improved User Experience: Enabling users to sort data by different parameters, such as date, name, price, or relevance, provides a more personalized and efficient experience.
  • Decision Making: Sorted data aids in decision-making processes by making it easier to compare and contrast information.

Pagination Support

Modify PostService interface

List<PostDto> getAllPost(int pageNo, int pageSize);

Modify PostServiceImplementation class

  • The Pageable interface in the context of pagination and sorting is a part of the Spring Data framework. It's used to represent information regarding pagination and sorting criteria for queries, enabling the retrieval of data in manageable chunks and in a specified order.
  • Pagination Information: Pageable encapsulates data that defines how data should be paginated. It holds information like the page number, number of items per page (page size), and other optional details.
  • Query Methods: When used as a method parameter in Spring Data repository methods, Pageable helps in retrieving a specific "page" of data, allowing applications to fetch a limited amount of data based on the given page number and size.
  • The Page interface extends Slice and represents a page of data along with some additional pagination information. It's typically used to retrieve a specific "page" of results and to provide insights into the available data such as the total number of pages, total elements, etc.
  • Page encapsulates the data fetched based on the pagination information provided by Pageable. It includes the actual content for the current page along with metadata like the total number of pages, the total number of elements, and more.
  • The Page interface provides the total number of elements in the dataset, which can be useful for creating pagination controls in a user interface.
  • Page offers methods for navigating through the data, iterating over the content, and extracting information about the current page.
@Override
public List<PostDto> getAllPost(int pageNo, int pageSize) {
// Create a Pageable instance
Pageable pageable = PageRequest.of(pageNo, pageSize);
// Retrieve a page of posts
Page<Post> postList = postRepository.findAll(pageable);
// Get content for page object
List<Post> listOfPost = postList.getContent();
return listOfPost.stream().map(post -> modelMapper.map(post, PostDto.class)).collect(Collectors.toList());
}

Modify PostController class

@GetMapping
public ResponseEntity<List<PostDto>> getAllPost(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize
)
{
return new ResponseEntity<>(postService.getAllPost(pageNo, pageSize), HttpStatus.OK);
}

Customizing Pagination API Response

Create a class called PostResponse

The PostResponse class encapsulates and organizes the paginated data and its metadata, providing a structured format for returning paginated content. It serves as a wrapper that includes both the paginated content and essential information about the pagination process. Below are the reasons for its need in pagination:

Encapsulation of Pagination Metadata:

Content Representation:

  • List<PostDto> content: Holds the actual paginated data (list of PostDto objects) for the specific page.

Pagination Metadata:

  • int pageNo: Indicates the current page number.
  • int pageSize: Specifies the number of elements per page.
  • long totalElements: Represents the total count of elements in the dataset.
  • int totalPages: Shows the total number of pages.
  • boolean last: Identifies if it's the last page.

Benefits and Use Cases:

Standardized Response:

  • PostResponse provides a consistent structure to return paginated data along with necessary pagination metadata. This standardized format makes it easier for consuming services or clients to interpret the paginated response.
  • Easier Consumption: It simplifies the handling of paginated data on the client-side, providing direct access to both the content and metadata without needing to parse separate response components.
  • Enhanced Information: The metadata within PostResponse (such as total elements, total pages, etc.) is crucial for clients to understand and navigate paginated data efficiently.
  • Facilitates Client-Side Navigation: The information within PostResponse can assist in building user interfaces, especially when creating navigation controls for users to move between pages.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PostResponse {

private List<PostDto> content;

private int pageNo;

private int pageSize;

private long totalElements;

private int totalPages;

private boolean last;
}

Modify PostService interface

 PostResponse getAllPost(int pageNo, int pageSize);

Modify PostServiceImplementation class

 @Override
public PostResponse getAllPost(int pageNo, int pageSize) {
// Create a Pageable instance
Pageable pageable = PageRequest.of(pageNo, pageSize);
// Retrieve a page of posts
Page<Post> postList = postRepository.findAll(pageable);
// Get content for page object
List<Post> listOfPost = postList.getContent();

List<PostDto> content = listOfPost.stream().map(post -> modelMapper.map(post, PostDto.class)).collect(Collectors.toList());

PostResponse postResponse = new PostResponse();
postResponse.setContent(content);
postResponse.setPageNo(postList.getNumber());
postResponse.setPageSize(postList.getSize());
postResponse.setTotalElements(postList.getTotalElements());
postResponse.setTotalPages(postList.getTotalPages());
postResponse.setLast(postList.isLast());
return postResponse;
}

Modify PostController class

 @GetMapping
public PostResponse getAllPost(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize
) {
return postService.getAllPost(pageNo, pageSize);
}

Sorting Support to Get All Posts REST API

The Sort object in Spring Data is a fundamental component used to define sorting criteria for queries, specifically when fetching data from a database. It allows you to specify the order in which data should be retrieved based on one or more fields. This object encapsulates details about how the data should be sorted and provides the necessary flexibility for arranging data in a desired sequence.

Key Aspects of the Sort Object:

Creation of Sort Criteria:

  • Sort is used to define criteria for sorting by field names in ascending or descending order.
  • It’s instantiated using the Sort.by() method, specifying the field names and the direction of sorting.

Ascending and Descending Order:

  • Sort.by("fieldName").ascending() sorts data based on the specified field in ascending order.
  • Sort.by("fieldName").descending() sorts data based on the specified field in descending order.

Multiple Sorting Fields:

  • Multiple fields can be included to establish a compound sort order using the and() method.
  • For example, Sort.by("field1").ascending().and(Sort.by("field2").descending()) sorts data by field1 in ascending order and, for items with the same field1 value, it then sorts by field2 in descending order.

Modify PostService interface

  PostResponse getAllPost(int pageNo, int pageSize, String sortBy);

Modify PostServiceImplementation class

 @Override
public PostResponse getAllPost(int pageNo, int pageSize, String sortBy) {

// Sorting Support
Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.by(sortBy));

// Retrieve a page of posts
Page<Post> postList = postRepository.findAll(pageable);
// Get content for page object
List<Post> listOfPost = postList.getContent();

List<PostDto> content = listOfPost.stream().map(post -> modelMapper.map(post, PostDto.class)).collect(Collectors.toList());

PostResponse postResponse = new PostResponse();
postResponse.setContent(content);
postResponse.setPageNo(postList.getNumber());
postResponse.setPageSize(postList.getSize());
postResponse.setTotalElements(postList.getTotalElements());
postResponse.setTotalPages(postList.getTotalPages());
postResponse.setLast(postList.isLast());
return postResponse;
}

Modify PostController class

@GetMapping
public PostResponse getAllPost(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize,
@RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortBy
) {
return postService.getAllPost(pageNo, pageSize, sortBy);
}

Ordering in Sorting API — ASC and DESC

Sort.Direction is an enum in the Spring Framework that represents the sorting direction used in sorting operations for query results.

Here is a detailed explanation of Sort.Direction:

Purpose:

  • Sort.Direction is used to define the sorting direction for sorting operations in database queries, especially when querying data through Spring Data repositories or services.

Enum Constants:

  • Sort.Direction consists of two enum constants:
  • ASC: Represents ascending order.
  • DESC: Represents descending order.

Key Points:

  • Sort.Direction provides a clear and standardized way to define sorting order within Spring Data repositories or services.
  • It helps in maintaining consistency and readability in sorting criteria used across different parts of the application.

Modify PostService interface

 PostResponse getAllPost(int pageNo, int pageSize, String sortBy, String sortDir);

Modify PostServiceImplementation class

 @Override
public PostResponse getAllPost(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortBy).ascending()
: Sort.by(sortBy).descending();

// Sorting Support
Pageable pageable = PageRequest.of(pageNo, pageSize, sort);

// Retrieve a page of posts
Page<Post> postList = postRepository.findAll(pageable);
// Get content for page object
List<Post> listOfPost = postList.getContent();

List<PostDto> content = listOfPost.stream().map(post -> modelMapper.map(post, PostDto.class)).collect(Collectors.toList());

PostResponse postResponse = new PostResponse();
postResponse.setContent(content);
postResponse.setPageNo(postList.getNumber());
postResponse.setPageSize(postList.getSize());
postResponse.setTotalElements(postList.getTotalElements());
postResponse.setTotalPages(postList.getTotalPages());
postResponse.setLast(postList.isLast());
return postResponse;
}
  • sortDir.equalsIgnoreCase(Sort.Direction.ASC.name()) checks if the provided sortDir string is case-insensitively equal to the string representation of Sort.Direction.ASC.
  • If the comparison is true:
  • It creates a Sort object in ascending order based on the specified sortBy field using Sort.by(sortBy).ascending().
  • If the comparison is false:
  • It creates a Sort object in descending order based on the specified sortBy field using Sort.by(sortBy).descending().

Modify PostController class

   @GetMapping
public PostResponse getAllPost(
@RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
@RequestParam(value = "pageSize", defaultValue = "10", required = false) int pageSize,
@RequestParam(value = "sortBy", defaultValue = "id", required = false) String sortBy,
@RequestParam(value = "sortDir", defaultValue = "asc", required = false) String sortDir
) {
return postService.getAllPost(pageNo, pageSize, sortBy, sortDir);
}

Thank you for taking the time to read my article until the end. I sincerely hope that you have gained valuable insights and knowledge from it. If you found the article enjoyable and informative, I kindly ask you to share it with your friends and colleagues.

Once again, thank you for your time and support. Stay tuned for more articles and updates as I embark on this exciting Java and Spring adventure.

Github repo: https://github.com/LuisSalas94/Pagination-and-Sorting-in-Spring-Boot

💖 Say 👋 to me!

Fernando Salas

Email: luisfernandosalasg@gmail.com

LinkedIn: https://www.linkedin.com/in/luisfernandosalasgave/

GitHub: https://github.com/LuisSalas94

Medium: https://medium.com/@luisfernandosalasg

Buymeacoffee: https://www.buymeacoffee.com/luisfernanM

Check out my other articles:

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.

Published in Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

Written by Fernando Salas

Java Backend Developer | Tech Writer @Stackademic

No responses yet

Write a response