In this article, we will explore React programming in Spring Boot, Reactive programming is an asynchronous, non-blocking programming paradigm for developing highly responsive applications that react to external stimuli.
What is Reactive Programming
- In reactive programming, the flow of data is asynchronous through push-based publishers and subscribers instead of synchronous pull-based calls.
- The core abstraction in reactive programming is the reactive stream which provides a standard way to work with asynchronous streams of data. The two primary reactive stream interfaces are Publisher and Subscriber.
- Publishers push data to Subscribers asynchronously. Subscribers register callbacks and are notified when new data arrives instead of actively polling for it.
- Examples of reactive streams include Mono and Flux in Spring Webflux. Mono represents a single event/value and Flux represents a stream of multiple values.
Benefits of Reactive Programming with Spring Webflux
- Support for Reactive Types
- Integration with Reactive Streams
- Non-blocking I/O
- Microservices-friendly
Spring Webflux Dependency
Gradle:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}
Maven:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webflux -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>6.1.3</version>
</dependency>
Reactive Types in Spring Webflux
- Mono: Mono specifically represents a single value or no value at all
- Flux: Flux represents a **stream of zero or more elements** emitted over time
Step By Step Implementation
Step 1: Set up a new Spring MVC project
Create a new Maven project in your preferred IDE (e.g., IntelliJ or Eclipse or Spring Tool Suite) and add the following dependencies.
- Spring Webflux
- Mongo Db – for Database
- Lombok
XML
<? xml version = "1.0" encoding = "UTF-8" ?>
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion >4.0.0</ modelVersion >
< parent >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-parent</ artifactId >
< version >3.2.2</ version >
< relativePath /> <!-- lookup parent from repository -->
</ parent >
< groupId >com.example</ groupId >
< artifactId >REST_Spring_Flux</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
< name >REST_Spring_Flux</ name >
< description >Demo project for Spring Boot</ description >
< properties >
< java.version >17</ java.version >
</ properties >
< 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 >
< dependency >
< groupId >org.projectlombok</ groupId >
< artifactId >lombok</ artifactId >
< optional >true</ optional >
</ dependency >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-test</ artifactId >
< scope >test</ scope >
</ dependency >
< dependency >
< groupId >io.projectreactor</ groupId >
< artifactId >reactor-test</ artifactId >
< scope >test</ scope >
</ dependency >
</ dependencies >
< build >
< plugins >
< plugin >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-maven-plugin</ artifactId >
< configuration >
< excludes >
< exclude >
< groupId >org.projectlombok</ groupId >
< artifactId >lombok</ artifactId >
</ exclude >
</ excludes >
</ configuration >
</ plugin >
</ plugins >
</ build >
</ project >
|
Project Structure:
Step 2: Configure Mongo Db Database
# MongoDB properties
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=student_management
- host: host property pecifies the hostname or IP address of the MongoDB server. In this example we are using localhost.
- port: property defines the port number on which the MongoDB server is running. In this example we are running our server on port no : 27010 [8080].
- database: sets the name of the MongoDB database that our Spring Boot application will connect to. In this example, the database name is “student_management”.
Step 3: Create Model Class
Student.class File:
Java
package com.example.demo.entities;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document public class Student {
@Id private String id;
private String name;
private int age;
public Student(String id, String name, int age)
{
super ();
this .id = id;
this .name = name;
this .age = age;
}
public Student()
{
super ();
// TODO Auto-generated constructor stub
}
public String getId() { return id; }
public void setId(String id) { this .id = id; }
public String getName() { return name; }
public void setName(String name) { this .name = name; }
public int getAge() { return age; }
public void setAge( int age) { this .age = age; }
} |
Note: @Document annotation indicate that this class should be mapped to a MongoDB document.
Step 4: Create Repository Interface
StudentRepository.class File:
Java
package com.example.demo.repositories;
import com.example.demo.entities.*;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
public interface StudentRepository
extends ReactiveMongoRepository<Student, String> {
} |
Step 5: Create Controller
StudentController.class File:
Java
package com.example.demo.controller;
import com.example.demo.entities.Student;
import com.example.demo.services.StudentService;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController @RequestMapping ( "/api/students" )
public class StudentController {
private final StudentService studentService;
public StudentController(StudentService studentService)
{
this .studentService = studentService;
}
public Mono<Student>
saveStudent( @RequestBody Student student)
{
return studentService.saveStudent(student);
}
@GetMapping public Flux<Student> getAllStudents()
{
return studentService.getAllStudents();
}
@GetMapping ( "/{id}" )
public Mono<Student>
getStudentById( @PathVariable String id)
{
return studentService.getStudentById(id);
}
@PostMapping
public Mono<Student>
createStudent( @RequestBody Student student)
{
return studentService.saveStudent(student);
}
@DeleteMapping ( "/{id}" )
public Mono<Void> deleteStudent( @PathVariable String id)
{
return studentService.deleteStudent(id);
}
} |
Step 6: Create Service Interface
StudentService.class File:
Java
package com.example.demo.services;
import com.example.demo.entities.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface StudentService {
Mono<Student> saveStudent(Student student);
Flux<Student> getAllStudents();
Mono<Student> getStudentById(String id);
Mono<Void> deleteStudent(String id);
} |
Step 7: Create ServiceImpl
StudentServiceImpl.class File:
Java
package com.example.demo.services;
import com.example.demo.entities.*;
import com.example.demo.repositories.StudentRepository;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Service public class StudentServiceImpl implements StudentService {
private final StudentRepository studentRepository;
public StudentServiceImpl(
StudentRepository studentRepository)
{
this .studentRepository = studentRepository;
}
@Override
public Mono<Student> saveStudent(Student student)
{
return studentRepository.save(student);
}
@Override public Flux<Student> getAllStudents()
{
return studentRepository.findAll();
}
@Override public Mono<Student> getStudentById(String id)
{
return studentRepository.findById(id);
}
@Override public Mono<Void> deleteStudent(String id)
{
return studentRepository.deleteById(id);
}
} |
Step 8: Run the Application
Now, You can run the Spring Boot application from IDE or by using the command-line tool provided by Spring Boot.
mvn spring-boot:run
Step 9: Test the Endpoints Using Postman
POST: http://localhost:8080/api/students-- Post the student data
GET: http://localhost:8080/api/students-- Get all student details
GET: http://localhost:8080/api/students/{id} -- Get the student details by Id