On this page
28. 开发 Web 应用程序
Spring Boot 非常适合 Web 应用程序开发。您可以使用嵌入式 Tomcat,Jetty,Undertow 或 Netty 创建独立的 HTTP 服务器。大多数 Web 应用程序都使用spring-boot-starter-web
模块来快速启动和运行。您还可以选择使用spring-boot-starter-webflux
模块来构建响应式 Web 应用程序。
如果尚未开发 Spring Boot Web 应用程序,则可以遵循“ Hello World!”。 * Getting started *部分中的示例。
28.1“ Spring Web MVC 框架”
Spring Web MVC 框架(通常简称为“ Spring MVC”)是一个丰富的“模型视图控制器” Web 框架。 Spring MVC 使您可以创建特殊的@Controller
或@RestController
bean 来处理传入的 HTTP 请求。控制器中的方法通过使用@RequestMapping
CommentsMap 到 HTTP。
以下代码显示了提供 JSON 数据的典型@RestController
:
@RestController
@RequestMapping(value="/users")
public class MyRestController {
@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}
}
Spring MVC 是核心 Spring Framework 的一部分,有关详细信息,请参见reference documentation。 spring.io/guides提供了一些涵盖 Spring MVC 的指南。
28.1.1 Spring MVC 自动配置
Spring Boot 为 Spring MVC 提供了自动配置,可与大多数应用程序完美配合。
自动配置在 Spring 的默认值之上添加了以下功能:
包括
ContentNegotiatingViewResolver
和BeanNameViewResolver
bean。支持提供静态资源,包括对 WebJars 的支持(覆盖本文档后面)。
自动注册
Converter
,GenericConverter
和Formatter
bean。支持
HttpMessageConverters
(包含本文档后面)。自动注册
MessageCodesResolver
(已发现本文档后面)。静态
index.html
支持。自定义
Favicon
支持(包含本文档后面)。自动使用
ConfigurableWebBindingInitializer
bean(包含本文档后面)。
如果您想保留 Spring Boot MVC 功能,并且想要添加其他MVC configuration(拦截器,格式化程序,视图控制器和其他功能),则可以添加自己的@Configuration
类,类型为WebMvcConfigurer
,但是 没有 @EnableWebMvc
。如果希望提供RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
的自定义实例,则可以声明WebMvcRegistrationsAdapter
实例以提供此类组件。
如果要完全控制 Spring MVC,则可以添加自己的@Configuration
并以@EnableWebMvc
Comments。
28.1.2 HttpMessageConverters
Spring MVC 使用HttpMessageConverter
接口转换 HTTP 请求和响应。开箱即用中包含明智的默认设置。例如,可以将对象自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展(如果可用)或通过使用 JAXB(如果 Jackson XML 扩展不可用))。默认情况下,字符串以UTF-8
编码。
如果需要添加或定制转换器,则可以使用 Spring Boot 的HttpMessageConverters
类,如以下 Lists 所示:
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
上下文中存在的任何HttpMessageConverter
bean 都将添加到转换器列表中。您也可以用相同的方法覆盖默认转换器。
28.1.3 自定义 JSON 序列化器和反序列化器
如果使用 Jackson 来序列化和反序列化 JSON 数据,则可能要编写自己的JsonSerializer
和JsonDeserializer
类。自定义序列化器通常是通过模块在 Jackson 注册,但是 Spring Boot 提供了@JsonComponent
Comments,这使得直接注册 Spring Bean 更加容易。
您可以直接在JsonSerializer
或JsonDeserializer
实现中使用@JsonComponent
Comments。您还可以在包含序列化器/反序列化器作为内部类的类上使用它,如以下示例所示:
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
public static class Serializer extends JsonSerializer<SomeObject> {
// ...
}
public static class Deserializer extends JsonDeserializer<SomeObject> {
// ...
}
}
ApplicationContext
中的所有@JsonComponent
bean 都会自动向 Jackson 进行注册。因为@JsonComponent
是用@Component
进行元 Comments 的,所以通常的组件扫描规则适用。
Spring Boot 还提供了JsonObjectSerializer和JsonObjectDeserializerBase Class,这些 Base Class 在序列化对象时为标准 Jackson 版本提供了有用的替代方法。有关详细信息,请参见 Javadoc 中的JsonObjectSerializer和JsonObjectDeserializer。
28.1.4 MessageCodesResolver
Spring MVC 有一种生成错误代码的策略,该错误代码用于从绑定错误MessageCodesResolver
渲染错误消息。如果设置spring.mvc.message-codes-resolver.format
属性PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,Spring Boot 会为您创建一个(请参见DefaultMessageCodesResolver.Format中的枚举)。
28.1.5 静态内容
默认情况下,Spring Boot 从 Classpath 中名为/static
(或/public
或/resources
或/META-INF/resources
)的目录或ServletContext
的根目录中提供静态内容。它使用 Spring MVC 中的ResourceHttpRequestHandler
,因此您可以通过添加自己的WebMvcConfigurer
并覆盖addResourceHandlers
方法来修改该行为。
在独立的 Web 应用程序中,还启用了容器中的默认 servlet,并将其用作后备,如果 Spring 决定不处理ServletContext
的根,则从ServletContext
的根开始提供内容。在大多数情况下,这不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过DispatcherServlet
处理请求。
默认情况下,资源 Map 在/**
上,但是您可以使用spring.mvc.static-path-pattern
属性对其进行调整。例如,将所有资源重定位到/resources/**
可以实现如下:
spring.mvc.static-path-pattern=/resources/**
您还可以使用spring.resources.static-locations
属性来自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径"/"
也会自动添加为位置。
除了前面提到的“标准”静态资源位置以外,还对Webjars content进行了特殊处理。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有/webjars/**
路径的任何资源。
Tip
如果您的应用程序打包为 jar,则不要使用src/main/webapp
目录。尽管此目录是一个通用标准,但它仅在 war 打包中有效,并且在生成 jar 时,大多数构建工具都将其忽略。
Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用案例,例如缓存清除静态资源或对 Webjars 使用版本无关的 URL。
要对 Webjar 使用版本无关的 URL,请添加webjars-locator-core
依赖项。然后声明您的 Webjar。以 jQuery 为例,在"/webjars/jquery/x.y.z/jquery.min.js"
中添加"/webjars/jquery/jquery.min.js"
结果。其中x.y.z
是 Webjar 版本。
Note
如果使用 JBoss,则需要声明webjars-locator-jboss-vfs
依赖性而不是webjars-locator-core
。否则,所有 Webjar 都解析为404
。
要使用缓存清除,以下配置为所有静态资源配置了缓存清除解决方案,从而有效地在 URL 中添加了内容哈希,例如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
Note
得益于为 Thymeleaf 和 FreeMarker 自动配置的ResourceUrlEncodingFilter
,在运行时将资源链接重写为模板。使用 JSP 时,您应该手动声明此过滤器。当前不自动支持其他模板引擎,但可以与自定义模板宏/帮助器一起使用,并可以使用ResourceUrlProvider。
例如,当使用 JavaScript 模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也受支持并且可以组合的原因。 “固定”策略在 URL 中添加静态版本字符串,而不会更改文件名,如以下示例所示:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
通过这种配置,位于"/js/lib/"
下的 JavaScript 模块使用固定的版本控制策略("/v12/js/lib/mymodule.js"
),而其他资源仍使用内容版本(<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
)。
有关更多受支持的选项,请参见ResourceProperties。
Tip
此功能已在专用的blog post和 Spring Framework 的reference documentation中进行了详细描述。
28.1.6 欢迎页面
Spring Boot 支持静态和模板欢迎页面。它首先在配置的静态内容位置中查找index.html
文件。如果未找到,则它将寻找index
模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。
28.1.7 自定义图标
Spring Boot 在配置的静态内容位置和 Classpath 的根目录(按此 Sequences)中查找favicon.ico
。如果存在这样的文件,它将自动用作应用程序的收藏夹图标。
28.1.8 路径匹配和内容协商
Spring MVC 可以通过查看请求路径并将其匹配到应用程序中定义的 Map(例如 Controller 方法上的@GetMapping
Comments),将传入的 HTTP 请求 Map 到处理程序。
Spring Boot 默认选择禁用后缀模式匹配,这意味着诸如"GET /projects/spring-boot.json"
之类的请求将不会与@GetMapping("/projects/spring-boot")
Map 相匹配。这被视为Spring MVC 应用程序的最佳实践。过去,此功能主要用于未发送正确的“ Accept”请求 Headers 的 HTTP Client 端。我们需要确保将正确的 Content Type 发送给 Client 端。如今,内容协商已变得更加可靠。
还有其他处理 HTTP Client 端的方法,这些方法不能始终发送正确的“ Accept”请求 Headers。除了使用后缀匹配,我们还可以使用查询参数来确保将"GET /projects/spring-boot?format=json"
之类的请求 Map 到@GetMapping("/projects/spring-boot")
:
spring.mvc.contentnegotiation.favor-parameter=true
# We can change the parameter name, which is "format" by default:
# spring.mvc.contentnegotiation.parameter-name=myparam
# We can also register additional file extensions/media types with:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
如果您了解了注意事项,但仍希望您的应用程序使用后缀模式匹配,则需要以下配置:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
另外,与其打开所有后缀模式,不如只支持注册的后缀模式,这是更安全的:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
# You can also register additional file extensions/media types with:
# spring.mvc.contentnegotiation.media-types.adoc=text/asciidoc
28.1.9 ConfigurableWebBindingInitializer
Spring MVC 使用WebBindingInitializer
来为特定请求初始化WebDataBinder
。如果创建自己的ConfigurableWebBindingInitializer
@Bean
,Spring Boot 会自动将 Spring MVC 配置为使用它。
28.1.10 模板引擎
除了 REST Web 服务之外,您还可以使用 Spring MVC 来提供动态 HTML 内容。 Spring MVC 支持各种模板技术,包括 Thymeleaf,FreeMarker 和 JSP。同样,许多其他模板引擎包括他们自己的 Spring MVC 集成。
Spring Boot 包括对以下模板引擎的自动配置支持:
Tip
如果可能,应避免使用 JSP。与嵌入式 servlet 容器一起使用时,有多个known limitations。
当您使用默认配置的这些模板引擎之一时,将从src/main/resources/templates
自动拾取模板。
Tip
根据您运行应用程序的方式,IntelliJ IDEA 对 Classpath 的排序方式不同。与使用 Maven 或 Gradle 或从打包的 jar 运行应用程序时,从 IDE 的 Main 方法运行应用程序的 Sequences 会有所不同。这可能会导致 Spring Boot 无法在 Classpath 上找到模板。如果遇到此问题,则可以在 IDE 中重新排序 Classpath,以首先放置模块的类和资源。另外,您可以配置模板前缀以搜索 Classpath 上的每个templates
目录,如下所示:classpath*:/templates/
。
28.1.11 错误处理
默认情况下,Spring Boot 提供了一个/error
Map,可以明智地处理所有错误,并且已在 servlet 容器中注册为“全局”错误页面。对于机器 Client 端,它将生成 JSON 响应,其中包含错误,HTTP 状态和异常消息的详细信息。对于浏览器 Client 端,存在一个“ whitelabel”错误视图,该视图以 HTML 格式渲染相同的数据(要对其进行自定义,请添加解析为error
的View
)。要完全替换默认行为,可以实现ErrorController
并注册该类型的 Bean 定义,或添加ErrorAttributes
类型的 Bean 以使用现有机制但替换其内容。
Tip
BasicErrorController
可用作自定义ErrorController
的 Base Class。如果要为新的 Content Type 添加处理程序(默认是专门处理text/html
并为其他所有内容提供后备功能),则此功能特别有用。为此,扩展BasicErrorController
,添加具有produces
属性的@RequestMapping
的公共方法,并创建新类型的 bean。
您还可以定义带有@ControllerAdvice
Comments 的类,以自定义 JSON 文档以针对特定的控制器和/或异常类型返回,如以下示例所示:
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
在前面的示例中,如果在与AcmeController
相同的程序包中定义的控制器抛出YourException
,则使用CustomErrorType
POJO 的 JSON 表示代替ErrorAttributes
表示。
自定义错误页面
如果要显示给定状态代码的自定义 HTML 错误页面,可以将文件添加到/error
文件夹。错误页面可以是静态 HTML(即添加到任何静态资源文件夹下),也可以使用模板来构建。文件名应为确切的状态代码或系列掩码。
例如,要将404
Map 到静态 HTML 文件,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用 FreeMarker 模板 Map 所有5xx
错误,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>
对于更复杂的 Map,还可以添加实现ErrorViewResolver
接口的 bean,如以下示例所示:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map<String, Object> model) {
// Use the request or status to optionally return a ModelAndView
return ...
}
}
您还可以使用常规的 Spring MVC 功能,例如@ExceptionHandler methods和@ControllerAdvice。 ErrorController
然后接收任何未处理的异常。
Map Spring MVC 之外的错误页面
对于不使用 Spring MVC 的应用程序,可以使用ErrorPageRegistrar
接口直接注册ErrorPages
。此抽象直接与基础嵌入式 servlet 容器一起使用,即使您没有 Spring MVC DispatcherServlet
,也可以使用。
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}
// ...
private static class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
Note
如果您注册的ErrorPage
的路径最终由Filter
处理(这在某些非 Spring Web 框架(如 Jersey 和 Wicket)中很常见),则必须将Filter
明确注册为ERROR
调度程序,如图所示。下面的例子:
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
return registration;
}
请注意,默认的FilterRegistrationBean
不包括ERROR
调度程序类型。
注意:Spring Boot 部署到 servlet 容器时,将使用其错误页面过滤器将具有错误状态的请求转发到相应的错误页面。如果尚未提交响应,则只能将请求转发到正确的错误页面。缺省情况下,WebSphere Application Server 8.0 和更高版本在成功完成 servlet 的服务方法后提交响应。您应该通过将com.ibm.ws.webcontainer.invokeFlushAfterService
设置为false
来禁用此行为。
12 年 12 月 28 日 Spring HATEOAS
如果您开发使用超媒体的 RESTful API,Spring Boot 将为 Spring HATEOAS 提供自动配置,该配置可与大多数应用程序很好地配合使用。自动配置取代了使用@EnableHypermediaSupport
的需要,并注册了许多 Bean 以简化基于超媒体的应用程序的构建,包括LinkDiscoverers
(用于 Client 端支持)和ObjectMapper
,这些ObjectMapper
被配置为将响应正确地编组为所需的表示形式。 ObjectMapper
是通过设置各种spring.jackson.*
属性来定制的,或者通过设置Jackson2ObjectMapperBuilder
bean 来定制(如果存在)。
您可以使用@EnableHypermediaSupport
来控制 Spring HATEOAS 的配置。请注意,这样做会禁用前面介绍的ObjectMapper
自定义。
28.1.13 CORS 支持
跨域资源共享(CORS)是由most browsers实现的W3C specification,可让您灵活地指定授权哪种类型的跨域请求,而不是使用一些安全性和功能不强的方法(例如 IFRAME 或 JSONP)。
从 4.2 版本开始,Spring MVC supports CORS。在 Spring Boot 应用程序中使用控制器方法 CORS 配置和@CrossOrigin注解不需要任何特定的配置。可以通过使用自定义的addCorsMappings(CorsRegistry)
方法注册WebMvcConfigurer
bean 来定义全局 CORS 配置,如以下示例所示:
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}
28.2“ Spring WebFlux 框架”
Spring WebFlux 是 Spring Framework 5.0 中引入的新的响应式 Web 框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步和非阻塞的,并通过反应堆项目实现Reactive Streams规范。
Spring WebFlux 有两种形式:功能性的和基于 Comments 的。基于 Comments 的模型非常类似于 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 Framework 的一部分,其reference documentation中提供了详细信息。
Tip
您可以根据需要定义尽可能多的RouterFunction
bean,以对 Router 的定义进行模块化。如果需要应用优先级,可以 Order Bean。
首先,将spring-boot-starter-webflux
模块添加到您的应用程序中。
Note
在应用程序中同时添加spring-boot-starter-web
和spring-boot-starter-webflux
模块会导致 Spring Boot 自动配置 Spring MVC,而不是 WebFlux。之所以选择这种行为,是因为许多 Spring 开发人员将spring-boot-starter-webflux
添加到他们的 Spring MVC 应用程序中以使用 ReactiveWebClient
。您仍然可以通过将选定的应用程序类型设置为SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)
来强制执行选择。
28.2.1 Spring WebFlux 自动配置
Spring Boot 为 Spring WebFlux 提供了自动配置,可与大多数应用程序完美配合。
自动配置在 Spring 的默认值之上添加了以下功能:
如果您想保留 Spring Boot WebFlux 功能,并且想要添加其他WebFlux configuration,则可以添加自己的@Configuration
类,类型为WebFluxConfigurer
,但 没有 @EnableWebFlux
。
如果要完全控制 Spring WebFlux,则可以添加带有@EnableWebFlux
Comments 的自己的@Configuration
。
28.2.2 带有 HttpMessageReaders 和 HttpMessageWriters 的 HTTP 编解码器
Spring WebFlux 使用HttpMessageReader
和HttpMessageWriter
接口转换 HTTP 请求和响应。通过查看 Classpath 中可用的库,将它们配置为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 序列化器和反序列化器。
28.2.3 静态内容
默认情况下,Spring Boot 从 Classpath 中名为/static
(或/public
或/resources
或/META-INF/resources
)的目录中提供静态内容。它使用 Spring WebFlux 中的ResourceWebHandler
,以便您可以通过添加自己的WebFluxConfigurer
并覆盖addResourceHandlers
方法来修改该行为。
默认情况下,资源 Map 在/**
上,但是您可以通过设置spring.webflux.static-path-pattern
属性对其进行调整。例如,将所有资源重定位到/resources/**
可以实现如下:
spring.webflux.static-path-pattern=/resources/**
您还可以使用spring.resources.static-locations
自定义静态资源位置。这样做会将默认值替换为目录位置列表。如果这样做,默认的欢迎页面检测将切换到您的自定义位置。因此,如果启动时您的任何位置都存在index.html
,则它是应用程序的主页。
除了前面列出的“标准”静态资源位置之外,Webjars content也是一种特殊情况。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有/webjars/**
路径的任何资源。
Tip
Spring WebFlux 应用程序不严格依赖 Servlet API,因此不能将它们部署为 war 文件,也不使用src/main/webapp
目录。
28.2.4 模板引擎
除了 REST Web 服务之外,您还可以使用 Spring WebFlux 来提供动态 HTML 内容。 Spring WebFlux 支持多种模板技术,包括 Thymeleaf,FreeMarker 和 Mustache。
Spring Boot 包括对以下模板引擎的自动配置支持:
当您使用默认配置的这些模板引擎之一时,将从src/main/resources/templates
自动拾取模板。
28.2.5 错误处理
Spring Boot 提供了一个WebExceptionHandler
,可以明智地处理所有错误。它在处理 Sequences 中的位置紧靠 WebFlux 提供的处理程序之前,该处理程序被认为是最后一个。对于机器 Client 端,它将生成 JSON 响应,其中包含错误,HTTP 状态和异常消息的详细信息。对于浏览器 Client 端,有一个“ whitelabel”错误处理程序,以 HTML 格式渲染相同的数据。您还可以提供自己的 HTML 模板来显示错误(请参见next section)。
定制此功能的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,您可以添加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
Map 到静态 HTML 文件,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用 Mustache 模板 Map 所有5xx
错误,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
28.2.6 网页过滤器
Spring WebFlux 提供了一个WebFilter
接口,可以实现该接口来过滤 HTTP 请求-响应交换。在应用程序上下文中找到的WebFilter
bean 将自动用于过滤每次交换。
在过滤器 Sequences 很重要的地方,它们可以实现Ordered
或用@Order
Comments。 Spring Boot 自动配置可能会为您配置 Web 过滤器。这样做时,将使用下表中显示的 Sequences:
Web Filter | Order |
---|---|
MetricsWebFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
WebFilterChainProxy (Spring Security 性) |
-100 |
HttpTraceWebFilter |
Ordered.LOWEST_PRECEDENCE - 10 |
28.3 JAX-RS 和 Jersey
如果您更喜欢 REST 端点的 JAX-RS 编程模型,则可以使用可用的实现之一来代替 Spring MVC。 Jersey和Apache CXF开箱即用。 CXF 要求您在应用程序上下文中将其Servlet
或Filter
注册为@Bean
。Jersey(Jersey)有一些本机 Spring 支持,因此我们在 Spring Boot 中还与启动程序一起为其提供了自动配置支持。
要开始使用 Jersey,请将spring-boot-starter-jersey
作为依赖项,然后需要一个ResourceConfig
类型的@Bean
,在其中注册所有端点,如以下示例所示:
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
}
Warning
Jersey 对扫描可执行归档文件的支持非常有限。例如,在运行可执行的 war 文件时,它无法扫描在完全可执行的 jar 文件或WEB-INF/classes
中找到的程序包中的端点。为避免此限制,不应使用packages
方法,并且应使用register
方法分别注册端点,如前面的示例所示。
对于更高级的定制,您还可以注册实现ResourceConfigCustomizer
的任意数量的 bean。
所有注册的端点都应为@Components
,并带有 HTTP 资源 Comments(@GET
和其他 Comments),如以下示例所示:
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
}
由于Endpoint
是 Spring @Component
,其生命周期由 Spring Management,因此您可以使用@Autowired
注解注入依赖项,并使用@Value
注解注入外部配置。默认情况下,Jersey servlet 已注册并 Map 到/*
。您可以通过将@ApplicationPath
添加到ResourceConfig
来更改 Map。
默认情况下,Jersey 在名为jerseyServletRegistration
的ServletRegistrationBean
类型的@Bean
中设置为 Servlet。默认情况下,该 Servlet 延迟初始化,但是您可以通过设置spring.jersey.servlet.load-on-startup
来自定义该行为。您可以通过使用相同的名称创建自己的一个来禁用或覆盖该 bean。您还可以通过设置spring.jersey.type=filter
(在这种情况下,要替换或覆盖的@Bean
是jerseyFilterRegistration
)来使用过滤器而不是 Servlet。过滤器具有@Order
,您可以使用spring.jersey.filter.order
进行设置。可以使用spring.jersey.init.*
指定属性 Map,从而为 servlet 和过滤器注册都赋予 init 参数。
有一个Jersey sample,以便您可以了解如何进行设置。
28.4 嵌入式 Servlet 容器支持
Spring Boot 包含对嵌入式Tomcat,Jetty和Undertow服务器的支持。大多数开发人员使用适当的“启动器”来获取完全配置的实例。默认情况下,嵌入式服务器在端口8080
上侦听 HTTP 请求。
Warning
如果选择在CentOS上使用 Tomcat,请注意,默认情况下,将使用一个临时目录来存储编译的 JSP,文件上载等等。您的应用程序运行时,此目录可能被tmpwatch
删除,从而导致失败。为避免这种情况,您可能需要自定义tmpwatch
配置,以使tomcat.*
目录不会被删除,或配置server.tomcat.basedir
,以使嵌入式 Tomcat 使用其他位置。
28.4.1 Servlet,过滤器和侦听器
使用嵌入式 Servlet 容器时,可以通过使用 Spring bean 或扫描 Servlet 组件来注册 Servlet 规范中的 Servlet,过滤器和所有侦听器(例如HttpSessionListener
)。
将 Servlet,过滤器和侦听器注册为 Spring Bean
任何作为 Spring bean 的Servlet
,Filter
或 servlet *Listener
实例都向嵌入式容器注册。如果要在配置过程中引用application.properties
中的值,这可能特别方便。
默认情况下,如果上下文仅包含单个 Servlet,则将其 Map 到/
。对于多个 servlet bean,bean 名称用作路径前缀。过滤器 Map 到/*
。
如果基于约定的 Map 不够灵活,则可以使用ServletRegistrationBean
,FilterRegistrationBean
和ServletListenerRegistrationBean
类进行完全控制。
Spring Boot 附带了许多可能定义 Filter bean 的自动配置。以下是过滤器及其各自 Sequences 的一些示例(较低的 Sequences 值表示较高的优先级):
Servlet Filter | Order |
---|---|
OrderedCharacterEncodingFilter |
Ordered.HIGHEST_PRECEDENCE |
WebMvcMetricsFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
ErrorPageFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
HttpTraceFilter |
Ordered.LOWEST_PRECEDENCE - 10 |
通常可以使无序滤 bean 处于无序状态。
如果需要特定的 Sequences,则应避免配置一个在Ordered.HIGHEST_PRECEDENCE
读取请求正文的过滤器,因为它可能与应用程序的字符编码配置不符。如果 Servlet 过滤器包装了请求,则应以小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的 Sequences 对其进行配置。
28.4.2 Servlet 上下文初始化
嵌入式 Servlet 容器不会直接执行 Servlet 3.0 javax.servlet.ServletContainerInitializer
接口或 Spring 的org.springframework.web.WebApplicationInitializer
接口。这是一个有意设计的决定,目的是减少旨在在 War 中运行的第三方库可能破坏 Spring Boot 应用程序的风险。
如果需要在 Spring Boot 应用程序中执行 servlet 上下文初始化,则应该注册一个实现org.springframework.boot.web.servlet.ServletContextInitializer
接口的 bean。单个onStartup
方法提供对ServletContext
的访问,并且在必要时可以轻松地用作现有WebApplicationInitializer
的适配器。
扫描 Servlet,过滤器和侦听器
使用嵌入式容器时,可以通过使用@ServletComponentScan
来启用自动注册带有@WebServlet
,@WebFilter
和@WebListener
Comments 的类。
Tip
@ServletComponentScan
在独立容器中无效,而是使用该容器的内置发现机制。
28.4.3 ServletWebServerApplicationContext
在后台,Spring Boot 使用另一种类型的ApplicationContext
来支持嵌入式 servlet 容器。 ServletWebServerApplicationContext
是WebApplicationContext
的一种特殊类型,它通过搜索单个ServletWebServerFactory
bean 来进行自我引导。通常TomcatServletWebServerFactory
,JettyServletWebServerFactory
或UndertowServletWebServerFactory
已被自动配置。
Note
通常,您不需要了解这些实现类。大多数应用程序都是自动配置的,并且代表您创建了相应的ApplicationContext
和ServletWebServerFactory
。
28.4.4 自定义嵌入式 Servlet 容器
可以使用 Spring Environment
属性来配置常见的 servlet 容器设置。通常,您将在application.properties
文件中定义属性。
常用服务器设置包括:
网络设置:侦听传入 HTTP 请求的端口(
server.port
),绑定到server.address
的接口地址,等等。会话设置:会话是否持久(
server.servlet.session.persistence
),会话超时(server.servlet.session.timeout
),会话数据的位置(server.servlet.session.store-dir
)和会话 cookie 配置(server.servlet.session.cookie.*
)。错误 Management:错误页面的位置(
server.error.path
),依此类推。
Spring Boot 尝试尽可能多地公开通用设置,但这并不总是可能的。在这种情况下,专用名称空间提供服务器特定的自定义项(请参见server.tomcat
和server.undertow
)。例如,access logs可以配置有嵌入式 Servlet 容器的特定功能。
Tip
有关完整列表,请参见ServerProperties类。
Programmatic Customization
如果需要以编程方式配置嵌入式 servlet 容器,则可以注册一个实现WebServerFactoryCustomizer
接口的 Spring bean。 WebServerFactoryCustomizer
提供对ConfigurableServletWebServerFactory
的访问,其中包括许多自定义设置方法。以下示例显示以编程方式设置端口:
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
Note
TomcatServletWebServerFactory
,JettyServletWebServerFactory
和UndertowServletWebServerFactory
是ConfigurableServletWebServerFactory
的专用变体,分别具有针对 Tomcat,Jetty 和 Undertow 的其他自定义设置方法。
直接自定义 ConfigurableServletWebServerFactory
如果上述定制技术太有限,则可以自己注册TomcatServletWebServerFactory
,JettyServletWebServerFactory
或UndertowServletWebServerFactory
bean。
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}
提供了许多配置选项的设置器。如果您需要做一些更奇特的操作,还提供了几种受保护的方法“钩子”。有关详情,请参见源代码文档。
28.4.5 JSP 限制
当运行使用嵌入式 servlet 容器(并打包为可执行归档文件)的 Spring Boot 应用程序时,JSP 支持存在一些限制。
对于 Jetty 和 Tomcat,如果使用 War 包装,它应该可以工作。与
java -jar
一起启动时,可执行的 War 将起作用,并且也可部署到任何标准容器中。使用可执行 jar 时,不支持 JSP。Undertow 不支持 JSP。
创建自定义
error.jsp
页面不会覆盖error handling的默认视图。应该改用自定义错误页面。
有一个JSP sample,以便您可以了解如何进行设置。
28.5 嵌入式反应式服务器支持
Spring Boot 包含对以下嵌入式反应式 Web 服务器的支持:Reactor Netty,Tomcat,Jetty 和 Undertow。大多数开发人员使用适当的“启动器”来获取完全配置的实例。默认情况下,嵌入式服务器在端口 8080 上侦听 HTTP 请求。
28.6 Reactive 服务器资源配置
当自动配置 Reactor Netty 或 Jetty 服务器时,Spring Boot 将创建特定的 bean,这些 bean 将为服务器实例提供 HTTP 资源:ReactorResourceFactory
或JettyResourceFactory
。
默认情况下,在以下情况下,这些资源还将与 Reactor Netty 和 Jetty Client 端共享,以实现最佳性能:
服务器和 Client 端使用相同的技术
Client 端实例是使用 Spring Boot 自动配置的
WebClient.Builder
bean 构建的
通过提供自定义的ReactorResourceFactory
或JettyResourceFactory
bean,开发人员可以覆盖 Jetty 和 Reactor Netty 的资源配置-这将同时应用于 Client 端和服务器。
您可以在WebClient 运行时部分中了解有关 Client 端资源配置的更多信息。