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:


	
		org.springframework.boot
		spring-boot-starter-webflux
	

	
		org.springframework.boot
		spring-boot-starter-test
		test
	
	
		io.projectreactor
		reactor-test
		test
	



	
		
			org.springframework.boot
			spring-boot-maven-plugin
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	



	
		spring-snapshots
		Spring Snapshots
		https://repo.spring.io/snapshot
		
			true
		
	
	
		spring-milestones
		Spring Milestones
		https://repo.spring.io/milestone
		
			false
		
	

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



By grokonez | September 20, 2017.


Related Posts


1 thought 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.

Got Something To Say:

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

*