8.1.1. “Spring Web MVC 框架”
Spring Web MVC 框架(通常称为“Spring MVC”)是一个丰富的“模型视图控制器”Web 框架。Spring MVC 允许您创建指定的@Controller
或@RestController
Bean 来处理传入的 HTTP 请求。控制器中的方法通过使用 @RequestMapping
注释映射到 HTTP。
以下代码显示了@RestController
提供 JSON 数据的典型代码:
“WebMvc.fn”,功能变体,将路由配置与请求的实际处理分开,如以下示例所示:
Spring MVC 是核心 Spring 框架的一部分,详细信息可在 参考文档中找到。spring.io/guides上还提供了一些涵盖 Spring MVC 的指南。
您可以定义任意数量的
RouterFunction
bean,以模块化路由器的定义。如果您需要应用优先级,可以对bean类排序。
Spring MVC 自动配置
Spring Boot 为 Spring MVC 提供自动配置,适用于大多数应用程序。它取代了需要@EnableWebMvc
,并且两者不能一起使用。除了 Spring MVC 的默认设置之外,自动配置还提供以下功能:
包含
ContentNegotiatingViewResolver
和BeanNameViewResolver
Bean类。支持提供静态资源,包括对 WebJars 的支持(本文档稍后介绍)。
自动注册
Converter
、GenericConverter
和Formatter
beans。支持
HttpMessageConverters
(本文档稍后介绍)。自动注册
MessageCodesResolver
(本文档稍后介绍)。静态
index.html
支持。自动使用
ConfigurableWebBindingInitializer
bean(本文档稍后介绍)。
如果您想保留这些 Spring Boot MVC 自定义并进行更多 MVC 自定义(拦截器、格式化程序、视图控制器和其他功能),您可以添加自己的WebMvcConfigurer
类型的 @Configuration
类,但不使用 @EnableWebMvc
。
如果您想要提供RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
、 或 ExceptionHandlerExceptionResolver
的自定义实例,并且仍然保留 Spring Boot MVC 自定义,则可以声明WebMvcRegistrations
类型的 bean并使用它来提供这些组件的自定义实例。自定义实例将由 Spring MVC 进行进一步的初始化和配置。要参与并在需要时覆盖后续处理,应使用WebMvcConfigurer
。
如果您不想使用自动配置并希望完全控制 Spring MVC,请添加您自己的带有 @EnableWebMvc
注释的 @Configuration
。或者,添加您自己的带有 @Configuration
注释的 DelegatingWebMvcConfiguration
,如@EnableWebMvc
的 Javadoc 中所述。
Spring MVC 转换服务
Spring MVC 使用一种与用于转换您application.properties
或application.yaml
文件中的值的方法不同的ConversionService
方法。这意味着Period
,Duration
和DataSize
转换器不可用,并且@DurationUnit
和@DataSizeUnit
注释将被忽略。
如果你想定制Spring MVC使用的ConversionService
,你可以提供一个带有addFormatters
方法的WebMvcConfigurer
bean 。通过此方法,您可以注册任何您喜欢的转换器,也可以委托给ApplicationConversionService
.
还可以使用spring.mvc.format.*
配置属性来自定义转换。如果未配置,则使用以下默认值:
属性 |
|
|
|
|
|
|
|
Http消息转换器
Spring MVC 使用HttpMessageConverter
接口来转换 HTTP 请求和响应。合理的默认值是开箱即用的。例如,对象可以自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展(如果可用),或者通过使用 JAXB(如果 Jackson XML 扩展不可用))。默认情况下,字符串以UTF-8
编码.
如果需要添加或自定义转换器,可以使用 Spring Boot 的HttpMessageConverters
类,如下清单所示:
上下文中存在的任何HttpMessageConverter
bean 都会添加到转换器列表中。您还可以以相同的方式覆盖默认转换器。
消息代码解析器
Spring MVC 有一个生成错误代码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver
。如果您设置spring.mvc.message-codes-resolver-format
属性为PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,Spring Boot 会为您创建一个属性(请参阅DefaultMessageCodesResolver.Format
中的枚举)。
静态内容
默认情况下,Spring Boot 从类路径中名为 /static
(或/public
或/resources
或/META-INF/resources
)的目录或 ServletContext
的根目录提供静态内容,它使用 Spring MVC 中的 ResourceHttpRequestHandler
,以便您可以通过添加自己的 WebMvcConfigurer
并重写 addResourceHandlers
方法来修改该行为。
在独立的 Web 应用程序中,容器中的默认 servlet 未启用。可以使用server.servlet.register-default-servlet
属性来启用它。
默认 servlet 充当后备,如果 Spring 决定不处理它,则从 ServletContext
的根提供内容。大多数时候,这种情况不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过 DispatcherServlet
处理请求。
默认情况下,资源映射到/**
,但您可以使用spring.mvc.static-path-pattern
属性对其进行调整。例如,将所有资源重新定位/resources/**
可以实现如下:
您还可以使用spring.web.resources.static-locations
属性自定义静态资源位置(用目录位置列表替换默认值)。根 Servlet 上下文路径"/"
也会自动添加为位置。
除了前面提到的“标准”静态资源位置之外,还为Webjars 内容制作了一个特例。默认情况下,如果以 Webjars 格式打包,则任何路径为/webjars/**
的资源都将从 jar 文件提供。可以使用属性spring.mvc.webjars-path-pattern
自定义路径。
如果您的应用程序打包为 jar, 请勿使用
src/main/webapp
目录。尽管此目录是通用标准,但它仅适用于 war 打包,并且如果您生成 jar,大多数构建工具都会默默地忽略它。
Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,允许使用缓存清除静态资源或对 Webjar 使用版本无关的 URL 等用例。
要对 Webjar 使用与版本无关的 URL,请添加webjars-locator-core
依赖项。然后声明你的Webjar。然后声明你的Webjar。以 jQuery 为例,添加“/webjars/jquery/jquery.min.js
”会生成“/webjars/jquery/x.y.z/jquery.min.js
”,其中 x.y.z
是 Webjar 版本。
如果您使用 JBoss,则需要声明
webjars-locator-jboss-vfs
依赖项而不是webjars-locator-core
. 否则,所有 Webjar 都会解析为404
.
要使用缓存清除,以下配置为所有静态资源配置缓存清除解决方案,有效地在 URL 中添加内容哈希,例如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
:
由于Thymeleaf 和 FreeMarker 自动配置
ResourceUrlEncodingFilter
,资源链接在运行时在模板中重写。使用 JSP 时您应该手动声明此过滤器。目前不自动支持其他模板引擎,但可以使用自定义模板宏/帮助程序以及使用ResourceUrlProvider
.
例如,使用 JavaScript 模块加载器动态加载资源时,不能选择重命名文件。这就是为什么其他策略也受到支持并且可以组合的原因。“固定”策略在 URL 中添加静态版本字符串而不更改文件名,如下例所示:
通过此配置,位于"/js/lib/"
下的 JavaScript 模块使用固定版本控制策略 ( "/v12/js/lib/mymodule.js"
),而其他资源仍然使用内容( <link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>
)。
请参阅WebProperties.Resources
参考资料 了解更多支持的选项。
欢迎页面
Spring Boot 支持静态和模板化欢迎页面。它首先在配置的静态内容位置查找index.html
文件。如果没有找到,它就会寻找index
模板。如果找到其中一个,它将自动用作应用程序的欢迎页面。
这仅充当应用程序定义的实际索引路由的后备。顺序由HandlerMapping
bean 的顺序定义,默认情况如下:
映射bean | 备注 |
|
|
|
|
| 欢迎页面支持 |
自定义图标
与其他静态资源一样,Spring Boot 检查配置的静态内容位置中的 favicon.ico
。如果存在这样的文件,它将自动用作应用程序的图标。
路径匹配和内容协商
Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射(例如,控制器方法上的@GetMapping
注释)进行匹配,将传入的 HTTP 请求映射到处理程序。
Spring Boot 默认选择禁用后缀模式匹配,这意味着类似的请求"GET /projects/spring-boot.json"
将不会与@GetMapping("/projects/spring-boot")
映射匹配。这被认为是Spring MVC 应用程序的最佳实践。过去,此功能主要适用于未发送正确“Accept”请求标头的 HTTP 客户端;我们需要确保向客户端发送正确的内容类型。如今,内容协商更加可靠。
还有其他方法可以处理不始终发送正确的“Accept”请求标头的 HTTP 客户端。我们可以使用查询参数来确保将请求"GET /projects/spring-boot?format=json"
映射到@GetMapping("/projects/spring-boot")
,而不是使用后缀匹配:
或者,如果您更喜欢使用不同的参数名称:
大多数标准媒体类型都是开箱即用的,但您也可以定义新的媒体类型:
从 Spring Framework 5.3 开始,Spring MVC 支持两种将请求路径与控制器匹配的策略。默认情况下,Spring Boot 使用PathPatternParser
策略。 PathPatternParser
是一个优化的实现,但与AntPathMatcher
策略相比有一些限制。PathPatternParser
限制某些路径模式变体的使用。它也与使用路径前缀 ( spring.mvc.servlet.path
)配置的DispatcherServlet
不兼容。
可以使用spring.mvc.pathmatch.matching-strategy
配置属性来配置该策略,如以下示例所示:
默认情况下,如果未找到请求的处理程序,Spring MVC 将发送 404 Not Found 错误响应。要改为NoHandlerFoundException
抛出异常,请将configprop:spring.mvc.throw-exception-if-no-handler-found
设置为true
。请注意,默认情况下,静态内容的服务会映射到/**
并因此为所有请求提供处理程序。对于要抛出的 NoHandlerFoundException
,您还必须设置spring.mvc.static-path-pattern
为更具体的值,例如/resources/**
或 设置spring.web.resources.add-mappings
为false
完全禁用静态内容的服务。
可配置的WebBinding初始化器
Spring MVC 使用 WebBindingInitializer
来初始化特定请求的WebDataBinder
。如果您创建自己的ConfigurableWebBindingInitializer
@Bean
,Spring Boot 会自动配置 Spring MVC 来使用它。
模板引擎
除了 REST Web 服务之外,您还可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 JSP。此外,许多其他模板引擎都包含自己的 Spring MVC 集成。
Spring Boot 包括对以下模板引擎的自动配置支持:
如果可能,应避免 JSP。将它们与嵌入式 servlet 容器一起使用时存在一些已知的限制。
当您使用这些模板引擎之一和默认配置时,您的模板会自动从src/main/resources/templates
载入.
根据您运行应用程序的方式,您的 IDE 可能会对类路径进行不同的排序。在 IDE 中从其 main 方法运行应用程序会导致与使用 Maven 或 Gradle 或从其打包的 jar 运行应用程序时不同的顺序。这可能会导致 Spring Boot 无法找到预期的模板。如果遇到此问题,可以在 IDE 中重新排序类路径,将模块的类和资源放在前面。
错误处理
默认情况下,Spring Boot 提供了一个以合理方式处理所有错误的/error
映射,并且它在 servlet 容器中注册为“全局”错误页面。对于机器客户端,它会生成一个 JSON 响应,其中包含错误、HTTP 状态和异常消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误视图,它以 HTML 格式呈现相同的数据(要自定义它,请添加解析为error
的View
)。
如果您想自定义默认的错误处理行为,可以设置许多server.error
属性。请参阅附录的“服务器属性”部分。
要完全替换默认行为,您可以实现ErrorController
并注册该类型的 bean 定义,或者添加该类型的 beanErrorAttributes
以使用现有机制但替换内容。
BasicErrorController
可以用作自定义ErrorController
的基类。如果您想为新的内容类型添加处理程序(默认情况是专门处理text/html
并为其他所有内容提供后备),这特别有用。为此,请扩展BasicErrorController
,添加一个@RequestMapping
具有produces
属性的公共方法,然后创建一个新类型的 bean。
从 Spring Framework 6.0 开始,支持RFC 7807 问题详细信息。Spring MVC 可以使用application/problem+json
媒体类型生成自定义错误消息,例如:
可以通过设置spring.mvc.problemdetails.enabled
为 true
来启用此支持。
您还可以定义一个带@ControllerAdvice
注释的类,以自定义要针对特定控制器和/或异常类型返回的 JSON 文档,如以下示例所示:
在前面的示例中,如果MyException
是由与 位于同一包中定义的SomeController
控制器抛出的,则使用 POJO 的 JSON 表示形式MyErrorBody
而不是ErrorAttributes
表示形式。
在某些情况下,度量基础设施不会记录在控制器级别处理的错误。应用程序可以通过将已处理的异常设置为请求属性来确保此类异常与请求指标一起记录:
自定义错误页面
如果要显示给定状态代码的自定义 HTML 错误页面,可以将文件添加到目录/error
。错误页面可以是静态 HTML(即添加在任何静态资源目录下),也可以使用模板构建。文件名应该是确切的状态代码或系列掩码。
例如,要映射404
到静态 HTML 文件,您的目录结构将如下所示:
要使用 FreeMarker 模板映射所有5xx
错误,您的目录结构将如下所示:
对于更复杂的映射,您还可以添加实现ErrorViewResolver
接口的 bean,如以下示例所示:
您还可以使用常规 Spring MVC 功能,例如@ExceptionHandler
方法和@ControllerAdvice
. ErrorController
会拾取任何未处理的异常。
在 Spring MVC 之外映射错误页面
对于不使用Spring MVC的应用程序,可以使用ErrorPageRegistrar
接口直接注册ErrorPages
。这种抽象直接与底层嵌入式 servlet 容器一起工作,即使您没有 Spring MVC DispatcherServlet
也可以工作。
如果您注册 ErrorPage
的路径最终由 Filter
处理(这在某些非 Spring Web 框架中很常见,例如 Jersey 和 Wicket),则必须将 Filter
显式注册为ERROR
调度程序,如以下示例所示:
请注意,默认值FilterRegistrationBean
不包括ERROR
调度程序类型。
WAR 部署中的错误处理
当部署到 servlet 容器时,Spring Boot 使用其错误页面过滤器将带有错误状态的请求转发到适当的错误页面。这是必要的,因为 servlet 规范没有提供用于注册错误页面的 API。根据您将 war 文件部署到的容器以及应用程序使用的技术,可能需要一些额外的配置。
如果响应尚未提交,错误页面过滤器只能将请求转发到正确的错误页面。默认情况下,WebSphere Application Server 8.0 及更高版本在成功完成 servlet 的服务方法后提交响应。您应该通过设置com.ibm.ws.webcontainer.invokeFlushAfterService
为false
来禁用此行为。
CORS 支持
跨域资源共享(CORS) 是大多数浏览器实现的W3C 规范,它允许您以灵活的方式指定授权哪种跨域请求,而不是使用一些不太安全且功能不太强大的方法,例如 IFRAME 或 JSONP。
从版本 4.2 开始,Spring MVC支持 CORS。在 Spring Boot 应用程序中使用带@CrossOrigin
注释的控制器方法 CORS 配置不需要任何特定配置。 可以通过自定义addCorsMappings(CorsRegistry)
方法注册WebMvcConfigurer
bean来定义全局CORS配置,如下例所示:
最后更新于