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
- New project
2. Add a dependencyr2dbc-mysql
isReactive MySQL connection driver
.Spring Data R2DBC
Need to ber2dbc-mysql
Work together. The introduction ofspring-boot-starter-validation
Dependencies 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
- 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
- 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
- To create the entity class
Repository
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
R2dbcRepository
Provides the function of adding, deleting and modifying query, paging query, named query, JPQL and other functions, inherited as shown below:
- 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
- Writing the Controller
Spring WebFlux function
useRouterFunction (Routing function)
andHandlerFunction ()
Develop the interface.RouterFunction
Responsible for receivingThe HTTP request
, and find the correspondingHandlerFunction
.HandlerFunction
To deal withThe HTTP request
And return a delayedServerResponse
7.1 writeHandlerFunction
HandlerFunction
It’s responsible for processing requests and responses, which is to take parameters from requests, process them, and return a response.HandlerFunction
useServerRequest
andServerResponse
Handle requests and responses.HandlerFunction
Is 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
- The new User
If the name field is not passed during the addition, the effect fails
- Query all users
- Query the User based on the ID
- Modify the User
- Delete the User