├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── javatechie
│ │ └── reactive
│ │ ├── SpringReactiveMongoCrudApplication.java
│ │ ├── controller
│ │ └── ProductController.java
│ │ ├── dto
│ │ └── ProductDto.java
│ │ ├── entity
│ │ └── Product.java
│ │ ├── repository
│ │ └── ProductRepository.java
│ │ ├── service
│ │ └── ProductService.java
│ │ └── utils
│ │ └── AppUtils.java
└── resources
│ ├── application.properties
│ └── application.yml
└── test
└── java
└── com
└── javatechie
└── reactive
└── SpringReactiveMongoCrudApplicationTests.java
/README.md:
--------------------------------------------------------------------------------
1 | # spring-reactive-mongo-crud
2 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.4.5
9 |
10 |
11 | com.javatechie
12 | spring-reactive-mongo-crud
13 | 0.0.1-SNAPSHOT
14 | spring-reactive-mongo-crud
15 | Demo project for Spring Boot
16 |
17 | 1.8
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-mongodb-reactive
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-webflux
27 |
28 |
29 |
30 | org.projectlombok
31 | lombok
32 | true
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-test
37 | test
38 |
39 |
40 | de.flapdoodle.embed
41 | de.flapdoodle.embed.mongo
42 | test
43 |
44 |
45 | io.projectreactor
46 | reactor-test
47 | test
48 |
49 |
50 | junit
51 | junit
52 | test
53 |
54 |
55 |
56 |
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-maven-plugin
61 |
62 |
63 |
64 | org.projectlombok
65 | lombok
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/SpringReactiveMongoCrudApplication.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SpringReactiveMongoCrudApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SpringReactiveMongoCrudApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/controller/ProductController.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.controller;
2 |
3 | import com.javatechie.reactive.dto.ProductDto;
4 | import com.javatechie.reactive.service.ProductService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.*;
7 | import reactor.core.publisher.Flux;
8 | import reactor.core.publisher.Mono;
9 |
10 | @RestController
11 | @RequestMapping("/products")
12 | public class ProductController {
13 |
14 | @Autowired
15 | private ProductService service;
16 |
17 | @GetMapping
18 | public Flux getProducts(){
19 | return service.getProducts();
20 | }
21 |
22 | @GetMapping("/{id}")
23 | public Mono getProduct(@PathVariable String id){
24 | return service.getProduct(id);
25 | }
26 |
27 | @GetMapping("/product-range")
28 | public Flux getProductBetweenRange(@RequestParam("min") double min, @RequestParam("max")double max){
29 | return service.getProductInRange(min,max);
30 | }
31 |
32 | @PostMapping
33 | public Mono saveProduct(@RequestBody Mono productDtoMono){
34 | System.out.println("controller method called ...");
35 | return service.saveProduct(productDtoMono);
36 | }
37 |
38 | @PutMapping("/update/{id}")
39 | public Mono updateProduct(@RequestBody Mono productDtoMono,@PathVariable String id){
40 | return service.updateProduct(productDtoMono,id);
41 | }
42 |
43 | @DeleteMapping("/delete/{id}")
44 | public Mono deleteProduct(@PathVariable String id){
45 | return service.deleteProduct(id);
46 | }
47 |
48 |
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/dto/ProductDto.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @AllArgsConstructor
9 | @NoArgsConstructor
10 | public class ProductDto {
11 |
12 | private String id;
13 | private String name;
14 | private int qty;
15 | private double price;
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/entity/Product.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.entity;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import org.springframework.data.annotation.Id;
7 | import org.springframework.data.mongodb.core.mapping.Document;
8 |
9 | @Data
10 | @AllArgsConstructor
11 | @NoArgsConstructor
12 | @Document(collection = "products")
13 | public class Product {
14 | @Id
15 | private String id;
16 | private String name;
17 | private int qty;
18 | private double price;
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/repository/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.repository;
2 |
3 | import com.javatechie.reactive.dto.ProductDto;
4 | import com.javatechie.reactive.entity.Product;
5 | import org.springframework.data.domain.Range;
6 | import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
7 | import org.springframework.stereotype.Repository;
8 | import reactor.core.publisher.Flux;
9 |
10 | @Repository
11 | public interface ProductRepository extends ReactiveMongoRepository {
12 | Flux findByPriceBetween(Range priceRange);
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/service/ProductService.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.service;
2 |
3 | import com.javatechie.reactive.dto.ProductDto;
4 | import com.javatechie.reactive.entity.Product;
5 | import com.javatechie.reactive.repository.ProductRepository;
6 | import com.javatechie.reactive.utils.AppUtils;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.data.domain.Range;
9 | import org.springframework.stereotype.Service;
10 | import reactor.core.publisher.Flux;
11 | import reactor.core.publisher.Mono;
12 |
13 | @Service
14 | public class ProductService {
15 |
16 | @Autowired
17 | private ProductRepository repository;
18 |
19 |
20 | public Flux getProducts(){
21 | return repository.findAll().map(AppUtils::entityToDto);
22 | }
23 |
24 | public Mono getProduct(String id){
25 | return repository.findById(id).map(AppUtils::entityToDto);
26 | }
27 |
28 | public Flux getProductInRange(double min,double max){
29 | return repository.findByPriceBetween(Range.closed(min,max));
30 | }
31 |
32 | public Mono saveProduct(Mono productDtoMono){
33 | System.out.println("service method called ...");
34 | return productDtoMono.map(AppUtils::dtoToEntity)
35 | .flatMap(repository::insert)
36 | .map(AppUtils::entityToDto);
37 | }
38 |
39 | public Mono updateProduct(Mono productDtoMono,String id){
40 | return repository.findById(id)
41 | .flatMap(p->productDtoMono.map(AppUtils::dtoToEntity)
42 | .doOnNext(e->e.setId(id)))
43 | .flatMap(repository::save)
44 | .map(AppUtils::entityToDto);
45 |
46 | }
47 |
48 | public Mono deleteProduct(String id){
49 | return repository.deleteById(id);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/javatechie/reactive/utils/AppUtils.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive.utils;
2 |
3 | import com.javatechie.reactive.dto.ProductDto;
4 | import com.javatechie.reactive.entity.Product;
5 | import org.springframework.beans.BeanUtils;
6 |
7 | public class AppUtils {
8 |
9 |
10 | public static ProductDto entityToDto(Product product) {
11 | ProductDto productDto = new ProductDto();
12 | BeanUtils.copyProperties(product, productDto);
13 | return productDto;
14 | }
15 |
16 | public static Product dtoToEntity(ProductDto productDto) {
17 | Product product = new Product();
18 | BeanUtils.copyProperties(productDto, product);
19 | return product;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | data:
3 | mongodb:
4 | database: Productsdb
5 | host: localhost
6 | port: 27017
7 |
8 |
9 | server:
10 | port: 9292
--------------------------------------------------------------------------------
/src/test/java/com/javatechie/reactive/SpringReactiveMongoCrudApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.javatechie.reactive;
2 |
3 | import com.javatechie.reactive.controller.ProductController;
4 | import com.javatechie.reactive.dto.ProductDto;
5 | import com.javatechie.reactive.service.ProductService;
6 | import org.junit.jupiter.api.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.boot.test.mock.mockito.MockBean;
12 | import org.springframework.test.context.junit4.SpringRunner;
13 | import org.springframework.test.web.reactive.server.WebTestClient;
14 | import reactor.core.publisher.Flux;
15 | import reactor.core.publisher.Mono;
16 | import reactor.test.StepVerifier;
17 |
18 | import static org.mockito.ArgumentMatchers.any;
19 | import static org.mockito.BDDMockito.given;
20 | import static org.mockito.Mockito.when;
21 |
22 | @RunWith(SpringRunner.class)
23 | @WebFluxTest(ProductController.class)
24 | class SpringReactiveMongoCrudApplicationTests {
25 | @Autowired
26 | private WebTestClient webTestClient;
27 | @MockBean
28 | private ProductService service;
29 |
30 | @Test
31 | public void addProductTest(){
32 | Mono productDtoMono=Mono.just(new ProductDto("102","mobile",1,10000));
33 | when(service.saveProduct(productDtoMono)).thenReturn(productDtoMono);
34 |
35 | webTestClient.post().uri("/products")
36 | .body(Mono.just(productDtoMono),ProductDto.class)
37 | .exchange()
38 | .expectStatus().isOk();//200
39 |
40 | }
41 |
42 |
43 | @Test
44 | public void getProductsTest(){
45 | Flux productDtoFlux=Flux.just(new ProductDto("102","mobile",1,10000),
46 | new ProductDto("103","TV",1,50000));
47 | when(service.getProducts()).thenReturn(productDtoFlux);
48 |
49 | Flux responseBody = webTestClient.get().uri("/products")
50 | .exchange()
51 | .expectStatus().isOk()
52 | .returnResult(ProductDto.class)
53 | .getResponseBody();
54 |
55 | StepVerifier.create(responseBody)
56 | .expectSubscription()
57 | .expectNext(new ProductDto("102","mobile",1,10000))
58 | .expectNext(new ProductDto("103","TV",1,50000))
59 | .verifyComplete();
60 |
61 | }
62 |
63 |
64 | @Test
65 | public void getProductTest(){
66 | Mono productDtoMono=Mono.just(new ProductDto("102","mobile",1,10000));
67 | when(service.getProduct(any())).thenReturn(productDtoMono);
68 |
69 | Flux responseBody = webTestClient.get().uri("/products/102")
70 | .exchange()
71 | .expectStatus().isOk()
72 | .returnResult(ProductDto.class)
73 | .getResponseBody();
74 |
75 | StepVerifier.create(responseBody)
76 | .expectSubscription()
77 | .expectNextMatches(p->p.getName().equals("mobile"))
78 | .verifyComplete();
79 | }
80 |
81 |
82 | @Test
83 | public void updateProductTest(){
84 | Mono productDtoMono=Mono.just(new ProductDto("102","mobile",1,10000));
85 | when(service.updateProduct(productDtoMono,"102")).thenReturn(productDtoMono);
86 |
87 | webTestClient.put().uri("/products/update/102")
88 | .body(Mono.just(productDtoMono),ProductDto.class)
89 | .exchange()
90 | .expectStatus().isOk();//200
91 | }
92 |
93 | @Test
94 | public void deleteProductTest(){
95 | given(service.deleteProduct(any())).willReturn(Mono.empty());
96 | webTestClient.delete().uri("/products/delete/102")
97 | .exchange()
98 | .expectStatus().isOk();//200
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------