This is the 9th day of my participation in the August More Text Challenge. For details, see:August is more challenging


WebFlux is an asynchronous and non-blocking Web Framework based on Reactor released by Spring Framework 5.0. Using WebFlux can make full use of the multi-core advantage of computing to improve the throughput and scalability of the system.

WebFlux does not reduce the response time of the interface, it only improves throughput and scalability

The following figure shows a comparison of Spring WebFlux and Spring MVC applications

  • Run the container

Spring WebFlux: Can run in Netty, Undertow and Servlet 3.1 containers and above. Spring MVC: can run in Servlet 3.1 containers

  • API for container and application interaction

Spring WebFlux: Uses the Reactor Stream Adapters Spring MVC: uses the Servlet API

  • security

Spring WebFlux: Uses Spring Security Reactor. Spring MVC: Uses synchronization Security frameworks such as Spring Security

  • Data is stored

Spring WebFlux: Use Spring Data Reactor Repositories to interact with databases, supporting Spring MVC (Mongo, Cassandra, Redis, CouchBase, R2DBC) : Use Spring Data Repositories to interact with the database

There are two ways to use WebFlux: Annotated Controllers and Functional Endpoints

  • Annotation: andSpringMvcThe annotation is consistent with that usedRestController,GetMapping,PostMappingSuch as annotation
  • Functional: Based on Lambda expressions, usingFunctionDescribe request endpoints

Annotation type (Annotated Controllers)

Spring Validation is supported using the RestController, GetMapping, and PostMapping annotations, consistent with SpringMvc annotations

Functional (Functional Endpoints)

The functional version of WebFlux uses Router and Handler to handle requests. The RouterFunction receives the HTTP request and finds the corresponding HandlerFunction. The HandlerFunction processes the HTTP request and returns a delayed ServerResponse

HandlerFunction

The HandlerFunction handles requests and responses using ServerRequest and ServerResponse

ServerRequest

ServerRequest provides method, URI, HEADERS, and Query parameters for accessing HTTP requests

         // Obtain the requested method
         HttpMethod method = serverRequest.method();

         // Get the request URI
         URI uri = serverRequest.uri();

         // Obtain the headers of the request
         ServerRequest.Headers headers = serverRequest.headers();

         // Get the query parameters with the specified key
         Optional<String> id = serverRequest.queryParam("id");
         // Obtain all query parameters for the request
         MultiValueMap<String, String> stringStringMultiValueMap = serverRequest.queryParams();

         // Obtain the request path
         RequestPath requestPath = serverRequest.requestPath();
Copy the code
Extract the request body and convert it to Mono or Flux
 // Get the request body and convert it to Mono
      
 Mono<String> string = serverRequest.bodyToMono(String.class);
 // Get the request body and convert it to Flux
      
 Flux<Person> people = serverRequest.bodyToFlux(User.class);
 Mono<String> string = serverRequest.body(BodyExtractors.toMono(String.class));
 Flux<Person> people = serverRequest.body(BodyExtractors.toFlux(User.class));
 
 // Retrieve the formData data
 Mono<MultiValueMap<String, String>> map = serverRequest.formData();
 // Get the multipartData data
 Mono<MultiValueMap<String, Part>> map1 = serverRequest.multipartData();
 // Obtain request body data and convert it to Flux
      
 Flux<Part> parts = serverRequest.body(BodyExtractors.toParts());
Copy the code

ServerResponse

ServerResponse can access the Response of an HTTP request. You can use builder mode to set the Response status, Response header, and Response body

 User user = User.builder()
         .id(1)
         .name("Zhang")
         .age(18)
         .build();
 
 return ServerResponse.ok().body(user, User.class);
Copy the code

Construct using Lambda expressionsHandlerFunction

 HandlerFunction<ServerResponse> helloWorld = request -> ServerResponse.ok().bodyValue("Hello World");
Copy the code

RouterFunction

The RouterFunction is responsible for finding the corresponding HandlerFunction for processing the request

 RouterFunction<ServerResponse> route = RouterFunctions.route()
     .GET("/person/{id}",, handler::getPerson)
     .POST("/person", handler::createPerson)
     .build();
Copy the code

RequestPredicate (RequestPredicate)

Methods like GET, POST, and so on have overloaded methods that accept request assertion parameters. If the request method and path match,RequestPredicate returning true will be processed by the corresponding HandlerFunction

RouterFunction<ServerResponse> route = route()
         // Accept limits the type of the request to JSON
        .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
        .POST("/person", handler::createPerson)
        .build();
Copy the code

Nested Routes

Use the PATH method to extract the same prefix for multiple requests

 RouterFunction<ServerResponse> route = route()
     .path("/person", builder -> builder 
         .GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
         .POST("/person", handler::createPerson))
     .build();
Copy the code

Parameter validation

You can use Spring Validation for parameter validation

  1. Add the dependent

             <dependency>
                 <groupId>org.hibernate.validator</groupId>
                 <artifactId>hibernate-validator</artifactId>
                 <version>6.2.0. The Final</version>
             </dependency>
    Copy the code
  2. Write an entity validator

     import org.springframework.validation.Validator;
     
     public class UserValidator implements Validator {
     
         @Override
         public boolean supports(Class
              aClass) {
             return User.class.equals(aClass);
         }
     
         @Override
         public void validate(Object o, Errors errors) {
     
             ValidationUtils.rejectIfEmpty(errors, "name"."name.empty");
             User user = (User) o;
             if (user.getAge() < 20) {
                 errors.rejectValue("age"."negativevalue");
             } else if (user.getAge() > 110) {
                 errors.rejectValue("age"."too.darn.old"); }}}Copy the code
  3. Application parameter verification

     public Mono<ServerResponse> addUser(ServerRequest serverRequest){
     
         // Bind the validation method in the doOnNext method
         serverRequest.bodyToMono(User.class) .doOnNext(this::validate);
     
         return ServerResponse.ok().body("122", String.class);
     }
     
     // Define the validation method
     private void validate(User user) {
         // Instantiate the entity validator
         Validator validator = new UserValidator();
         Errors errors = new BeanPropertyBindingResult(user, "user");
         validator.validate(user, errors);
         if (errors.hasErrors()) {
             throw newServerWebInputException(errors.toString()); }}Copy the code

Handlers can also through the Validator LocalValidatorFactoryBean into a global, using standard bean validation API (JSR – 303)