上一篇[29.1.13、CORS 支持]
下一篇[29.3、JAX-RS 和 Jersey]

英文原文:https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-developing-web-applications.html#boot-features-developing-web-applications
GitHub:https://github.com/jijicai/Spring/tree/master/spring-boot
29.2 Spring WebFlux 框架
Spring WebFlux 是 Spring Framework 5.0 中引入的新的反应式 web 框架。与 Spring MVC 不同,它不需要 Servlet API ,完全异步且非阻塞,并通过 Reactor 项目实现反应式流规范。
Spring WebFlux 有两种风格:函数式和基于注解的。基于注解的模型非常接近 Spring MVC 模型,如下面示例所示:

@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
}
函数变体“WebFlux.fn”将路由配置与请求的实际处理分离,如下面示例所示:

@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}
WebFlux 是 Spring 框架的一部分,其参考文档中提供了详细信息。(https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web-reactive.html#webflux-fn )
提示:你可以定义任意多个 RouterFunction bean 来模块化路由器的定义。如果需要应用优先级,可以对 beans 进行排序。
要开始,请将 spring-boot-starter-webflux 模块添加到应用程序中。
注释:在应用程序中同时添加 spring-boot-starter-web 和 spring-boot-starter-webflux 模块会导致 Spring Boot 自动配置 Spring MVC,而不是 WebFlux。之所以选择这种行为,是因为许多 Spring 开发者将 spring-boot-starter-webflux 添加到他们的 Spring MVC 应用程序中,以使用反应式 WebClient。你仍然可以通过将所选应用程序类型设置为 SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) 来强制你的选择。
29.2.1、Spring WebFlux 自动配置
Spring Boot 为 Spring WebFlux 提供了自动配置,它可以很好地与大多数应用程序一起工作。
自动配置在 Spring 默认设置的基础上添加了以下特性:
(1)为 HttpMessageReader 和 HttpMessageWriter 实例配置编解码器(本文档稍后介绍)。
(2)支持为静态资源提供服务,包括对 Webjar 的支持(稍后将在本文中描述)。
如果你想保留 Spring Boot WebFlux 的特性,并且想添加额外的 WebFlux 配置,那么你可以添加自己的类型为 WebFluxConfigurer 类,但是不需要 @EnableWebFlux。
如果您想完全控制 Spring WebFlux,可以添加自己的 @Configuration,并用 @EnableWebFlux 注解。
29.2.2、带有 HttpMessageReaders 和 HttpMessageWriters 的 HTTP 编解码器
Spring WebFlux 使用 HttpMessageReader 和 HttpMessageWriter 接口来转换 HTTP 请求和响应。它们是用 CodecConfigurer 配置的,通过查看类路径中可用的库来获得合理的默认值。
Spring Boot 通过使用 CodecCustomizer 实例应用进一步的定制。例如,spring.jackson.* 配置键应用于 Jackson 编解码器。
如果需要添加或自定义编解码器,则可以创建自定义 CodecCustomizer 组件,如下面示例所示:

import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}
}
你还可以利用 Boot 的自定义 JSON 序列化器和反序列化器。(https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/html/boot-features-developing-web-applications.html#boot-features-json-components )
29.2.3、静态内容
默认情况下,Spring Boot 从类路径中名为 /static(或 /public 或 /resources 或 /META-INF/resources)的目录提供静态内容。它使用 Spring WebFlux 中的 ResourceWebHandler,这样你就可以通过添加自己的 WebFluxConfigurer 并重写 addResourceHandlers 方法来修改该行为。
默认情况下,资源被映射到 /**,但是你可以通过设置 spring.webflux.static-path-pattern 属性来优化它。例如,可以将所有资源重新定位到 /resources/** 中,如下所示:
spring.webflux.static-path-pattern=/resources/**
还可以使用 spring.resources.static-locations 自定义静态资源位置。这样做会将默认值替换为目录位置列表。如果这样做,默认的欢迎页面检测将切换到你的自定义位置。因此,如果在启动时在你的任何位置有 index.html,它就是应用程序的主页。
除了前面的列出的“标准”静态资源位置之外,Webjars 内容还有一个特殊情况。如果以 Webjars 格式打包,那么路径为 /webjars/** 的任何资源都将从 jar 文件中获得。
提示:Spring WebFlux 应用程序并不严格依赖于 Servlet API,因此它们不能作为 war 文件部署,也不能使用 src/main/webapp 目录。
29.2.4、模板引擎
除了 REST web 服务,你还可以使用 Spring WebFlux 来提供动态 HTML 内容。Spring WebFlux 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 Mustache。
Spring Boot 包括对以下模板引擎的自动配置支持:
(1)FreeMarker(https://freemarker.apache.org/docs/ )
(2)Thymeleaf(https://www.thymeleaf.org/ )
(3)Mustache(https://mustache.github.io/ )
当你使用这些具有默认配置的模板引擎之一时,你的模板将自动从 src/main/resources/templates 中获取。
29.2.5、错误处理
Spring Boot 提供了一个 WebExceptionHandler,它以合理的方式处理所有错误。它在处理顺序中的位置紧接在 WebFlux 提供的处理器之前,后者被认为是最后一个处理器。对于机器客户端,它生成一个 JSON 响应,其中包含错误、HTTP 状态和异常消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误处理器以 HTML 格式呈现相同的数据。你还可以提供自己的 HTML 模板来显示错误(请参阅下一节)。
定制此功能的第一步通常涉及使用现有的机制,但替换或扩充错误内容。为此,可以添加 ErrorAttributes 类型的 bean。
要更改错误处理行为,可以实现 ErrorWebExceptionHandler 并注册该类型的 bean 定义。由于 WebExceptionHandler 是非常低级的,Spring Boot 还提供了一个方便的 AbstractErrorWebExceptionHandler,使你能够以 WebFlux 函数的方式处理错误,如下面示例所示:

public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
为了获得更完整的图景,还可以直接将 DefaultErrorWebExceptionHandler 子类化并重写特定的方法。
自定义错误页
如果要显示给定状态码的自定义 HTML 错误页,则可以将文件添加到 /error 文件夹。错误页可以是静态 HTML(即添加到任何静态资源文件夹下)或使用模板生成。文件名应为确切的状态码或序列掩码。
例如,要将 404 映射到静态 HTML 文件,文件夹结构如下:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用 Mustache 模板映射所有 5xx 错误,文件夹结构如下:

src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
29.2.6、Web 过滤器
Spring WebFlux 提供了一个 WebFilter 接口,可以实现该接口来过滤 HTTP 请求-响应交换。在应用程序上下文中找到的 WebFilter bean 将自动用于过滤每个 exchange。
如果过滤器的顺序很重要,那么它们可以实现 Ordered 接口或用 @Order 注解。Spring Boot 自动配置可以为你配置 web 过滤器。执行此操作时,将使用下表中显示的顺序:

Web Filter Order
MetricsWebFilter Ordered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy(Spring Security) -100
HttpTraceWebFilter Ordered.LOWEST_PRECEDENCE - 10
上一篇[29.1.13、CORS 支持]
下一篇[29.3、JAX-RS 和 Jersey]