这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战
WebFlux是Spring Framework 5.0 发布的基于Reactor的异步、非阻塞的web框架,使用WebFlux可以充分的利用计算的多核优势提升系统的吞吐量和伸缩性。
WebFlux并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性
下图展示了Spring WebFlux和Spring MVC的应用对比
- 运行容器
Spring WebFlux: 可以运行在Netty,Undertow和Servlet 3.1以上的容器中Spring MVC: 可以运行在Servlet 3.1容器中 - 容器与应用交互API
Spring WebFlux: 使用Reactor Stream AdaptersSpring MVC: 使用Servlet API - 安全
Spring WebFlux: 使用Spring Security Reactor安全框架Spring MVC: 使用Spring Security等同步安全框架 - 数据存储
Spring WebFlux:使用Spring Data Reactor Repositories和数据库交互,支持(Mongo、Cassandra、Redis、CouchBase、R2DBC)Spring MVC: 使用Spring Data Repositories和数据库交互
WebFlux提供了两种使用方式:注解式(Annotated Controllers)和 函数式(Functional Endpoints)
- 注解式:和
SpringMvc的注解一致,使用RestController、GetMapping、PostMapping等注解 - 函数式:基于Lambda表达式,使用
Function描述请求端点
注解式(Annotated Controllers)
和SpringMvc的注解一致,使用RestController、GetMapping、PostMapping等注解,支持Spring validation参数效验
函数式(Functional Endpoints)
WebFlux的函数式使用Router和Handler处理请求。RouterFunction负责接收HTTP请求,并找到对应的HandlerFunction,HandlerFunction处理HTTP请求,并返回一个延迟的ServerResponse
HandlerFunction
HandlerFunction使用ServerRequest和ServerResponse处理请求和响应
ServerRequest
ServerRequest提供了访问HTTP请求的method, URI, headers和 query parameters
// 获取请求的method
HttpMethod method = serverRequest.method();
// 获取请求的URI
URI uri = serverRequest.uri();
// 获取请求的headers
ServerRequest.Headers headers = serverRequest.headers();
// 获取指定key的查询参数
Optional<String> id = serverRequest.queryParam("id");
// 获取请求全部的查询参数
MultiValueMap<String, String> stringStringMultiValueMap = serverRequest.queryParams();
// 获取请求路径
RequestPath requestPath = serverRequest.requestPath();
提取request body并转成Mono或Flux
// 获取request body并转成Mono<String>
Mono<String> string = serverRequest.bodyToMono(String.class);
// 获取request body并转成Flux<User>
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));
// 获取formData数据
Mono<MultiValueMap<String, String>> map = serverRequest.formData();
// 获取multipartData数据
Mono<MultiValueMap<String, Part>> map1 = serverRequest.multipartData();
// 获取request body数据,并转成Flux<Part>
Flux<Part> parts = serverRequest.body(BodyExtractors.toParts());
ServerResponse
ServerResponse可以访问HTTP请求的Response, 可以使用builder模式设置响应状态、响应头和响应体
User user = User.builder()
.id(1)
.name("张三")
.age(18)
.build();
return ServerResponse.ok().body(user, User.class);
使用Lambda表达式构造HandlerFunction
HandlerFunction<ServerResponse> helloWorld = request -> ServerResponse.ok().bodyValue("Hello World");
RouterFunction
RouterFunction负责为请求找到对应的HandlerFunction进行处理
RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/person/{id}",, handler::getPerson)
.POST("/person", handler::createPerson)
.build();
RequestPredicate(请求断言)
GET、POST等方法都有用于接受请求断言参数的重载方法。请求方法和路径匹配后,RequestPredicate返回true的请求才会被对应的HandlerFunction处理
RouterFunction<ServerResponse> route = route()
// accept限制了该请求的类型是JSON格式
.GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
.POST("/person", handler::createPerson)
.build();
Nested Routes(嵌套路由)
使用path方法可以将多个请求的相同前缀提取出来
RouterFunction<ServerResponse> route = route()
.path("/person", builder -> builder
.GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
.POST("/person", handler::createPerson))
.build();
参数验证
可以使用Spring validation进行参数验证
-
添加依赖
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.2.0.Final</version> </dependency> -
编写实体的验证器
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"); } } } -
应用参数验证
public Mono<ServerResponse> addUser(ServerRequest serverRequest){ // 在doOnNext方法中绑定验证方法 serverRequest.bodyToMono(User.class) .doOnNext(this::validate); return ServerResponse.ok().body("122", String.class); } // 定义验证方法 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()); } }
Handlers 也可以通过
LocalValidatorFactoryBean注入一个全局的Validator,使用standard bean validation API(JSR-303)验证