Sunday, December 15, 2019

Spring Webflux with MongoDB

Objective:

The objective of this tutorial is to develop a sample MonogoDB application using Spring Webflux.

Pre-requisites:

The following softwares are to be installed on your machine for this code to work:

  • JDK 11 or Open JDK 11
  • Maven

GitHub links:

The source code covered in this tutorial is available in the following link in GitHub.

Steps:

1. Go to https://start.spring.io/ and enter the following details (as shown in the screenshot below).
Group: com.narayan.reactive
Artifact: reactive-mongo-sample
Java: 11 (under Options)
Dependencies: Spring Data Reactive MongoDB, Spring Reactive Web
and click "Generate Project" button.





2. Now import the project into any IDE like IntelliJ OR Eclipse etc. Once the project is imported, open the pom.xml to make sure that the following dependencies are already listed.

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

spring-boot-starter-webflux is to bring all the Spring Webflux library dependencies and 
spring-boot-starter-data-mongodb-reactive is to bring all the Reactive MongoDB dependencies

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>

Additionally add the Lombok dependency to auto-generate the getters and setters for model classes.

Model Classes:
3. Create a new package called "model" under "com.narayan.reactive.reactivemongosample" and create a new class called Employee and EmployeeEvent

4. Employee.java - is the model we want to persist to Mongo DB


Employee Model class has id, name, and salary which we want to persist in MongoDB. The following are the various annotations used in this Model class:

@Document (line 12)- This annotation marks a class as being a domain object that we want to persist to the Mongo database
@Id (line 15)- This annotation specifies the primary key of an entity

Lombok Annotations:
@AllArgsConstructor (line 9) - This annotation will generate a constructor with 1 parameter for each field in your class. 
@NoArgsConstructor (line 10) - This annotation will generate a constructor with no parameters
@Data (line 11) -  This annotation will  generate all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans - like getters, setters, appropriate toString, equals and hashCode implementations 

 5. EmployeeEvent,java is an event class which we want to use it for Event Stream, which will have the Employee object and the Date time. This will be used in Flux to generate the event stream, which will be used in /


Repository Class:
7. Now create a new package called "repository" and create a new Java class called EmployeeRepository.java, which will act as Mongo DB Repository interface which will extend ReactiveMongoRepository.java with parameters as Employee and String.


Main Class:
8. This class will insert 4 records during Server Startup. This class has @Bean annotation with CommandLineRunner return type which indicates that the logic inside this method will be executed first during ServerStartup. This method will delete all the records from MongoDB using deleteAll() method, followed by subscribe() method, which in turn create a Stream of 4 employees and save them to the database using save() method and also print the same in subscribe() method. Note that in Webflux, everything is lazy loading, so everything the operator in the reactive chain will be invoked by subscribe() method.


Rest Controller Class:
9. Let's create a new package called "resource" and create a new Java class called EmployeeResource.java, which will act as Rest Controller class.

@RestController (line 21) - This annotation is used to indicate this is Rest Controller for Web 
Service.
@RequestMapping("/rest/employee") - line 22 - This annotation is used to map HTTP requests to handler methods of MVC and REST controllers
@RequiredArgsConstructor - line 23 - This annotation is used to generate a constructor with required arguments, which is applied for EmployeeRepository (in line 26)




lines 28 to 31 - @GetMapping("/all") - This annotation is used to map HTTP GET requests onto specific handler methods. This method will fetch all the records saved in the database using employeeRepository.findAll() method. The return type of this method is of type Flux<Employee> which indicates that there are more than one record will be received.

line 33 to 36 - @GetMapping("/{id}") - will accept id as input and assign it to @PathVariable - which will fetch the specific record matching for the input id using employeeRepository.findById(id) method. The return type of this method is of type Mono<Employee> which indicates that there is only one record will be received.

line 38 to 48 - @GetMapping(value = "/{id}/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE) -  is an event stream API, which will push records continously as an event stream, which is indicated by produces = MediaType.TEXT_EVENT_STREAM_VALUE. This method will receive the id as input, tries to find that record in the database by using employeeRepository.findById(empId) method. Once the record is found, it will apply flatMapMany() operator which will generate two Flux values - where 1st Flux value will generate the timer logic to generate a stream for every 2 seconds and other Flux value will generate EmployeeEvent model class. Both these Flux values are merged together will Flux.zip() and map operator is applied to get the 2nd flux value.



10. docker-compose.yml:
This yaml file will have instructions to pull the monodb docker image (in line 5) and to run on port 27017 (in line 8). Inorder to run the docker-compose, open command prompt and go to the root directory path (/reactive-mongo-sample) and run the following command, which will pull the MongoDB docker image and run the same

docker-compose up


Steps to run the application and see the output:
Once the MongoDB is up and running, follow the below steps to run the application and see the output. 
11. Open another Command prompt and go to the root directory path (/reactive-mongo-sample) and run the following command, which will start the application.

mvnw clean install && java -jar target/reactive-mongo-sample-0.0.1-SNAPSHOT.jar

12. As part of the output of the above command, if everything is working correctly, you should finally see the following output in the console, which indicate that 4 sample records are successfully inserted to MongoDB during Server start up

...
...
Employee(id=6b24f202-180b-4729-8660-1b305fe678f4, name=Aditya, salary=40000)
Employee(id=6e69194f-072b-4399-8381-fa85a9468274, name=Raghu, salary=25000)
Employee(id=91e34aa0-4801-468e-8e9f-b62b5ac18576, name=Praveen, salary=30000)
Employee(id=66a9a625-77fd-4c71-b981-19b3a0f29a6a, name=Shyam, salary=35000)


13. Now open the Browser (or any rest client like Postman) and invoke the following URL which will fetch all the 4 employees (as shown in the screenshot below) that were inserted during Server startup:

http://localhost:8080/rest/employee/all


14. Copy any id value from the above output (in my case, I copied 6e69194f-072b-4399-8381-fa85a9468274). Now open another Browser (or any rest client like Postman) and hit the following URL with the copied id appended at the end of the URL (in my case, I copied 6e69194f-072b-4399-8381-fa85a9468274), which will fetch only one employee detail (as shown in the screenshot below):

http://localhost:8080/rest/employee/6e69194f-072b-4399-8381-fa85a9468274

15. Now open Browser (or any rest client like Postman) and hit the following URL with /events appended at the end of the URL, which will fetch continuous stream of text events (as shown in the screenshot below):
http://localhost:8080/rest/employee/6e69194f-072b-4399-8381-fa85a9468274/events


16. That's all. Hope you learned something from this.

No comments:

Post a Comment