# Pagination in Spring Boot REST APIs with H2 Database

In this article, you are going to learn how to create pagination in the spring Boot REST API and how you can use it in your project. The code is very generic so you can use any RDBMS instead of the H2 database. For simplicity, I have used the H2 database.

Let us begin and start coding, we open Spring Initializr from https://start.spring.io/ and add the below dependencies. Click on Generate and after the project downloads, we open it in our IDE/editor of choice (I am using VSCode). You can use vscode to generate spring boot project as well.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657596523951/VwzKbZ_Ml.png align="left")

and the project structure looks like below.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1657596781260/rxC-E0T16.png align="left")

Let's start coding.

**application.properties:**

In application properties, we have added data source properties and the spring boot application name.

```

spring.application.name=pagination-springboot
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:customer
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.driver-class-name=org.h2.Driver
server.port=9010

``` 

**Customer.java**
Let us create an entity that helps to represent the same structure as a table. We try to demonstrate things with minimal fields so that we can concentrate on pagination.

```
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.Date;
import java.util.UUID;

@Entity
@Table(name="customer")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Customer{

    @Id
    @GeneratedValue()
    private UUID id;

    @Column(nullable = false)
    private String userId;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false)
    private String mobileno;

    private Date createdDate;

    @Column(nullable = false)
    private String createdBy;

    private Date updatedDate;

}

``` 

**CustomerDTO.java**
Let us create customerDTO that helps to transfer data.


```
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.UUID;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CustomerDTO {

    private UUID id;

    private String userId;

    @NotNull(message = "name cannot be empty")
    private String name;

   @NotNull(message="mobile number cannot be empty")
    private String mobileno;

    private Date createdDate;

    private Date updatedDate;

    private String createdBy;

}

``` 

**CustomerRespositoy.java**
Let us create a repository interface by extending ```JpaRepository```  that helps to do CRUD operations on a database


```
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface CustomerRepository extends JpaRepository <Customer, UUID> {

    Optional<List<Customer>> findAllByUserId(String userId, Pageable page);
}

``` 

**CustomerService.java**

The saveCustomer() saves new customer records. We call Spring Data JPAs save() method to save a new customer. The getAllCustomers() retrieves all customers from the database. We pass an argument of type Pageable when we make a call to Spring Data JPA’s findAll() method.

```
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
public class CustomerService {

    @Autowired
    CustomerRepository customerRepository;

    public void saveCustomer(CustomerDTO customerDTO) {
        Customer customer= Customer
                .builder()
                .name(customerDTO.getName())
                .mobileno(customerDTO.getMobileno())
                .createdDate(new Date())
                .createdBy(customerDTO.getCreatedBy())
                .userId(customerDTO.getUserId())
                .build();
        customerRepository.save(customer);
    }

    public List<CustomerDTO> getAllCustomers(Pageable paging){
        
        Iterable<Customer> customers= 
                customerRepository.findAll(paging);
        List<CustomerDTO> customersDTO = new ArrayList<>();

        customers.forEach( customer -> {
            customersDTO.add(CustomerDTO
                    .builder()
                    .id(customer.getId())
                    .userId(customer.getUserId())
                    .name(customer.getName())
                    .mobileno(customer.getMobileno())
                    .createdBy(customer.getCreatedBy())
                    .createdDate(customer.getCreatedDate())
                    .build());
        });

        return customersDTO;
    }

    
public List<CustomerDTO> getCustomersByUserId(
            String userId, 
            Pageable page) {
       Optional<List<Customer>> customers =  
      customerRepository.findAllByUserId(userId, page);
      
      if (customers.isPresent()) {
          return customers.get()
                   .stream()
                   .map( customer ->  CustomerDTO.builder()
                       .id(customer.getId())
                       .name(customer.getName())
                       .mobileno(customer.getMobileno())
                       .userId(customer.getUserId())
                       .createdBy(customer.getCreatedBy())
                       .createdDate(customer.getCreatedDate())
                       .build())
                   .collect(Collectors.toList());

       }
       return null;
    }
}

``` 

** CustomerController.java**
Controller class that controls the request and response. The controller class is annotated with ```RestController``` and ```@RequestMapping(“/customers”)```.

The createCustomer() method saves new customer to the database and the ```getCustomers()```method retrieves all customers. We define two parameters annotated with ```@RequestParams``` called page and pageSize.

The **page** parameter determines which page is to be returned as part of pagination. The first page is considered to be 0, and then incremented by one for subsequent pages. The default value is 0, which is the first page.

The **pageSize ** parameter determines how many records will be returned for that particular page. We set a default value of 5. Both page and pageSize are optional, which means that if not present in our API request, the default values will be considered. You can define a **Pageable** variable with the page and pageSize parameters. This variable is used to query our database with the pagination details that you have to pass in the ```RequestParams``` annotated parameters page and pageSize.

