SpringBoot WebFlux Annotation-based RestAPIs

Reactive programming is about non-blocking applications. And Spring Framework 5 includes a new spring-webflux module, supports Reactive Streams for communicating backpressure across async components and libraries. So in the tutorial, JavaSampleApproach will guide you through the steps for creating a SpringBoot WebFlux Annotation-based restful APIs.

Related posts:
SpringBoot WebFlux Functional RestAPIs
Reactor – Simple Ways to create Flux/Mono
Spring WebClient with Spring Webflux | SpringBoot 2
SpringBoot WebFlux Test

I. Technologies

– Java: 1.8
– Maven: 3.3.9
– Spring Tool Suite: Version 3.9.0.RELEASE
– Spring Boot: 2.0.0.M4
– Spring Boot Starter Webflux

II. Spring WebFlux

Spring Framework 5.0 supports WebFlux with fully asynchronous and non-blocking and does NOT require the Servlet API(Unlike Spring MVC).

Spring WebFlux supports 2 distinct programming models:
– Annotation-based with @Controller
– Functional with Java 8 lambda style

In the tutorial, we will introduce WebFlux with Annotation-based.
For starting with WebFlux, SpringBoot supports a collection dependency: spring-boot-starter-webflux.

Sample code:


@RestController
@RequestMapping(value="/api/customer")
public class RestControllerAPIs {
	
    @GetMapping("/")
    public Flux getAll() {
	
    	...
    }
    
	@GetMapping("/{id}")
    public Mono getCustomer(@PathVariable Long id) {
		
		...
    }
}

reactor.core.publisher.Flux: is a standard Publisher representing a reactive sequence of 0..N items, optionally terminated by either a success signal or an error.
reactor.core.publisher.Mono: Mono is a specialized Publisher that emits at most single-valued-or-empty result.

III. Practice

In the tutorial, We create a SpringBoot project as below:

springboot webflux annotation-based - project structure

Step to do:
– Create SpringBoot project
– Create data model
– Implement Spring WebFlux APIs
– Run and check results

1. Create SpringBoot project

Using SpringToolSuite, create a SpringBoot project with Reactive Web dependency:

springboot webflux reactive - select reactive web

Check pom.xml after creating:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-webflux</artifactId>
	</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>
		</plugin>
	</plugins>
</build>

<repositories>
	<repository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</repository>
	<repository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</repository>
</repositories>

<pluginRepositories>
	<pluginRepository>
		<id>spring-snapshots</id>
		<name>Spring Snapshots</name>
		<url>https://repo.spring.io/snapshot</url>
		<snapshots>
			<enabled>true</enabled>
		</snapshots>
	</pluginRepository>
	<pluginRepository>
		<id>spring-milestones</id>
		<name>Spring Milestones</name>
		<url>https://repo.spring.io/milestone</url>
		<snapshots>
			<enabled>false</enabled>
		</snapshots>
	</pluginRepository>
</pluginRepositories>

2. Create data model

– Create a Customer model class:


package com.javasampleapproach.webflux.model;

public class Customer {
	private long custId;
	private String firstname;
	private String lastname;
	private int age;
	
	public Customer(){}
	
	public Customer(long custId, String firstname, String lastname, int age){
		this.custId = custId;
		this.firstname = firstname;
		this.lastname = lastname;
		this.age = age;
	}
 
	public long getCustId() {
		return custId;
	}
 
	public void setCustId(Long custId) {
		this.custId = custId;
	}
 
	public String getFirstname() {
		return firstname;
	}
 
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
 
	public String getLastname() {
		return lastname;
	}
 
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
 
	public int getAge() {
		return age;
	}
 
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public String toString() {
		String info = String.format("custId = %d, firstname = %s, lastname = %s, age = %d", custId, firstname, lastname, age);
		return info;
	}
}

3. Implement Spring WebFlux APIs

Implement WebFlux APIs:


package com.javasampleapproach.webflux.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.RestController;

import com.javasampleapproach.webflux.model.Customer;

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

@RestController
@RequestMapping(value="/api/customer")
public class RestControllerAPIs {
	
	Map custStores = new HashMap();
	
    @PostConstruct
    public void initIt() throws Exception {
        custStores.put(Long.valueOf(1), new Customer(1, "Jack", "Smith", 20));
        custStores.put(Long.valueOf(2), new Customer(2, "Peter", "Johnson", 25));
    }
	
    @GetMapping("/")
    public Flux getAll() {
    	return Flux.fromIterable(custStores.entrySet().stream()
    	        										.map(entry -> entry.getValue())
    	        										.collect(Collectors.toList()));
    }
    
	@GetMapping("/{id}")
    public Mono getCustomer(@PathVariable Long id) {
		return Mono.justOrEmpty(custStores.get(id));
    }
	
	
	@PostMapping("/post")
    public Mono> postCustomer(@RequestBody Customer customer){
		// do post
		custStores.put(customer.getCustId(), customer);
		
		// log on console
		System.out.println("########### POST:" + customer);
				
		return Mono.just(new ResponseEntity<>("Post Successfully!", HttpStatus.CREATED));
	}
	
