Spring Boot WebFlux + MongoDB Crud Example
Overview
In this tutorial we will be looking at creating example using Spring Boot WebFlux + MongoDB Crud.
Spring WebFlux Tutorial :
- Spring WebFlux Overview
- Install MongoDB on Windows
- Spring WebFlux + MongoDB Crud Example
- Spring Boot WebClient Example
- Spring WebFlux Interview Questions and Answers
In this article will create the example which will support fully non-blocking, also using mongodb as back-end database to utilise reactive programming completely.
Follow steps from MongoDB Installation on Windows.
Project Structure
Maven Dependency
Add spring-boot-starter-webflux and spring-boot-starter-data-mongodb-reactive dependencies.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.techgeeknext</groupId>
<artifactId>spring-boot-webflux-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-webflux-example</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Application Properties
## MongoDB default port
dbport=27017
##MongoDB database name
dbname=TechGeekNextDB
Webflux Configuration
package com.techgeeknext.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer
{
}
MongoDB Configuration
package com.techgeeknext.example.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.techgeeknext.example.dao")
public class MongoDbConfig extends AbstractReactiveMongoConfiguration
{
@Value("${dbport}")
private String port;
@Value("${dbname}")
private String dbName;
@Override
public MongoClient reactiveMongoClient() {
return MongoClients.create();
}
@Override
protected String getDatabaseName() {
return dbName;
}
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() {
return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName());
}
}
Take a look at our suggested posts:
Model Class
Create Employee Model Class.
package com.techgeeknext.example.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Document
public class Employee {
@Id
int id;
String name;
String role;
}
REST Controller
package com.techgeeknext.example.controller;
import com.techgeeknext.example.model.Employee;
import com.techgeeknext.example.service.EmployeeServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
public class EmployeeController {
@Autowired
private EmployeeServiceImpl employeeServiceImpl;
@PostMapping("/create/emp")
@ResponseStatus(HttpStatus.CREATED)
public void createEmp(@RequestBody Employee employee) {
employeeServiceImpl.createEmp(employee);
}
@GetMapping(value = "/get/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@ResponseBody
public Flux<Employee> findAll() {
return employeeServiceImpl.findAllEmp();
}
@GetMapping("/get/{id}")
public ResponseEntity<Mono<Employee>> findEmpById(@PathVariable("id") Integer id) {
Mono<Employee> employee = employeeServiceImpl.findByEmpId(id);
return new ResponseEntity<Mono<Employee>>(employee, employee != null ? HttpStatus.OK : HttpStatus.NOT_FOUND);
}
@PutMapping("/update/emp")
@ResponseStatus(HttpStatus.OK)
public Mono<Employee> update(@RequestBody Employee employee) {
return employeeServiceImpl.updateEmp(employee);
}
@DeleteMapping("/delete/{id}")
@ResponseStatus(HttpStatus.OK)
public void delete(@PathVariable("id") Integer id) {
employeeServiceImpl.deleteEmp(id).subscribe();
}
}
Service classes Implementation
package com.techgeeknext.example.service;
import com.techgeeknext.example.dao.EmployeeRepository;
import com.techgeeknext.example.model.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class EmployeeServiceImpl implements EmployeeServiceInterface {
@Autowired
EmployeeRepository employeeRepo;
public void createEmp(Employee employee) {
employeeRepo.save(employee).subscribe();
}
public Mono<Employee> findByEmpId(Integer id) {
return employeeRepo.findById(id);
}
public Flux<Employee> findAllEmp() {
return employeeRepo.findAll();
}
public Mono<Employee> updateEmp(Employee employee) {
return employeeRepo.save(employee);
}
public Mono<Void> deleteEmp(Integer id) {
return employeeRepo.deleteById(id);
}
}
Test
Run the application and follow the below steps to test the application response.- Create the Employees data, use HTTP POST http://localhost:8080/create/emp
- Once, created few employees, you can GET all employees using HTTP GET http://localhost:8080/get/all
- To delete the employee, use HTTP DELETE http://localhost:8080/delete/2
- To update the employee, use HTTP PUT http://localhost:8080/update/emp and provide Employee details to update
NOTE: Postman chrome browser extension is a blocking client, because it will only show the
result for get all employees (http://localhost:8080/get/all) after it has collected
all the result set of employees from database.
Testing non-blocking response : Open the URL in the Chrome browser. The result will be
displayed one after another as they
become available in the form of events (text/event-stream).
Also, you can see the output in MongoDB UI - Management Tool. You can install the MongoDB UI from here.
Download Source Code
The full source code for this article can be found on below.Download it here - Spring Boot WebFlux + MongoDB Crud Example