这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
Spring WebFlux
提供了注解式
和函数式
的使用方式。注解式
类似于Spring MVC
使用注解开发接口,函数式
使用RouterFunction (路由函数)
和HandlerFunction (处理函数)
开发接口。本文演示函数式
的开发方式。
示例
- 新建项目
2. 添加依赖
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请求
,并返回一个延迟的ServerResponse
7.1 编写HandlerFunction
HandlerFunction
负责处理请求和响应即从请求中获取参数处理后返回响应。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
注解配置RouterFunction
Bean。
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
近期评论