	@PutMapping("/put/{id}")
	public Mono> putCustomer(@PathVariable Long id, @RequestBody Customer customer){
		// reset customer.Id
		customer.setCustId(id);
		
		custStores.put(id, customer);
		
		// log on console
		System.out.println("########### PUT:" + customer);
		
		return Mono.just(new ResponseEntity<>(customer, HttpStatus.CREATED));
	}
	
	@DeleteMapping("/delete/{id}")
    public Mono> deleteMethod(@PathVariable Long id) {
		// delete processing
    	custStores.remove(id);
    	return Mono.just(new ResponseEntity<>("Delete Succesfully!", HttpStatus.ACCEPTED));
    }
}

4. Run and check results

Build and run the SpringBoot project with commandlines: {mvn clean install, mvn spring-boot:run}

– See console’ logs:


Mapped "{[/api/customer/],methods=[GET]}" onto public reactor.core.publisher.Flux com.javasampleapproach.webflux.controller.RestControllerAPIs.getAll()
Mapped "{[/api/customer/{id}],methods=[GET]}" onto public reactor.core.publisher.Mono com.javasampleapproach.webflux.controller.RestControllerAPIs.getCustomer(java.lang.Long)
Mapped "{[/api/customer/post],methods=[POST]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.postCustomer(com.javasampleapproach.webflux.model.Customer)
Mapped "{[/api/customer/delete/{id}],methods=[DELETE]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.deleteMethod(java.lang.Long)
Mapped "{[/api/customer/put/{id}],methods=[PUT]}" onto public reactor.core.publisher.Mono> com.javasampleapproach.webflux.controller.RestControllerAPIs.putCustomer(java.lang.Long,com.javasampleapproach.webflux.model.Customer)
Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.reactive.resource.ResourceWebHandler]
Looking for @ControllerAdvice: org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext@42dce8e7: startup date [Wed Sep 20 18:02:45 ICT 2017]; root of context hierarchy
Started HttpServer on /0:0:0:0:0:0:0:0:8080
Netty started on port(s): 8080

– Make a GET all customer request: http://localhost:8080/api/customer/

springboot webflux reactive - get all request

– Make a GET customer request: http://localhost:8080/api/customer/1/

springboot webflux reactive - get a customer

– Make a POST request: http://localhost:8080/api/customer/post

springboot webflux reactive - post a customer

– Make a PUT request: http://localhost:8080/api/customer/put/3

springboot webflux reactive - put a customer

– Make a DELETE request: http://localhost:8080/api/customer/delete/1

springboot webflux reactive - delete request

– Make a GET all customers request: http://localhost:8080/api/customer/

springboot webflux reactive - get all customer for final check

IV. Sourcecode

SpringBootWebFluxAnnotationBased

24 thoughts on “SpringBoot WebFlux Annotation-based RestAPIs”

  1. How do I convert CompletableFuture to a Flux or Mono?

    I would love to design my services layer to depend on CompletableFutures and convert it to Flux and Mono on a web layer.

  2. Great post. I was checking constantly this blog and I am inspired!
    Extremely helpful info particularly the closing phase 🙂 I handle such info a lot.
    I was seeking this particular information for a long time.
    Thank you and good luck.

  3. Thanks for one’s marvelous posting! I truly enjoyed reading it, you’re a great
    author. I will ensure that I bookmark your blog and definitely will come back
    in the foreseeable future. I want to encourage that you continue
    your great posts, have a nice weekend!

  4. You actually make it appear really easy together with your
    presentation however I in finding this topic to be actually one thing which I believe I might never understand.

    It kind of feels too complex and extremely vast for me.

    I’m taking a look ahead in your next post, I will
    attempt to get the dangle of it!

  5. Greetings! I know this is kind of off topic but I was wondering which blog platform are you
    using for this site? I’m getting fed up of WordPress because I’ve had problems with hackers
    and I’m looking at alternatives for another platform. I would be awesome if you could
    point me in the direction of a good platform.

  6. You actually make it seem so easy along with your presentation but I in finding this matter to be really one thing that I think I’d never understand.
    It sort of feels too complicated and extremely extensive for me.

    I’m having a look ahead in your next post, I’ll attempt to get the hang
    of it!

  7. I loved as much as you will receive carried out right here.
    The sketch is attractive, your authored material stylish.

    nonetheless, you command get bought an nervousness over that you wish be delivering the
    following. unwell unquestionably come more formerly again as exactly the same
    nearly very often inside case you shield this hike.

  8. Thanks on your marvelous posting! I genuinely enjoyed reading it, you can be
    a great author.I will make certain to bookmark your blog and will often come back later on. I
    want to encourage you continue your great work, have a nice
    day!

  9. Hey there would you mind sharing which blog platform you’re using?
    I’m looking to start my own blog soon but I’m having a difficult time making a decision between BlogEngine/Wordpress/B2evolution and Drupal.
    The reason I ask is because your layout seems different then most blogs
    and I’m looking for something unique.
    P.S Sorry for getting off-topic but I had to ask!

  10. What’s Going down i am new to this, I stumbled
    upon this I have found It positively useful and it has
    helped me out loads. I hope to give a contribution & assist
    different customers like its helped me. Great job.

Leave a Reply

Your email address will not be published. Required fields are marked *