```Pageable paging  = PageRequest.of(page, pageSize);```

The final method getCustomersByUser() retrieves all customers made by a user. This method also has pagination implemented similar to the getCustomers() method.


```
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("/customers")
@CrossOrigin(origins = "http://localhost:3000/")
public class CustomersController {


    @Autowired
    CustomerService customerService;

    @PostMapping(
            consumes = {
                    MediaType.APPLICATION_JSON_VALUE ,
                    MediaType.APPLICATION_XML_VALUE},
            produces= {
                    MediaType.APPLICATION_JSON_VALUE ,
                    MediaType.APPLICATION_XML_VALUE
            })
    public ResponseEntity<CustomerDTO> creatCustomer(
     @Valid @RequestBody CustomerDTO customerDTO
    ) throws Exception {
        
        customerDTO.setCreatedDate(new Date());
        customerService.saveCustomer(customerDTO);
        
        return new ResponseEntity<>(customerDTO, HttpStatus.CREATED);
    }

    @GetMapping(
            consumes = {
                    MediaType.APPLICATION_JSON_VALUE ,
                    MediaType.APPLICATION_XML_VALUE},
            produces= {
                    MediaType.APPLICATION_JSON_VALUE ,
                    MediaType.APPLICATION_XML_VALUE
            })
    public ResponseEntity<List<CustomerDTO>> getCustomers(
           @RequestParam(defaultValue = "5", required = false) 
                  Integer pageSize,
           @RequestParam(defaultValue = "0", required = false) 
                  Integer page
    ) throws Exception {

        Pageable paging  = PageRequest.of(page, pageSize);
       
        List<CustomerDTO> customersDTO=   
              customerService.getAllCustomers(paging);
        
        return new ResponseEntity<>(
              customersDTO, HttpStatus.CREATED);
    }

    @GetMapping(
            path = "/user/{userId}",
            consumes = {
                    MediaType.APPLICATION_JSON_VALUE ,
                    MediaType.APPLICATION_XML_VALUE
            },
            produces = {
                    MediaType.APPLICATION_JSON_VALUE,
                    MediaType.APPLICATION_XML_VALUE
            })
    public ResponseEntity<List<CustomerDTO>> getCustomersByUserId(
            @PathVariable String userId,
            @RequestParam(defaultValue= "0", required = false)
                   Integer page ,
            @RequestParam(defaultValue= "5", required = false) 
                   Integer pageSize 
   ) throws Exception {
        Pageable paging = PageRequest.of(page, pageSize);
        
        List<CustomerDTO> customersDTOs= 
               customerService.getCustomersByUserId(userId, paging);
        
        return new ResponseEntity<List<CustomerDTO>>( 
               customersDTOs, HttpStatus.ACCEPTED);
    }

}

``` 

Now let us run the application and hit the URL http://localhost:9010.
Let us verify the database by accessing h2 console by hitting the [http://localhost:9010/h2-console](http://localhost:9010/h2-console) and logging in by the credentials provided in the properties file. 


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1659115400536/a0flItDoB.png align="left")

Now let's push some records using the postman tool or any tool of your choice,


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1659115508175/aKMm-akpc.png align="left")

 Insert some records in the table by using the post endpoint and verify by running a select query like below.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1659115781573/mgQSbFsrY.png align="left")

**Pagination Retrieve records:**
Retrieve records using the GET HTTP verb with same URL endpoint.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1659116092164/v6wzUtC3r.png align="left")

If we make the below API GET request, we can see that five customers are returned. The default values of page=0 and pageSize=5. Hence it returns five records even though we have mentioned any page size or page number. If you provide the next page size in the request param then you will get the next page. The best thing about this implementation is that you can provide page size based on client requirements some may provide 10 or 100 or any number that suits. 

http://localhost:9010/customers?page=1&pageSize=5.

If records are not available on that page then it will return the empty JSON array.

# Conclusion:
In this article, we have discussed pagination in spring boot REST API, an easy way we can pagination implementation with a database, you can same code to have pagination on any database such as MySQL, Oracle or PostgreSQL, etc.

# Source Code:

```
$ git  clone https://github.com/maheshwarLigade/spring-boot-examples/tree/main/h2paginationdemo

cd h2paginationdemo

gradle build

``` 


**More such articles:**

[https://medium.com/techwasti](Link)

[https://www.youtube.com/channel/UCiTaHm1AYqMS4F4L9zyO7qA](Link)

[https://www.techwasti.com/](Link)

==========================**=========================

**If this article adds any value for you then please clap and comment.**

**Let’s connect on [Stackoverflow](http://stackoverflow.com/users/3187349/maheshwar-ligade), [LinkedIn](https://in.linkedin.com/in/maheshwar-ligade-14447841), & [Twitter](https://twitter.com/MaheshwarLigade).**


