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


Spring WebFlux provides both annotated and functional usage. Annotatively, Spring MVC uses annotations to develop the interface, and functionally, RouterFunction and HandlerFunction to develop the interface. This article demonstrates a functional approach to development.

The sample

  1. New project

2. Add a dependencyr2dbc-mysqlisReactive MySQL connection driver.Spring Data R2DBCNeed to ber2dbc-mysqlWork together. The introduction ofspring-boot-starter-validationDependencies can be used for parameter validation.

<! -- Responsive MySQL driver -->
<dependency>
    <groupId>dev.miku</groupId>
    <artifactId>r2dbc-mysql</artifactId>
</dependency>

<! -- Spring parameter validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Copy the code
  1. Write yML configuration files

Spring Data R2DBC supports the Repository schema as Spring Data JPA does. Note that the Spring Data R2DBC URL starts with R2DBC instead of JDBC

server:
  port: 8099
spring:
  data:
    r2dbc:
      repositories:
        enabled: true  # Enable Repository mode

  r2dbc:
    url: r2dbc:mysql://**********:****/user? useUnicode=true&characterEncoding=UTF-8&useSSL=false
    username: * * * *
    password: * * * *
    pool:
      enabled: true
      max-size: 10
      initial-size: 10
      validation-query: select 1
  
Copy the code
  1. Write the create entity class

Spring WebFlux supports parameter validation using Spring Validation. For example, the name field in an entity class has a validation annotation that cannot be empty

@Data
@Table(value = "user")
public class User {

    @Id
    private Integer id;

    // NotBlank: validation annotation
    @notblank (message = "name is null ")
    private String name;
    
    // Java 8 new time type
    private LocalDate birthday;

    private String sex;
    
}
Copy the code

Cannot encode value of type ‘class java.util.Date ‘exception Cannot encode value of type ‘class java.util.Date

  1. To create the entity classRepository

Create an interface and inherit the R2dbcRepository interface. The R2dbcRepository interface provides responsive add, delete, modify and check methods similar to the JpaRepository interface in JPA.

public interface UserRepository extends R2dbcRepository<User.Integer> {}Copy the code

R2dbcRepositoryProvides the function of adding, deleting and modifying query, paging query, named query, JPQL and other functions, inherited as shown below:

  1. Write parameter validation classes

New UserValidator class and realize the org. Springframework. Validation. The Validator interface, efficacy for parameters

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"); }}Copy the code
  1. Writing the Controller

Spring WebFlux functionuseRouterFunction (Routing function)andHandlerFunction ()Develop the interface.RouterFunctionResponsible for receivingThe HTTP request, and find the correspondingHandlerFunction.HandlerFunctionTo deal withThe HTTP requestAnd return a delayedServerResponse7.1 writeHandlerFunction HandlerFunctionIt’s responsible for processing requests and responses, which is to take parameters from requests, process them, and return a response.HandlerFunctionuseServerRequestandServerResponseHandle requests and responses.HandlerFunctionIs a functional interface defined as follows:

Write User add, delete, change and check methods, all methods of the input type is ServerRequest, return value type is ServerResponse, to conform to the definition of HandlerFunction

@Component
public class UserHandlerFunction {

    @Resource
    private UserRepository userRepository;

    public Mono<ServerResponse> createUser(ServerRequest request){

        // Use the doOnNext method to validate when getting the parameter
        Mono<User> userMono = request.bodyToMono(User.class).doOnNext(this::validate);
        Flux<Integer> integerFlux = userRepository.saveAll(userMono).map(User::getId);
        return ServerResponse.ok().body(integerFlux, Integer.class);
    }


    public Mono<ServerResponse> getUsers(ServerRequest request){

        Flux<User> userFlux = userRepository.findAll();
        return ServerResponse.ok().body(userFlux, User.class);
    }

    public Mono<ServerResponse> getUserById(ServerRequest request){

        String id = request.pathVariable("id");
        Mono<User> userMono = userRepository.findById(Integer.valueOf(id));
        return ServerResponse.ok().body(userMono, User.class);
    }

    public Mono<ServerResponse> updateUser(ServerRequest request){

        Mono<User> userMono = request.bodyToMono(User.class);
        userRepository.saveAll(userMono);
        return ServerResponse.ok().bodyValue("Modification succeeded");
    }

    public Mono<ServerResponse> delUser(ServerRequest request){

        String id = request.pathVariable("id");
        userRepository.deleteById(Integer.valueOf(id));
        return ServerResponse.ok().bodyValue("Deletion successful"); }}// 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

7.2 Writing A RouterFunction A RouterFunction is responsible for finding a corresponding HandlerFunction for processing a request.

Create a new Configuration class to implement the WebFluxConfigurer interface with @Configuration and @EnableWebFlux annotations, and configure the RouterFunctionBean using the @Bean annotation in the Configuration class.

RouterFunctions is a utility class for RouterFunctions

@Configuration
@EnableWebFlux
public class WebFLuxRoute implements WebFluxConfigurer {

    @Bean
    public RouterFunction<ServerResponse> userRouterFunction(UserHandlerFunction userHandlerFunction) {

        RouterFunction<ServerResponse> routerFunction = RouterFunctions.route()
                .GET("/users/{id}", userHandlerFunction::getUserById)
                .GET("/users", userHandlerFunction::getUsers)
                .POST("/users", userHandlerFunction::createUser)
                .PUT("/users", userHandlerFunction::updateUser)
                .DELETE("/users/{id}", userHandlerFunction::delUser)
                .build();

        returnrouterFunction; }}Copy the code

test

  1. The new User

If the name field is not passed during the addition, the effect fails

  1. Query all users

  1. Query the User based on the ID

  1. Modify the User

  1. Delete the User