In this tutorial, we’re gonna build a Spring Boot MongoDB Reactive example – CRUD application that uses Maven, Spring Data Reactive MongoDB to interact with MongoDB database and Spring WebFlux for Reactive Rest API. You’ll know:
- How to configure Spring Data to work with MongoDB Database
- How to define Data Model and Repository interface
- Way to create Spring Rest Controller to process HTTP requests
- Way to use Spring Data Reactive MongoDB to interact with Database
More Practice:
– Spring WebFlux File upload example
– Spring Boot + GraphQL + MongoDB example with Spring Data & graphql-java
– Spring Boot, MongoDB: JWT Authentication with Spring Security
– Spring Boot MongoDB Pagination example with Spring Data
– Dockerize: Docker Compose: MongoDB and Spring Boot example
Exception Handling:
– Spring Boot @ControllerAdvice & @ExceptionHandler example
– @RestControllerAdvice example in Spring Boot
Fullstack:
– Angular 8 + Spring Boot + MongoDB example
– Angular 10 + Spring Boot + MongoDB example
– Angular 11 + Spring Boot + MongoDB example
– Angular 12 + Spring Boot + MongoDB example
– Angular 13 + Spring Boot + MongoDB example
– Angular 14 + Spring Boot + MongoDB example
– Angular 15 + Spring Boot + MongoDB example
– Angular 16 + Spring Boot + MongoDB example
– React + Spring Boot + MongoDB example
– Vue.js + Spring Boot + MongoDB example
Contents
- Overview of Spring MongoDB Reactive example
- Technology
- Project Structure
- Create & Setup Spring Boot project
- Configure the Spring Data MongoDB database
- Define Data Model
- Create Repository Interface
- Create Data Service
- Create Spring Reactive Rest API Controller
- Enable WebFlux
- Run & Check
- Conclusion
- Source Code
- Further Reading
Overview of Spring MongoDB Reactive example
We will build a Spring Boot, MongoDB, Reactive example – Rest CRUD API for a Tutorial application in that:
- Each Tutorial has id, title, description, published status.
- Apis help to create, retrieve, update, delete Tutorials.
- Apis also support custom finder methods such as find by published status or by title.
These are APIs that we need to provide:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
PUT | /api/tutorials/:id | update a Tutorial by :id |
DELETE | /api/tutorials/:id | delete a Tutorial by :id |
DELETE | /api/tutorials | delete all Tutorials |
GET | /api/tutorials/published | find all published Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
Technology
- Java 11/17
- Spring Boot 3 (with Spring WebFlux, Spring Data MongoDB Reactive)
- MongoDB
- Maven 3.6.1
Project Structure
Let me explain it briefly.
– Tutorial
data model class.
– TutorialRepository
is an interface that extends ReactiveMongoRepository to interact with the database. It is autowired in TutorialService
.
– TutorialService
is a service component that uses TutorialRepository
and provides CRUD methods and custom finder methods for TutorialController
.
– TutorialController
is a RestController which has request mapping methods for RESTful requests such as: getAllTutorials, createTutorial, updateTutorial, deleteTutorial, findByPublished…
– Configuration for Spring Data MongoDB is in application.properties.
– schema.sql has SQL statement for initializing database table.
– pom.xml contains dependencies for Spring Boot, WebFlux, Spring Data MongoDB Reactive.
Create & Setup Spring Boot project
Use Spring web tool or your development tool (Spring Tool Suite, Eclipse, Intellij) to create a Spring Boot project.
Then open pom.xml and add these dependencies:
<dependencies>
<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>
</dependencies>
Configure the Spring Data MongoDB database
Under src/main/resources folder, open application.properties and write these lines.
spring.data.mongodb.uri=mongodb://localhost:27017/bezkoder_db
The connection URL is set to mongodb://localhost:27017/[database-name]
, which indicates that you are using a MongoDB database located at localhost
on port 27017
.
Define Data Model
Our Data model is Tutorial with four fields: id, title, description, published.
In model package, we define Tutorial
class.
model/Tutorial.java
package com.bezkoder.spring.mongodb.reactive.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Tutorial {
@Id
private String id;
private String title;
private String description;
private boolean published;
public Tutorial() {
}
public Tutorial(String title, String description, boolean published) {
this.title = title;
this.description = description;
this.published = published;
}
// getters and setters
@Override
public String toString() {
return "Tutorial [id=" + id + ", title=" + title + ", desc=" + description + ", published=" + published + "]";
}
}
Create Repository Interface
Let’s create a repository to interact with Tutorials from the MongoDB database.
In repository package, create TutorialRepository
interface that extends ReactiveMongoRepository
(which extends Spring Data Reactive ReactiveCrudRepository
).
repository/TutorialRepository.java
package com.bezkoder.spring.mongodb.reactive.repository;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import com.bezkoder.spring.mongodb.reactive.model.Tutorial;
import reactor.core.publisher.Flux;
@Repository
public interface TutorialRepository extends ReactiveMongoRepository<Tutorial, String> {
Flux<Tutorial> findByPublished(boolean published);
Flux<Tutorial> findByTitleContaining(String title);
}
Now we can use ReactiveMongoRepository
and ReactiveCrudRepository
methods: insert()
/ save()
, findById()
, findAll()
, count()
, delete()
, deleteById()
, deleteAll()
… without implementing these methods.
We also define custom finder methods:
– findByPublished()
: returns all Tutorials with published
having value as input published
.
– findByTitleContaining()
: returns all Tutorials which title contains input title
.
The implementation is plugged in by Spring Data MongoDB automatically.
Create Data Service
Let’s create a service that uses TutorialRepository
to implement CRUD Operations and custom finder methods.
In service package, create TutorialService
.
service/TutorialService.java
package com.bezkoder.spring.mongodb.reactive.service;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.bezkoder.spring.mongodb.reactive.model.Tutorial;
import com.bezkoder.spring.mongodb.reactive.repository.TutorialRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service
public class TutorialService {
@Autowired
TutorialRepository tutorialRepository;
public Flux<Tutorial> findAll() {
return tutorialRepository.findAll();
}
public Flux<Tutorial> findByTitleContaining(String title) {
return tutorialRepository.findByTitleContaining(title);
}
public Mono<Tutorial> findById(String id) {
return tutorialRepository.findById(id);
}
public Mono<Tutorial> save(Tutorial tutorial) {
return tutorialRepository.save(tutorial);
}
public Mono<Tutorial> update(String id, Tutorial tutorial) {
return tutorialRepository.findById(id).map(Optional::of).defaultIfEmpty(Optional.empty())
.flatMap(optionalTutorial -> {
if (optionalTutorial.isPresent()) {
tutorial.setId(id);
return tutorialRepository.save(tutorial);
}
return Mono.empty();
});
}
public Mono<Void> deleteById(String id) {
return tutorialRepository.deleteById(id);
}
public Mono<Void> deleteAll() {
return tutorialRepository.deleteAll();
}
public Flux<Tutorial> findByPublished(boolean isPublished) {
return tutorialRepository.findByPublished(isPublished);
}
}
– TutorialService
class is annotated with @Service
to indicate that it is a service component. Spring will create a singleton bean for this class and manage its lifecycle.
– We use @Autowired
to inject TutorialRepository
bean to local variable.
Create Spring Reactive Rest API Controller
Finally, we create a controller that provides APIs for creating, retrieving, updating, deleting and finding Tutorials.
controller/TutorialController.java
package com.bezkoder.spring.mongodb.reactive.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.bezkoder.spring.mongodb.reactive.model.Tutorial;
import com.bezkoder.spring.mongodb.reactive.service.TutorialService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@CrossOrigin(origins = "http://localhost:8081")
@RestController
@RequestMapping("/api")
public class TutorialController {
@Autowired
TutorialService tutorialService;
@GetMapping("/tutorials")
@ResponseStatus(HttpStatus.OK)
public Flux<Tutorial> getAllTutorials(@RequestParam(required = false) String title) {
if (title == null)
return tutorialService.findAll();
else
return tutorialService.findByTitleContaining(title);
}
@GetMapping("/tutorials/{id}")
@ResponseStatus(HttpStatus.OK)
public Mono<Tutorial> getTutorialById(@PathVariable("id") String id) {
return tutorialService.findById(id);
}
@PostMapping("/tutorials")
@ResponseStatus(HttpStatus.CREATED)
public Mono<Tutorial> createTutorial(@RequestBody Tutorial tutorial) {
return tutorialService.save(new Tutorial(tutorial.getTitle(), tutorial.getDescription(), false));
}
@PutMapping("/tutorials/{id}")
@ResponseStatus(HttpStatus.OK)
public Mono<Tutorial> updateTutorial(@PathVariable("id") String id, @RequestBody Tutorial tutorial) {
return tutorialService.update(id, tutorial);
}
@DeleteMapping("/tutorials/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public Mono<Void> deleteTutorial(@PathVariable("id") String id) {
return tutorialService.deleteById(id);
}
@DeleteMapping("/tutorials")
@ResponseStatus(HttpStatus.NO_CONTENT)
public Mono<Void> deleteAllTutorials() {
return tutorialService.deleteAll();
}
@GetMapping("/tutorials/published")
@ResponseStatus(HttpStatus.OK)
public Flux<Tutorial> findByPublished() {
return tutorialService.findByPublished(true);
}
}
– @CrossOrigin
is for configuring allowed origins.
– @RestController
annotation is used to define a controller and to indicate that the return value of the methods should be be bound to the web response body.
– @RequestMapping("/api")
declares that all Apis’ url in the controller will start with /api
.
– We use @Autowired
to inject TutorialService
bean to local variable.
Enable WebFlux
We use @EnableWebFlux to enable support for reactive web application using the Spring WebFlux framework.
SpringBootMongodbReactiveApplication.java
package com.bezkoder.spring.mongodb.reactive;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.reactive.config.EnableWebFlux;
@EnableWebFlux
@SpringBootApplication
public class SpringBootMongodbReactiveApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMongodbReactiveApplication.class, args);
}
}
Run & Check
Run Spring Boot application with Maven command: mvn spring-boot:run
.
Create some Tutorial documents:
Check MongoDB database collection:
Retrieve all Tutorial documents:
Update some Tutorials:
Check MongoDB database collection:
Retrieve a Tutorial document by Id:
Filter published Tutorials:
Find all Tutorial documents which title contains a certain string:
Delete a Tutorial document by id
:
Check MongoDB database collection:
Delete all Tutorials and check:
You can also check this Spring Boot App with Client in one of these posts:
- Simple HTTP Client using Axios
- Simple HTTP Client using Fetch API
- Angular 8 CRUD Application example with Web API
- Angular 10 CRUD example with Web API
- Angular 11 CRUD example with Web API
- Angular 12 CRUD example with Web API
- Angular 13 CRUD example with Web API
- Angular 14 CRUD example with Web API
- Angular 15 CRUD example with Web API
- Angular 16 CRUD example with Web API
- Vue 2 CRUD example with Axios
- Vue 3 CRUD example with Axios
- React CRUD example with Axios
- React Redux CRUD example
Conclusion
Today we’ve built a Spring Data MongoDB Reactive example in Spring Boot successfully using WebFlux Framework for Rest API, Spring Data Reactive MongoDB for CRUD and custom finder methods.
Happy learning! See you again.
Source Code
You can find the complete source code for this tutorial on Github.
Further Reading
Fullstack CRUD App:
– Angular 8 + Spring Boot + MongoDB example
– Angular 10 + Spring Boot + MongoDB example
– Angular 11 + Spring Boot + MongoDB example
– Angular 12 + Spring Boot + MongoDB example
– Angular 13 + Spring Boot + MongoDB example
– Angular 14 + Spring Boot + MongoDB example
– Angular 15 + Spring Boot + MongoDB example
– Angular 16 + Spring Boot + MongoDB example
– React + Spring Boot + MongoDB example
– Vue.js + Spring Boot + MongoDB example
More Practice:
– Spring WebFlux File upload example
– Spring Boot + GraphQL + MongoDB example with Spring Data & graphql-java
– Spring Boot, MongoDB: JWT Authentication with Spring Security
– Spring Boot MongoDB Pagination example with Spring Data
– Dockerize: Docker Compose: MongoDB and Spring Boot example
Exception Handling:
– Spring Boot @ControllerAdvice & @ExceptionHandler example
– @RestControllerAdvice example in Spring Boot