Master java skills

Spring Web Flux

Spring WebFlux is a reactive web framework for building reactive web applications. It is part of the Spring Framework. It is built on top of Project Reactor.

Project Reactor is a reactive programming library for building asynchronous, non-blocking applications.

Spring WebFlux is a powerful tool for building reactive, scalable web applications in high concurrency applications.


Mono and Flux

Spring WebFlux majorly uses two publishers: Mono and Flux
Mono: Returns 0 or 1 element.
The Mono API allows producing only one value.
Flux: Returns 0…N elements.
The Flux can be endless, it can produce multiple values.

Mono vs Flux


Mono and Flux are both implementations of the Publisher interface. When we’re doing some computations or making a request to a database or an external service, and expecting a maximum of one result, then Mono should be used.

When multiple results are expected, then we should use Flux.

Spring WebFlux Reactive CRUD REST API Example

Create a spring starter project

pom.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.1.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.jts</groupId>
	<artifactId>boot-webflux</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>boot-webflux</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-web</artifactId>
		</dependency>
		
		<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>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Project Structure

Actor.java

package com.jts.model;

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

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Document(value = "actors")
public class Actor {

	@Id
	private String id;
	private String firstName;
	private String lastName;
	private String email;

}

ActorRepository.java

package com.jts.repo;

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

import com.jts.model.Actor;

public interface ActorRepository extends ReactiveCrudRepository<Actor, String> {
	
	
}

ActorService.java

package com.jts.service;

import com.jts.model.Actor;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface ActorService {
	
	Mono<Actor> saveActor(Actor Actor);

    Mono<Actor> getActor(String actorId);

    Flux<Actor> getAllActors();

    Mono<Actor> updateActor(Actor Actor, String actorId);

    Mono<Void> deleteActor(String actorId);

}

ActorServiceImpl.java

package com.jts.service;

import org.springframework.stereotype.Service;

import com.jts.model.Actor;
import com.jts.repo.ActorRepository;

import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Service
@AllArgsConstructor
public class ActorServiceImpl implements ActorService {

	private ActorRepository actorRepository;

	@Override
	public Mono<Actor> saveActor(Actor Actor) {
		
		Mono<Actor> savedActor = actorRepository.save(Actor);
		return savedActor;
	}

	@Override
	public Mono<Actor> getActor(String ActorId) {
		return actorRepository.findById(ActorId); 
	}

	@Override
	public Flux<Actor> getAllActors() {

		return actorRepository.findAll();
	}

	@Override
	public Mono<Actor> updateActor(Actor Actor, String ActorId) {

		Mono<Actor> ActorMono = actorRepository.findById(ActorId);

		return ActorMono.flatMap((existingActor) -> {
			existingActor.setFirstName(Actor.getFirstName());
			existingActor.setLastName(Actor.getLastName());
			existingActor.setEmail(Actor.getEmail());
			return actorRepository.save(existingActor);
		});
	}

	@Override
	public Mono<Void> deleteActor(String ActorId) {
		return actorRepository.deleteById(ActorId);
	}

}

ActorController.java

package com.jts.controller;

import org.springframework.http.HttpStatus;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.jts.model.Actor;
import com.jts.service.ActorService;

import lombok.AllArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/actors")
@AllArgsConstructor
public class ActorController {

	private ActorService actorService;

	@PostMapping
	@ResponseStatus(value = HttpStatus.CREATED)
	public Mono<Actor> saveActor(@RequestBody Actor Actor) {
		return actorService.saveActor(Actor);
	}

	@GetMapping("{id}")
	public Mono<Actor> getActor(@PathVariable("id") String ActorId) {
		return actorService.getActor(ActorId);
	}

	@GetMapping
	public Flux<Actor> getAllActors() {
		return actorService.getAllActors();
	}

	@PutMapping("{id}")
	public Mono<Actor> updateActor(@RequestBody Actor Actor,
			@PathVariable("id") String ActorId) {
		return actorService.updateActor(Actor, ActorId);
	}

	@DeleteMapping("{id}")
	@ResponseStatus(value = HttpStatus.NO_CONTENT)
	public Mono<Void> deleteActor(@PathVariable("id") String ActorId) {
		return actorService.deleteActor(ActorId);
	}
}

application.properties

spring.data.mongodb.uri=mongodb+srv://abc:[email protected]/?retryWrites=true&w=majority
spring.data.mongodb.database=my_db

Run and test the application

Create actor data

Get all actors

Get Actor by id