Реактивный поток с MongoDB, Kotlin и Spring Web Flux

1. Общий обзор

В этом руководстве мы напишем простое приложение, демонстрирующее полностью реактивный поток, используя Spring Data Reactive MongoDB и Spring SSeEmitter.

С одной стороны, мы применим Spring Data Reactive MongoDB для сохранения данных через базу данных Mongo reactive и объединим ее с механизмом отправки событий сервером для уведомления подписанных клиентов о поступающих данных.

 В этом руководстве мы напишем простое приложение, демонстрирующее полностью реактивный поток, используя Spring Data Reactive MongoDB и Spring SSeEmitter.

2. Настройка

Прежде всего, мы должны настроить наш проект Maven, добавив реактивную зависимость Spring Data от MongoDB в наш pom.xml:

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

Более того, чтобы использовать Kotlin, нам нужно будет добавить стандартную библиотеку Kotlin в тот же файл:

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

Теперь мы готовы приступить к разработке нашего приложения. Мы приступим к настройке среды для поддержки реактивного программирования и Mongo DB, так что вперед!

3. Реактивная конфигурация Mongo

Первое, что нам нужно сделать, это настроить наш проект на поддержку реактивных данных Spring. Мы добавим новый класс, расширяющий AbstractReactiveMongoConfiguration, для настройки реактивного клиента Mongo и хранилища данных Spring:

@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)
}

Эта конфигурация не требуется, если мы хотим взаимодействовать с MongoDB в режиме реального времени. Обратите внимание, что мы должны добавить тег @EnableReactiveMongoRepositories, чтобы конфигурация знала, где находятся наши хранилища данных Spring.

После этого мы готовы приступить к реализации основной функциональности.
Первое, что мы сделаем, это разработаем новый класс данных для сохранения поступающей информации, а затем связанный с ним реактивный репозиторий Spring Data для управления сохранением.

4. Документ

Документ является единицей хранения данных в базе данных MongoDB. В этом модуле для хранения данных используется стиль JSON.

В нашем проекте мы упростим его, используя фиктивный документ Event с двумя атрибутами: id и name:

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

5. Реактивный репозиторий весенних данных

Цель абстрагирования Spring Data - уменьшить объем кода, необходимого для реализации уровней доступа к данным для постоянных хранилищ.

Следовательно, реактивная версия работает так же, поэтому у нас будет следующая строка для реализации всего реактивного хранилища:

interface EventRepository : ReactiveMongoRepository<Event, String>

6. Контроллер

Класс Controller будет отвечать за отправку события, отправляемого сервером, всякий раз, когда сохраняются какие-либо реактивные данные.

Метод saveAndSend сначала сохранит входящие данные в нашей реактивной базе данных Mongo, делегировав это действие нашему EventRepository.

Следовательно, мы добавим новую конечную точку, которая создает и сохраняет новые события.

Сначала давайте посмотрим на код Kotlin:

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

Как мы видим, после сохранения новых данных реактивный репозиторий Spring Data вернет актив, который будет отправлен подписанному клиенту.

На данный момент мы можем сказать, что у нас есть готовый реактивный серверный проект на Kotlin. У нас уже есть все необходимые элементы для запуска нашего приложения Spring Boot.

Итак, теперь мы рассмотрим, как создать простой веб-клиент для отправки и получения всех созданных нами событий, отправляемых сервером.

7. Subscriber

Здесь у нас есть простой веб-клиент, который сможет сохранять данные и получать изменения с сервера.

Давайте посмотрим, как это реализовано:

7.1. Отправка данных

Клиент сохранит введенное название события с помощью кнопки Сохранить новое событие.

Это, в свою очередь, отправит HTTP-запрос на сохранение события на нашем сервере:

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

7.2. Получать данные

С другой стороны, клиент также будет прослушивать save endpoint. Обратите внимание, что в каждом языке программирования есть определенные фреймворки для управления SSE.

Однако для нашего примера мы постараемся максимально упростить его:

<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. Заключение

В заключение, Spring Data MongoDB был обновлен, чтобы использовать модель реактивного программирования, представленную в Spring Framework 5. Теперь у нас есть простой способ использовать эту парадигму программирования и события, отправляемые сервером.

Следовательно, это предполагает альтернативу традиционным нереактивным приложениям для решения проблем с блокировкой базы данных.

Оригинал статьи: https://www.baeldung.com/kotlin/mongodb-spring-webflux