Are you a backend developer looking to build a powerful pagination and sorting system for your Rest API?
Look no further than this tutorial on Spring Boot Pagination and Sorting. In this article, I’ll walk you through the steps of building and adapting API endpoints to support pagination and sorting.
This article is part 1 of a series of 2 articles, where, in the second one, I showed you how to write testing code for pagination and sorting with spring boot and JPA, check it out down below ↓
So, in this part 1 which is focused on production code, you'll learn how to create a structured response via your API and how to run a successful demo project. Follow along, and you'll be implementing pagination and sorting in no time.
Prerequisite
In order to follow this tutorial, you will need:
- Java 10+ version (for type inference with var keyword)
- Maven 3+
- An HTTP client such as curl or Postman
What is Pagination and Sorting
Pagination and sorting mechanism is a common feature asked backend developers to build in their day-to-day task. You’ll then adapt your API endpoints to support pagination and sorting.
The pagination mechanism returns a specific range of resources, and the sorting mechanism places the resources in order.
To maintain a certain consistency, and for ease of understanding, I've decided to use layered architecture for most of my Spring Boot step-by-step types of tutorials. I’ve made an article about spring boot architecture and how it is designed, you can check it out down below ↓
Now that I’ve set this reminder, we can continue on this tutorial.
Practice
First thing first, you will need to create a spring boot project. You can do it by downloading one on the spring initialzr website. Once you have clicked on GENERATE, download the project and open it in your IDE.
Personally, I use IntelliJ IDEA Ultimate, it’s a pretty good one.
For this demo, we will expose a GET
request with the /students
endpoint that will return an array of students and information about the pagination. The database schema of the student will look like something like this.
The following URL shows these default pagination and sorting parameters in an explicit form.
/students?pageNumber=1&size=10&sort=name&direction=ASC
Dependency
To run this demo project well, you will need these dependencies. I choose to use Lombok to avoid repetitive Getter, Setter and toString methods in our classes.
<!-- Tutorials dependencies -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.1</version>
</dependency>
<!-- End of dependencies -->
Entity
We will use Hibernate to define the model of the entity in Java, and it will create the SQL-related queries for DDL. You can create a package named entity and create a Student
class.
@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(unique = true, nullable = false, updatable = false)
private UUID id;
private String name;
private int age;
private String address;
}
Database Configuration
For this demo, I use PostgreSQL as a database launched in a docker container. If you want to know to achieve that, I have made a short tutorial to do so. Check it up here ↓
Now let’s add the configuration of our database, so that hibernate can connect and perform the database creation. In the src/main/resources/application.yml
add the following code.
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://localhost:5432/tutos
username: tuto
password: admingres
jpa:
show-sql: true
open-in-view: false
hibernate:
ddl-auto: create
properties:
hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
logging:
level:
org.springframework: warn
org.hibernate.type: trace
server:
port: 8000
create
first.Then set the value of the property spring.jpa.hibernate.ddl-auto to
validate
after the tables are created to prevent them from being deleted and then re-created when starting the application.Repository
Create a package called repository, then create a class StudentRepository
and add the code below.
@Repository
public interface StudentRepository extends PagingAndSortingRepository<Student, UUID>,
CrudRepository<Student, UUID> {}
Service
Create a package called service, then create a class StudentService
and add the code below.
@Service
@RequiredArgsConstructor
public class StudentService {
private final StudentRepository repository;
public ResponseModel findAllStudents(PageRequest pageable) {
var studentsPage= this.repository.findAll(pageable);
return buildResponse(studentsPage);
}
private ResponseModel buildResponse(Page studentsPage){
return ResponseModel.builder()
.pageNumber(studentsPage.getNumber() + 1)
.pageSize(studentsPage.getSize())
.totalElements(studentsPage.getTotalElements())
.totalPages(studentsPage.getTotalPages())
.students(studentsPage.toList())
.isLastPage(studentsPage.isLast())
.build();
}
}
Given that we want to return a structured response via our API, we will create a ResponseModel
class. So create a package model and add the code below.
@Builder
@Getter
public class ResponseModel {
private final List<Student> students;
private final int pageNumber;
private final int pageSize;
private final long totalElements;
private final int totalPages;
private final boolean isLastPage;
}
Controller
Create a package controller and a file StudentController
and add the code below.
@Controller
@RequiredArgsConstructor
public class StudentController {
private final StudentService service;
@GetMapping("/students")
public ResponseEntity<ResponseModel> fetchAllStudents(
@RequestParam(name = "pageNumber", required = false, defaultValue = "1") int pageNumber,
@RequestParam(name = "size", required = false, defaultValue = "10") int size,
@RequestParam(name = "sort", required = false, defaultValue = "name") String sort,
@RequestParam(name = "direction", required = false, defaultValue = "ASC") String direction
) {
var pageRequestData = PageRequest.of(pageNumber - 1, size, Sort.Direction.valueOf(direction), sort);
return new ResponseEntity<>(service.findAllStudents(pageRequestData), HttpStatus.PARTIAL_CONTENT);
}
}
Demonstration
Before diving into the demonstration, we have to create an AppRunner
class which will load data in the database each time the application starts. Create that class and add the code below
@Component
@RequiredArgsConstructor
public class AppRunner implements CommandLineRunner {
public static final int MAX_AGE = 26;
public static final int MIN_AGE = 17;
private static int NUMBER_OF_STUDENTS = 45;
private final StudentRepository repository;
@Override
public void run(String... args) {
var faker = new Faker(new Locale("fr"));
var students = new ArrayList<Student>();
while (NUMBER_OF_STUDENTS > 0) {
var student = Student.builder()
.name(faker.name().fullName())
.age(new Random().nextInt(MAX_AGE - MIN_AGE) + MIN_AGE)
.address(faker.address().fullAddress())
.build();
students.add(student);
NUMBER_OF_STUDENTS--;
}
repository.saveAll(students);
}
}
We annotated this class with @Component
so that spring will detect it when it launches the application context.
Spring ApplicationContext is where Spring holds instances of objects that it has identified to be managed and distributed automatically. These are called beans.
Spring collects bean instances from our application and uses them at the appropriate time. To tell Spring about the custom beans we want it to manage for us, we use stereotype annotations like @Component.
Once we have configured all the parts of our app, we can run it, with this command.
$ mvn spring-boot:start
Now open an app to perform the GET request, personally I use Postman. (Use 1080p in view settings ⚙️)
Now enter parameters explicitly to perform the GET request
Once you have finished to test your Rest API, you can now stop the spring application running in the background.
$ mvn spring-boot:stop
I hope you enjoyed reading this, and I'm curious to hear if this tutorial helped you. Please let me know your thoughts below in the comments. Don't forget to subscribe to my newsletter to avoid missing my upcoming blog posts.
You can also find me here LinkedIn • Twitter • GitHub or Medium
Wrap Up
Spring Boot Pagination and Sorting is a common feature asked in many enterprises projects. In this tutorial, you have all the things required to build a powerful pagination and sorting system for your Rest API.
You can find all the code of this tutorial on my GitHub repository.
Thanks so much for reading, I hope you found it useful.