Data pagination and sorting in Spring

There are many situations where your data set size could influence overall application performance - slow down the browser or backend response. In these situations, you should somehow split your data into chunks. The best way to do this is by using pagination where instead of the whole dataset that corresponds to some query, your service returns the subset of it. The amount of data this subset contains is defined by parameters that describe interval and sorting type.   

One of the easiest ways to achieve pagination and sorting in Spring is to use pagination features from Spring Data JPA library - using Page, Slice or List object as return type. In this article, we'll show a code sample where we implemented pagination. 

Implementation

In this code sample, we'll search for items that belong to a specific tenant - we'll search by tenantId and we will return a paginated response.

Controller method:

@GetMapping("/items")
	public Page<Item> getItems(@RequestParam(name="tenantId", required=true) Long tenantId,
RequestParam(name = "page", required = false) Integer page,
			@RequestParam(name = "size", required = false) Integer size,
			@RequestParam(name = "sortOrder", required = false) String sortOrder,
			@RequestParam(name = "sortParam", required = false) String sortParam) {
          Pageable pageable = PageRequest.of(page, size, Sort.by( Direction.fromString(sortOrder), sortParam));
          return itemsRepository.findByTenantId(tenantId, pageable);
	}

Parameters you see here are:

  • page - page number
  • size - number of items you want to return
  • sortOrder - ASC or DESC
  • sortParam - parameter by which you want to sort returned items

Sort parameters are not mandatory to achieve pagination but they can help you to more precisely define the resulting set.  

Repository method:

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.items.model.Item;

@Repository
public interface ItemsRepository extends JpaRepository<Item, Long> {
	public Page<Item> findByTenantId(Long tenantId, Pageable pageable);
}

As you can see, we return Page object, but we could also return List and Slice. The main differences between these return types are:

  • Page has information about the total number of pages stored in totalPages field in return object. This means that if you're returning Page object you have one additional query that does a count for you. If you consider this too expensive operation, you can use Slice or List return type.  
  • Slice has information about whether the next or previous object exists or not. This is not as expensive as Page object and it could be sufficient for navigation through bigger datasets.
  • List is just a list of items, without any additional info.