Skip to content

1.9. расширение функционала на лету

Для реализации такой логики, чтобы при несовпадении полей JSON-объекта с таблицей PostgreSQL данные сохранялись в MongoDB, нужно добавить следующие шаги:

  1. Конфигурация MongoDB: Подключение MongoDB в Spring Boot.
  2. Обработка несовпадения полей: При получении JSON проверять, соответствуют ли поля структуре таблицы UserData в PostgreSQL.
  3. Сохранение в MongoDB: Если поля не соответствуют, сохранять данные в MongoDB.

Шаг 1: Добавление конфигурации для MongoDB

В файле application.properties нужно добавить параметры для подключения к MongoDB:

# MongoDB configuration
spring.data.mongodb.uri=mongodb://localhost:27017/somedb
spring.data.mongodb.database=somedb

Шаг 2: Настройка MongoDB модели и репозитория

Создадим модель для хранения произвольных JSON-документов в MongoDB и репозиторий для неё.

Модель для MongoDB:

package com.example.websocket8_4.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Map;

@Document(collection = "jsondata")
public class JsonData {

    @Id
    private String id;
    private Map<String, Object> data;

    // Getters and Setters
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public void setData(Map<String, Object> data) {
        this.data = data;
    }
}

Репозиторий для MongoDB:

package com.example.websocket8_4.repository;

import com.example.websocket8_4.model.JsonData;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface JsonDataRepository extends ReactiveMongoRepository<JsonData, String> {
}

Шаг 3: Обновление хэндлера

Теперь нужно обновить хэндлер, чтобы он проверял поля JSON-объекта. Если они не соответствуют таблице UserData в PostgreSQL, данные будут сохранены в MongoDB.

Обновим хэндлер:

package com.example.websocket8_4.handler;

import com.example.websocket8_4.model.UserData;
import com.example.websocket8_4.model.JsonData;
import com.example.websocket8_4.repository.UserDataRepository;
import com.example.websocket8_4.repository.JsonDataRepository;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Controller
public class JsonSaveHandler implements WebSocketHandler {

    @Autowired
    private UserDataRepository userDataRepository;

    @Autowired
    private JsonDataRepository jsonDataRepository;

    @Override
    public Mono<Void> handle(WebSocketSession session) {
        return session.receive()
                .map(msg -> msg.getPayloadAsText()) // Получаем текст
                .flatMap(this::processJson) // Обрабатываем JSON
                .flatMap(result -> session.send(Mono.just(session.textMessage(result)))) // Отправляем результат обратно
                .onErrorResume(e -> session.send(Mono.just(session.textMessage("Error: " + e.getMessage())))) // Обрабатываем ошибки
                .then();
    }

    // Метод для обработки JSON
    private Mono<String> processJson(String jsonString) {
        try {
            JsonNode jsonNode = new ObjectMapper().readTree(jsonString);
            if (isPostgresCompatible(jsonNode)) {
                // Сохраняем в PostgreSQL
                String name = jsonNode.get("name").asText();
                String message = jsonNode.get("message").asText();

                UserData userData = new UserData();
                userData.setName(name);
                userData.setMessage(message);

                return userDataRepository.save(userData)
                        .map(saved -> "Json Save: Success, ID: " + saved.getId())
                        .onErrorResume(e -> Mono.just("Json Save: Error: " + e.getMessage()));
            } else {
                // Сохраняем в MongoDB
                Map<String, Object> jsonMap = convertJsonNodeToMap(jsonNode);
                JsonData jsonData = new JsonData();
                jsonData.setData(jsonMap);

                return jsonDataRepository.save(jsonData)
                        .map(saved -> "Json Save to MongoDB: Success, ID: " + saved.getId())
                        .onErrorResume(e -> Mono.just("Json Save: Error: " + e.getMessage()));
            }
        } catch (Exception e) {
            return Mono.just("Json Save: Invalid JSON format: " + e.getMessage());
        }
    }

    // Проверка, соответствует ли JSON полям PostgreSQL
    private boolean isPostgresCompatible(JsonNode jsonNode) {
        return jsonNode.has("name") && jsonNode.has("message");
    }

    // Метод для конвертации JsonNode в Map
    private Map<String, Object> convertJsonNodeToMap(JsonNode jsonNode) {
        Map<String, Object> map = new HashMap<>();
        Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields();
        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> field = fields.next();
            map.put(field.getKey(), field.getValue().asText()); // Конвертируем значения в строку
        }
        return map;
    }
}

Объяснение:

  1. MongoDB конфигурация: Мы добавили параметры подключения к MongoDB и создали сущность JsonData для произвольного хранения JSON-данных в MongoDB.
  2. Логика в хэндлере:
  3. Проверка JSON: Метод isPostgresCompatible(JsonNode jsonNode) проверяет, содержит ли JSON необходимые поля для сохранения в таблице PostgreSQL (name и message).
  4. Если поля соответствуют, данные сохраняются в PostgreSQL. Если нет — объект сохраняется в MongoDB как документ с произвольными полями.
  5. Метод convertJsonNodeToMap(JsonNode jsonNode) конвертирует произвольный JSON в Map<String, Object>, чтобы сохранить его в MongoDB.

Шаг 4: Зависимости в pom.xml

Убедитесь, что у вас подключены зависимости для работы с MongoDB и PostgreSQL:

<dependencies>
    <!-- Для работы с PostgreSQL -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
    </dependency>

    <!-- Для работы с MongoDB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>
</dependencies>

Теперь, если в вашем JSON присутствуют поля name и message, они будут сохранены в таблице PostgreSQL, в противном случае весь JSON будет сохранён как документ в MongoDB.

application.properties

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=somedb
#spring.data.mongodb.username=root
#spring.data.mongodb.password=example
services:
    mongo:
        image: mongo:latest
        restart: always
        environment:
#            - MONGO_INITDB_ROOT_USERNAME=${MONGO_ROOT_USER}
#            - MONGO_INITDB_ROOT_PASSWORD=${MONGO_ROOT_PASSWORD}
            - MONGO_INITDB_DATABASE=myDatabase
        ports:
            - 27017:27017
        volumes:
            - mongo_data:/data/db
        networks:
            - mongo-network
    mongo-express:
        image: mongo-express
        environment:
            - ME_CONFIG_MONGODB_SERVER=mongo
            - ME_CONFIG_MONGODB_PORT=27017
            - ME_CONFIG_MONGODB_ENABLE_ADMIN=true
            - ME_CONFIG_MONGODB_AUTH_DATABASE=admin
#            - ME_CONFIG_MONGODB_AUTH_USERNAME=${MONGO_ROOT_USER}
#            - ME_CONFIG_MONGODB_AUTH_PASSWORD=${MONGO_ROOT_PASSWORD}
            - ME_CONFIG_BASICAUTH_USERNAME=${MONGOEXPRESS_LOGIN}
            - ME_CONFIG_BASICAUTH_PASSWORD=${MONGOEXPRESS_PASSWORD}
        depends_on:
            - mongo
        ports:
            - "8081:8081"
        networks:
            - mongo-network
MONGO_ROOT_USER=root
MONGO_ROOT_PASSWORD=example
MONGOEXPRESS_LOGIN=root
MONGOEXPRESS_PASSWORD=example

но с логинной парой не получилось подключиться к монго поэтому убрал, логин и пароль и всё стало работать.