这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
Spring WebFlux提供了注解式和函数式的使用方式。注解式类似于Spring MVC使用注解开发接口,函数式使用RouterFunction (路由函数)和HandlerFunction (处理函数)开发接口。本文演示函数式的开发方式。
示例
- 新建项目
- 添加依赖
r2dbc-mysql是响应式的MySQL连接驱动,Spring Data R2DBC需要r2dbc-mysql配合工作。引入spring-boot-starter-validation依赖可以进行参数效验。
<!-- 响应式的MySQL驱动-->
<dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
</dependency>
<!-- Spring参数效验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
- 编写yml配置文件
Spring Data R2DBC和Spring Data JPA一样支持Repository模式。需要注意的是Spring Data R2DBC的url使用r2dbc开头而不是jdbc
server:
port: 8099
spring:
data:
r2dbc:
repositories:
enabled: true # 开启Repository模式
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
- 编写创建实体类
Spring WebFlux支持使用spring validation进行参数效验。如实体类中的name字段加上了不能为空的效验注解
@Data
@Table(value = "user")
public class User {
@Id
private Integer id;
// NotBlank:效验注解
@NotBlank(message = "name为空")
private String name;
// Java 8 新时间类型
private LocalDate birthday;
private String sex;
}
时间类型不能使用
Date,不然会出现Cannot encode value of type 'class java.util.Date异常
- 创建实体类的
Repository
创建接口,继承R2dbcRepository接口。R2dbcRepository接口提供了响应式的增删改查方法类似于JPA中的JpaRepository接口。
public interface UserRepository extends R2dbcRepository<User, Integer> {
}
R2dbcRepository提供了增删改查、分页查询、命名查询、jpql等功能,继承图如下所示:
- 编写参数验证类
新建
UserValidator类并实现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");
}
}
- 编写Controller
Spring WebFlux 函数式使用RouterFunction (路由函数)和HandlerFunction (处理函数)开发接口。RouterFunction负责接收HTTP请求,并找到对应的HandlerFunction,HandlerFunction处理HTTP请求,并返回一个延迟的ServerResponse7.1 编写HandlerFunctionHandlerFunction负责处理请求和响应即从请求中获取参数处理后返回响应。HandlerFunction使用ServerRequest和ServerResponse处理请求和响应。HandlerFunction是一个函数式接口,定义如下:
编写User的增删改查方法,所有方法的入参类型是ServerRequest,返回值类型是ServerResponse,以符合HandlerFunction的定义
@Component
public class UserHandlerFunction {
@Resource
private UserRepository userRepository;
public Mono<ServerResponse> createUser(ServerRequest request){
// 使用doOnNext方法在获取参数时进行验证
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("修改成功");
}
public Mono<ServerResponse> delUser(ServerRequest request){
String id = request.pathVariable("id");
userRepository.deleteById(Integer.valueOf(id));
return ServerResponse.ok().bodyValue("删除成功");
}
}
// 定义验证方法
private void validate(User user) {
// 实例化实体验证器
Validator validator = new UserValidator();
Errors errors = new BeanPropertyBindingResult(user, "user");
validator.validate(user, errors);
if (errors.hasErrors()) {
throw new ServerWebInputException(errors.toString());
}
}
7.2 编写RouterFunction
RouterFunction负责为请求找到对应的HandlerFunction进行处理。
新建一个配置类实现WebFluxConfigurer接口,并加@Configuration和@EnableWebFlux注解,在配置类里面使用@Bean注解配置RouterFunctionBean。
RouterFunctions是RouterFunction的工具类
@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();
return routerFunction;
}
}
测试
- 新增User
新增时不传name字段时,效验未通过
-
查询所有User
-
根据id查询User
-
修改User
-
删除User