Reactive Flow with MongoDB, Kotlin, and Spring WebFlux

1. Overview

In this tutorial, we’ll write a simple application showcasing a fully reactive flow using Spring Data Reactive MongoDB and Spring SSeEmitter.

On one side, we’ll apply Spring Data Reactive MongoDB to save data through a Mongo reactive database and combine it with the Server-Sent-Events mechanism to notify subscribed clients about incoming data.

Additionally, we’ll take advantage of Spring Boot’s Kotlin support.

So, let’s start!

2. Setup

First of all, we have to configure our Maven project adding the Spring Data Reactive MongoDB dependency in our pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>

Moreover, to use Kotlin, we’ll need to add the Kotlin standard library to the same file:

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-stdlib</artifactId>
</dependency>

Now, we’re ready to start developing our application. We’ll start configuring the environment to support reactive programming and Mongo DB, so let’s go!

3. Reactive Mongo Configuration

The first thing we have to do is to configure our project to support reactive Spring Data. We’ll add a new class extending from AbstractReactiveMongoConfiguration to configure the Mongo reactive client and the Spring Data Repository:

@Configuration
@EnableReactiveMongoRepositories(
  basePackageClasses = arrayOf(EventRepository::class))
class MongoConfig : AbstractReactiveMongoConfiguration() {
 
    override fun getDatabaseName() = "mongoDatabase"
 
    override fun reactiveMongoClient() = mongoClient()
 
    @Bean
    fun mongoClient() = MongoClients.create()
 
    @Bean
    override fun reactiveMongoTemplate()
     = ReactiveMongoTemplate(mongoClient(), databaseName)
}

This configuration isn’t required if we want to interact with MongoDB in a non-reactive manner. Note that we have to add the @EnableReactiveMongoRepositories tag to let the configuration know where our Spring Data repositories are. 

Following this, we’re now ready to start implementing the main functionality. The first thing we’ll do is develop a new data class to persist the incoming information and then, a related Spring Data reactive repository to manage that persistence.

4. Document

The document is the unit of storing data in a MongoDB database. This unit uses JSON style for storing data.

In our project, we’ll keep it simple using a dummy document called Event with two attributes: id and name:

@Document
class Event(id: String, name: String)

5. Spring Data Reactive Repository 

The goal of Spring Data abstraction is to reduce the amount of code required to implement data access layers for persistence stores.

Consequently, the reactive version works the same so, we’ll have the following line to implement a whole reactive repository:

interface EventRepository : ReactiveMongoRepository<Event, String>

6. Controller

The Controller class will be responsible for sending a Server-Sent Event whenever any reactive data is saved.

The method saveAndSend will first save the incoming data into our Mongo Reactive database delegating this action to our EventRepository. 

Consequently, we’ll add a new endpoint that creates and saves new Events.

First, let’s see the Kotlin code:

@GetMapping(value = "/save", 
  produces = arrayOf(MediaType.TEXT_EVENT_STREAM_VALUE))
fun saveAndSend(@RequestParam("eventName") eventName: String) =
  eventRepository
    .save(Event(UUID.randomUUID().toString(), eventName))
    .flux()

As we can see, after saving the new data, the Spring Data reactive repository will return an SSE that will be sent to the subscribed client.

At this point, we can say that we have a complete reactive Kotlin server-side project. We already have all the needed elements to execute our Spring Boot application.

Thus, we’ll now take a look at how to create a simple web client to send and receive all our created Server-Sent events.

7. Subscriber

Here we have a simple web client that will be able to save data and receive changes from the server.

Let’s see how it’s implemented:

7.1. Send Data

The client will save the typed event name through the Save new event button.

This, in turn, will make an HTTP request to our server endpoint saveEvent:

<form method="get" action="/save">
    <input type="text" name="eventName">
    <button type="submit">Save new event</button>
</form>

7.2. Receive Data

On the other hand, the client will be listening to save endpoint as well. Note that each programming language has specific frameworks to manage SSE.

However, for our example, we’ll keep it as simple as possible:

<div id="content"></div>
<script>
    var source = new EventSource("save");
source.addEventListener('message', function (e) {
        console.log('New message is received');
        const index = JSON.parse(e.data);
        const content = `New event added: ${index.name}<br>`;
        document.getElementById("content").innerHTML += content;
    }, false);
</script>

8. Conclusion

In conclusion, Spring Data MongoDB has been updated to leverage the reactive programming model introduced in Spring Framework 5. We now have a simple way to use this programming paradigm and Server-Sent events.

Hence, this supposes an alternative to the traditional non-reactive applications the problems with the database blocking.

The implementation of this example can be checked in the GitHub project.

This is a Maven-based project, so then, execute the Spring Boot application to see how it works. Don’t forget to run the Mongo DB server first.Comments are closed on this article!

Related posts:

Java Program to Implement Triply Linked List
Java Program to Solve any Linear Equations
Java Program to do a Breadth First Search/Traversal on a graph non-recursively
Java CyclicBarrier vs CountDownLatch
Guide to Apache Commons CircularFifoQueue
More Jackson Annotations
Java Program to Create a Random Graph Using Random Edge Generation
Zipping Collections in Java
Show Hibernate/JPA SQL Statements from Spring Boot
Spring Boot - Google Cloud Platform
Java Program to Solve the Fractional Knapsack Problem
Spring Boot - Code Structure
Java Program to Implement Jarvis Algorithm
Java Program to Implement Karatsuba Multiplication Algorithm
Hướng dẫn Java Design Pattern – DAO
Spring Security – security none, filters none, access permitAll
Java Program to Implement Sorted Doubly Linked List
Java Program to Perform Cryptography Using Transposition Technique
Giới thiệu Swagger – Công cụ document cho RESTfull APIs
Map Interface trong java
Comparing Two HashMaps in Java
Java Program to Implement the RSA Algorithm
Spring’s RequestBody and ResponseBody Annotations
Java Program to Implement Solovay Strassen Primality Test Algorithm
Wiring in Spring: @Autowired, @Resource and @Inject
Java – Random Long, Float, Integer and Double
Array to String Conversions
Sử dụng Fork/Join Framework với ForkJoinPool trong Java
Java Program to Check whether Directed Graph is Connected using BFS
Biến trong java
Deploy a Spring Boot WAR into a Tomcat Server
Java Program to Check Whether a Given Point is in a Given Polygon