Spring Boot Reactive MongoDB and React.js CRUD Application


Here’s a step-by-step guide to building a Spring Boot Reactive MongoDB React.js CRUD application:


1. Backend: Spring Boot Reactive MongoDB

Setup the Spring Boot Project

  1. Dependencies:

    • Spring WebFlux (for reactive programming)
    • Spring Data Reactive MongoDB
    • Lombok (optional)
    • Spring Boot DevTools (for easier development)

    Example pom.xml dependencies:

    <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

Define MongoDB Model

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

@Data
@Document(collection = "items")
public class Item {
    @Id
    private String id;
    private String name;
    private String description;
    private double price;
}

Create Repository

import org.springframework.data.repository.reactive.ReactiveCrudRepository;

public interface ItemRepository extends ReactiveCrudRepository<Item, String> {
}

Service Layer

import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
public class ItemService {
    private final ItemRepository repository;

    public ItemService(ItemRepository repository) {
        this.repository = repository;
    }

    public Flux<Item> getAllItems() {
        return repository.findAll();
    }

    public Mono<Item> getItemById(String id) {
        return repository.findById(id);
    }

    public Mono<Item> saveItem(Item item) {
        return repository.save(item);
    }

    public Mono<Void> deleteItem(String id) {
        return repository.deleteById(id);
    }
}

Controller

import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/items")
public class ItemController {
    private final ItemService service;

    public ItemController(ItemService service) {
        this.service = service;
    }

    @GetMapping
    public Flux<Item> getAllItems() {
        return service.getAllItems();
    }

    @GetMapping("/{id}")
    public Mono<Item> getItemById(@PathVariable String id) {
        return service.getItemById(id);
    }

    @PostMapping
    public Mono<Item> createItem(@RequestBody Item item) {
        return service.saveItem(item);
    }

    @PutMapping("/{id}")
    public Mono<Item> updateItem(@PathVariable String id, @RequestBody Item item) {
        item.setId(id);
        return service.saveItem(item);
    }

    @DeleteMapping("/{id}")
    public Mono<Void> deleteItem(@PathVariable String id) {
        return service.deleteItem(id);
    }
}

2. Frontend: React.js

Set up React.js Project

  1. Create a React app:
    npx create-react-app reactive-crud
    cd reactive-crud
  2. Install Axios for API calls:
    npm install axios

React Components

  1. API Service (apiService.js)

    import axios from "axios";
    
    const API_URL = "http://localhost:8080/api/items";
    
    export const getAllItems = () => axios.get(API_URL);
    export const getItemById = (id) => axios.get(`${API_URL}/${id}`);
    export const createItem = (item) => axios.post(API_URL, item);
    export const updateItem = (id, item) => axios.put(`${API_URL}/${id}`, item);
    export const deleteItem = (id) => axios.delete(`${API_URL}/${id}`);
  2. Main CRUD Component (App.js)

    import React, { useState, useEffect } from "react";
    import { getAllItems, createItem, updateItem, deleteItem } from "./apiService";
    
    function App() {
        const [items, setItems] = useState([]);
        const [form, setForm] = useState({ id: "", name: "", description: "", price: "" });
    
        useEffect(() => {
            fetchItems();
        }, []);
    
        const fetchItems = async () => {
            const response = await getAllItems();
            setItems(response.data);
        };
    
        const handleSubmit = async (e) => {
            e.preventDefault();
            if (form.id) {
                await updateItem(form.id, form);
            } else {
                await createItem(form);
            }
            setForm({ id: "", name: "", description: "", price: "" });
            fetchItems();
        };
    
        const handleEdit = (item) => {
            setForm(item);
        };
    
        const handleDelete = async (id) => {
            await deleteItem(id);
            fetchItems();
        };
    
        return (
            <div>
                <h1>Reactive CRUD App</h1>
                <form onSubmit={handleSubmit}>
                    <input
                        type="text"
                        placeholder="Name"
                        value={form.name}
                        onChange={(e) => setForm({ ...form, name: e.target.value })}
                        required
                    />
                    <input
                        type="text"
                        placeholder="Description"
                        value={form.description}
                        onChange={(e) => setForm({ ...form, description: e.target.value })}
                        required
                    />
                    <input
                        type="number"
                        placeholder="Price"
                        value={form.price}
                        onChange={(e) => setForm({ ...form, price: e.target.value })}
                        required
                    />
                    <button type="submit">Save</button>
                </form>
    
                <ul>
                    {items.map((item) => (
                        <li key={item.id}>
                            {item.name} - {item.description} - ${item.price}
                            <button onClick={() => handleEdit(item)}>Edit</button>
                            <button onClick={() => handleDelete(item.id)}>Delete</button>
                        </li>
                    ))}
                </ul>
            </div>
        );
    }
    
    export default App;

3. Run the Application

Run Spring Boot Backend

mvn spring-boot:run

Run React Frontend

npm start

4. Features

  • Reactive Backend: Non-blocking requests and responses using WebFlux.
  • Modern Frontend: Clean React UI with form handling and CRUD operations.
  • MongoDB Integration: Easily scalable database for reactive data storage.

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete