In this tutorial, we will learn how to create a Spring boot project with CRUD operations using Reactive Programming through Spring Data Reactive Repositories with MongoDB.
Java
MongoDB
Spring Boot
Source code of this tutorial is available on our GitHub repository at https://github.com/sourcecodeexamples/spring-reactive-mongo-crud
In order to use Reactive MongoDB, we need to add the dependency to our pom.xml.
We'll also add an embedded MongoDB for testing:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
Let's create a step-by-step Spring boot project from scratch that uses Reactive MongoDB.
1. Create Spring Boot Project
We’ll use Spring initializr web tool to bootstrap our application.
Go to http://start.spring.io
Select Java in the language section.
Artifact: spring-boot-crud-example
Dependencies: Reactive, Lombok, JPA, and Embedded Mongo Database.
Package name: com.springboot.reactive
Click Generate to generate and download the project.
Once the project is generated, unzip it and import it into your favorite IDE.
2. Maven Dependencies
Open the pom.xml file and confirm below dependencies are present:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</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>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
3. Configure MongoDB
Let's first create a products database in the MongoDB server.
Then, open the application.yml file and add the following code to it:
spring:
data:
mongodb:
database: Productsdb
host: localhost
port: 27017
server:
port: 9292
4. Create Model Layer
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "products")
public class Product {
@Id
private String id;
private String name;
private int qty;
private double price;
}
5. Create Repository Layer
import com.springboot.reactive.dto.ProductDto;
import com.springboot.reactive.entity.Product;
import org.springframework.data.domain.Range;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
@Repository
public interface ProductRepository extends ReactiveMongoRepository<Product,String> {
Flux<ProductDto> findByPriceBetween(Range<Double> priceRange);
}
6. Create Service Layer
import com.springboot.reactive.dto.ProductDto;
import com.springboot.reactive.entity.Product;
import com.springboot.reactive.repository.ProductRepository;
import com.springboot.reactive.utils.AppUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Range;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class ProductService {
@Autowired
private ProductRepository repository;
public Flux<ProductDto> getProducts(){
return repository.findAll().map(AppUtils::entityToDto);
}
public Mono<ProductDto> getProduct(String id){
return repository.findById(id).map(AppUtils::entityToDto);
}
public Flux<ProductDto> getProductInRange(double min,double max){
return repository.findByPriceBetween(Range.closed(min,max));
}
public Mono<ProductDto> saveProduct(Mono<ProductDto> productDtoMono){
System.out.println("service method called ...");
return productDtoMono.map(AppUtils::dtoToEntity)
.flatMap(repository::insert)
.map(AppUtils::entityToDto);
}
public Mono<ProductDto> updateProduct(Mono<ProductDto> productDtoMono,String id){
return repository.findById(id)
.flatMap(p->productDtoMono.map(AppUtils::dtoToEntity)
.doOnNext(e->e.setId(id)))
.flatMap(repository::save)
.map(AppUtils::entityToDto);
}
public Mono<Void> deleteProduct(String id){
return repository.deleteById(id);
}
}
7. Create DTO Class
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductDto {
private String id;
private String name;
private int qty;
private double price;
}
8. DTO to Entity Converter Class
import com.springboot.reactive.dto.ProductDto;
import com.springboot.reactive.entity.Product;
import org.springframework.beans.BeanUtils;
public class AppUtils {
public static ProductDto entityToDto(Product product) {
ProductDto productDto = new ProductDto();
BeanUtils.copyProperties(product, productDto);
return productDto;
}
public static Product dtoToEntity(ProductDto productDto) {
Product product = new Product();
BeanUtils.copyProperties(productDto, product);
return product;
}
}
9. Controller Layer
import com.springboot.reactive.dto.ProductDto;
import com.springboot.reactive.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductService service;
@GetMapping
public Flux<ProductDto> getProducts(){
return service.getProducts();
}
@GetMapping("/{id}")
public Mono<ProductDto> getProduct(@PathVariable String id){
return service.getProduct(id);
}
@GetMapping("/product-range")
public Flux<ProductDto> getProductBetweenRange(@RequestParam("min") double min, @RequestParam("max")double max){
return service.getProductInRange(min,max);
}
@PostMapping
public Mono<ProductDto> saveProduct(@RequestBody Mono<ProductDto> productDtoMono){
System.out.println("controller method called ...");
return service.saveProduct(productDtoMono);
}
@PutMapping("/update/{id}")
public Mono<ProductDto> updateProduct(@RequestBody Mono<ProductDto> productDtoMono,@PathVariable String id){
return service.updateProduct(productDtoMono,id);
}
@DeleteMapping("/delete/{id}")
public Mono<Void> deleteProduct(@PathVariable String id){
return service.deleteProduct(id);
}
}
10. Run Spring Boot Application
We’ve successfully built all the APIs for our application. Let’s now run the app and test the APIs.
Just go to the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
Spring Boot application running on a server on port 9292.
11. REST APIs Details for Testing
Use below endpoint URLs for testing CRUD REST APIs.
Create new Product:
URL - http ://localhost:8080/products
HTTP Method - POST
HTTP Method - POST
Get All Products:
URL - http ://localhost:8080/products
HTTP Method - GET
HTTP Method - GET
Update existing Product:
URL - http ://localhost:8080/products/update/{id}
HTTP Method - PUT
HTTP Method - PUT
Delete existing Product:
URL - http ://localhost:8080/products/delete/{id}
HTTP Method - DELETE
HTTP Method - DELETE
12. Source Code on GitHub
Source code of this tutorial is available on our GitHub repository at https://github.com/sourcecodeexamples/spring-reactive-mongo-crud
Comments
Post a Comment