├── 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 | --------------------------------------------------------------------------------