基于 Servlet API 并部署到 Servlet 容器

时间:2022-11-17 17:00:57

版本 6.0.0

文档的这一部分涵盖了对基于 Servlet API 并部署到 Servlet 容器。个别章节包括Spring MVC,View Technologies,CORS​支持和WebSocket支持​。 对于反应式堆栈 Web 应用程序,请参阅反应式堆栈上的 Web。

基于 Servlet API 并部署到 Servlet 容器

1. 春季网络 MVC

Spring Web MVC是基于Servlet API构建的原始Web框架,已被包含 从一开始就在 Spring 框架中。正式名称“Spring Web MVC”。 来自其源模块的名称 (Spring-WebMVC), 但它通常被称为“Spring MVC”。

与Spring Web MVC并行,Spring Framework 5.0引入了一个反应式堆栈Web框架。 其名称“Spring WebFlux”也基于其源模块 (弹簧网流)。 本节介绍Spring Web MVC。下一节将介绍Spring WebFlux。

有关基线信息以及与 Servlet 容器和 Jakarta EE 版本的兼容性 范围,请参阅 Spring框架 Wiki。

1.1. 调度程序服务版

网络通量

Spring MVC与许多其他Web框架一样,是围绕前端控制器设计的。 集中式 The(提供共享算法)的模式 用于请求处理,而实际工作由可配置的委托组件执行。 此模型非常灵活,支持多种工作流程。​​Servlet​​​​DispatcherServlet​

与任何一样,需要根据 通过使用 Java 配置或 in 到 Servlet 规范。 反过来,使用弹簧配置来发现 请求映射、视图解析、异常所需的委托组件 处理,等等。​​DispatcherServlet​​​​Servlet​​​​web.xml​​​​DispatcherServlet​

以下 Java 配置示例注册并初始化 ,由 Servlet 容器自动检测 (参见Servlet Config):​​DispatcherServlet​

public class MyWebApplicationInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) {

// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);

// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
class MyWebApplicationInitializer : WebApplicationInitializer {

override fun onStartup(servletContext: ServletContext) {

// Load Spring web application configuration
val context = AnnotationConfigWebApplicationContext()
context.register(AppConfig::class.java)

// Create and register the DispatcherServlet
val servlet = DispatcherServlet(context)
val registration = servletContext.addServlet("app", servlet)
registration.setLoadOnStartup(1)
registration.addMapping("/app/*")
}
}

以下配置示例注册并初始化:​​web.xml​​​​DispatcherServlet​

<web-app>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>

<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>

</web-app>

1.1.1. 上下文层次结构

​DispatcherServlet​​期望 a(一个普通的扩展)用于它自己的配置。有一个链接到它与之关联的 the。它还绑定到应用程序可以使用静态方法来查找是否需要访问它。​​WebApplicationContext​​​​ApplicationContext​​​​WebApplicationContext​​​​ServletContext​​​​Servlet​​​​ServletContext​​​​RequestContextUtils​​​​WebApplicationContext​

对于许多应用程序,拥有单个是简单而足够的。 也可以有一个上下文层次结构,其中一个根在多个(或其他)实例之间共享,每个实例都有 它自己的子配置。 有关上下文层次结构功能的更多信息,请参阅ApplicationContext的其他功能。​​WebApplicationContext​​​​WebApplicationContext​​​​DispatcherServlet​​​​Servlet​​​​WebApplicationContext​

根通常包含基础结构 bean,例如数据存储库和 需要在多个实例之间共享的业务服务。那些豆子 被有效地继承,并且可以在特定于 Servlet 的 Servlet 中被覆盖(即重新声明) 子,通常包含给定的本地豆子。 下图显示了此关系:​​WebApplicationContext​​​​Servlet​​​​WebApplicationContext​​​​Servlet​

基于 Servlet API 并部署到 Servlet 容器

以下示例配置层次结构:​​WebApplicationContext​

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
}

@Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
}

以下示例显示了等效项:​​web.xml​

<web-app>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>

<servlet>
<servlet-name>app1</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app1-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>app1</servlet-name>
<url-pattern>/app1/*</url-pattern>
</servlet-mapping>

</web-app>

1.1.2. 特殊豆类

网络通量

委托特殊 bean 来处理请求并呈现 适当的回应。我们所说的“特殊 bean”是指 Spring 管理的实例 实施框架合同。这些通常带有内置合同,但是 您可以自定义其属性并扩展或替换它们。​​DispatcherServlet​​​​Object​

下表列出了检测到的特殊 bean:​​DispatcherServlet​

豆类

解释

​HandlerMapping​

将请求映射到处理程序以及用于预处理和后处理的拦截器​列表。 映射基于一些标准,其细节因实现而异。​​HandlerMapping​

两个主要实现是(支持sannotated方法)和(维护URI路径模式到处理程序的显式注册)。​​HandlerMapping​​​​RequestMappingHandlerMapping​​​​@RequestMapping​​​​SimpleUrlHandlerMapping​

​HandlerAdapter​

帮助调用映射到请求的处理程序,无论 如何实际调用处理程序。例如,调用带批注的控制器 需要解析批注。ais 的主要目的 以屏蔽此类细节。​​DispatcherServlet​​​​HandlerAdapter​​​​DispatcherServlet​

HandlerExceptionResolver

解决异常的策略,可能将它们映射到处理程序,到 HTML 错误 视图或其他目标。请参阅例外情况。

ViewResolver

将从处理程序返回的基于逻辑的视图名称解析为要呈现到响应的实际值。请参阅视图分辨率​和视图技术​。StringView

LocaleResolver​,LocaleContextResolver

解析客户端正在使用的时区以及可能的时区,以便能够 提供国际化视图。请参阅区域设置​。Locale

ThemeResolver

解析 Web 应用程序可以使用的主题,例如,提供个性化布局。 请参阅主题。

MultipartResolver

用于解析多部分请求(例如,浏览器表单文件上传)的抽象 一些多部分解析库的帮助。请参阅多部分解析程序。

FlashMapManager

存储和检索可用于传递的“输入”和“输出” 从一个请求到另一个请求的属性,通常是通过重定向。 请参阅闪存属性。FlashMap

1.1.3. 网页MVC配置

网络通量

应用程序可以声明处理请求所需的特殊 Bean 类型中列出的基础结构 Bean。检查每个特殊的豆子。如果没有匹配的 Bean 类型, 它回退到DispatcherServlet.properties 中列出的默认类型。DispatcherServletWebApplicationContext

在大多数情况下,MVC 配置是最佳起点。它声明了所需的 在 Java 或 XML 中提供更高级别的配置回调 API,以 自定义它。

1.1.4. servlet 配置

在 Servlet 环境中,您可以选择配置 Servlet 容器 以编程方式作为替代项或与 Afile 结合使用。 以下示例注册 a:​​web.xml​​​​DispatcherServlet​

public class MyWebApplicationInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext container) {
XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}

​WebApplicationInitializer​​是Spring MVC提供的接口,可确保 检测到实现并自动用于初始化任何 Servlet 3 容器。 一个抽象的基类实现 named使得注册变得更加容易,通过重写方法来指定servlet映射和 配置的位置。​​WebApplicationInitializer​​​​AbstractDispatcherServletInitializer​​​​DispatcherServlet​​​​DispatcherServlet​

对于使用基于 Java 的 Spring 配置的应用程序,建议这样做,因为 以下示例显示:

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}

@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { MyWebConfig.class };
}

@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}

如果使用基于 XML 的 Spring 配置,则应直接从 扩展,如以下示例所示:​​AbstractDispatcherServletInitializer​

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}

@Override
protected WebApplicationContext createServletApplicationContext() {
XmlWebApplicationContext cxt = new XmlWebApplicationContext();
cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
return cxt;
}

@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}

​AbstractDispatcherServletInitializer​​还提供了一种方便的方式来添加实例并将它们自动映射到,因为 以下示例显示:​​Filter​​​​DispatcherServlet​

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

// ...

@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
}
}

每个过滤器都根据其具体类型添加默认名称,并自动添加 映射到。​​DispatcherServlet​

受保护的方法提供了一个单一的位置来启用异步支持和所有 映射到它的筛选器。默认情况下,此标志设置为 。​​isAsyncSupported​​​​AbstractDispatcherServletInitializer​​​​DispatcherServlet​​​​true​

最后,如果需要进一步自定义自己,可以 重写方法。​​DispatcherServlet​​​​createDispatcherServlet​

1.1.5. 处理

网络通量

处理请求如下:​​DispatcherServlet​

  • 在请求中搜索并绑定为属性 控制器和过程中的其他元素可以使用。默认情况下它是绑定的 在钥匙下。WebApplicationContextDispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE
  • 区域设置解析器绑定到请求以允许进程中的元素 解析处理请求时要使用的区域设置(呈现视图、准备 数据等)。如果不需要区域设置解析,则不需要区域设置解析程序。
  • 主题解析程序绑定到请求,让视图等元素确定 使用哪个主题。如果不使用主题,则可以忽略它。
  • 如果指定多部分文件解析程序,则会检查请求是否存在多部分。如果 找到多部分,请求包装在 afor 中 由过程中的其他元素进一步处理。有关更多详细信息,请参阅多部分解析程序 有关多部件处理的信息。MultipartHttpServletRequest
  • 搜索适当的处理程序。如果找到处理程序,则执行链 与处理程序(预处理器、后处理器和控制器)关联的是 运行以准备要渲染的模型。或者,对于带注释的 控制器,响应可以呈现(在)而不是 返回视图。HandlerAdapter
  • 如果返回模型,则呈现视图。如果未返回模型(可能是由于 预处理器或后处理器拦截请求,可能是为了安全起见 原因),不呈现任何视图,因为请求可能已经满足。

在 theare 中声明的 thebeans 用于 解决请求处理期间引发的异常。这些异常解析程序允许 自定义逻辑以解决异常问题。有关更多详细信息,请参阅例外情况。​​HandlerExceptionResolver​​​​WebApplicationContext​

对于 HTTP 缓存支持,处理程序可以使用以下方法: 以及带注释的控制器的更多选项,如控制器的 HTTP 缓存中所述。​​checkNotModified​​​​WebRequest​

您可以通过添加 Servlet 来自定义单个实例 初始化参数(元素)到文件中的 Servlet 声明。下表列出了支持的参数:​​DispatcherServlet​​​​init-param​​​​web.xml​

表 1.DispatcherServlet 初始化参数

参数

解释

​contextClass​

实现、要实例化和 由此 Servlet 在本地配置。默认情况下,使用。​​ConfigurableWebApplicationContext​​​​XmlWebApplicationContext​

​contextConfigLocation​

传递给上下文实例(指定者)的字符串 指示可以找到上下文的位置。该字符串可能包含多个 字符串(使用逗号作为分隔符)以支持多个上下文。在以下情况下: 具有定义两次的 bean 的多个上下文位置,最新的位置 优先。​​contextClass​

​namespace​

的命名空间。默认为。​​WebApplicationContext​​​​[servlet-name]-servlet​

​throwExceptionIfNoHandlerFound​

在找不到请求的处理程序时是否抛出。 然后可以使用 a(例如,通过使用控制器方法)捕获异常,并像处理任何其他异常一样处理异常。​​NoHandlerFoundException​​​​HandlerExceptionResolver​​​​@ExceptionHandler​

默认情况下,此选项设置为 ,在这种情况下,设置 响应状态到 404 (NOT_FOUND),而不引发异常。​​false​​​​DispatcherServlet​

请注意,如果默认的 servlet 处理是 此外,已配置未解析的请求始终转发到默认 Servlet 并且从未提出过 404。

1.1.6. 路径匹配

Servlet API 公开了完整的请求路径,并进一步细分了它 进入,,,其值因 Servlet 被映射。从这些输入中,Spring MVC需要确定查找路径 用于映射处理程序,应排除 and 任何前缀(如果适用)。​​requestURI​​​​contextPath​​​​servletPath​​​​pathInfo​​​​contextPath​​​​servletMapping​

Theandare解码,这使得它们无法比较 直接到 full,以便派生 lookupPath,这使得它 需要解码。但是,这引入了自己的问题,因为 路径可能包含编码的保留字符,例如可以反过来 解码后更改路径的结构,这也可能导致安全性 问题。此外,Servlet 容器可以规范化变化 度数,使得进一步无法与 这。​​servletPath​​​​pathInfo​​​​requestURI​​​​requestURI​​​​"/"​​​​";"​​​​servletPath​​​​startsWith​​​​requestURI​

这就是为什么最好避免依赖随之而来的 基于前缀的映射类型。如果映射为 默认的 Servlet withor 否则没有前缀 withand Servlet 容器是 4.0+,那么 Spring MVC 能够检测 Servlet 映射类型并避免 使用和。在 3.1 Servlet 容器上, 假设相同的 Servlet 映射类型,可以通过提供 awithvia路径匹配in MVC 配置。​​servletPath​​​​servletPath​​​​DispatcherServlet​​​​"/"​​​​"/*"​​​​servletPath​​​​pathInfo​​​​UrlPathHelper​​​​alwaysUseFullPath=true​

幸运的是,默认的 Servlet 映射是一个不错的选择。但是,仍然有 一个问题在于需要解码才能与 控制器映射。这又是不可取的,因为有可能解码 更改路径结构的保留字符。如果不需要这样的字符, 然后你可以拒绝它们(如Spring Security HTTP防火墙),或者你可以配置但是控制器映射需要与 编码路径,可能并不总是工作良好。此外,有时需要与另一个 Servlet 共享 URL 空间,并且可能需要 按前缀映射。​​"/"​​​​requestURI​​​​UrlPathHelper​​​​urlDecode=false​​​​DispatcherServlet​

使用和解析模式时解决了上述问题,如 字符串路径匹配的替代方法。泰哈斯 可从版本 5.3 开始在 Spring MVC 中使用,并且默认从 版本 6.0。不像哪个需要解码查找路径或 控制器映射编码,解析匹配到解析表示 调用的路径,一次一个路径段。这允许解码和 单独清理路径段值,而不会有改变结构的风险 的路径。解析还支持使用前缀映射 只要使用 Servlet 路径映射并且前缀保持简单,即它没有 编码字符。有关模式语法详细信息和比较,请参阅模式比较。​​PathPatternParser​​​​AntPathMatcher​​​​PathPatternParser​​​​AntPathMatcher​​​​PathPattern​​​​RequestPath​​​​PathPattern​​​​servletPath​

1.1.7. 拦截

所有实现都支持处理程序拦截器,这些拦截器在以下情况下很有用 您希望将特定功能应用于某些请求,例如,检查 校长。拦截器必须使用三种方法从包中实现,这些方法应提供足够的 灵活地进行各种预处理和后处理:​​HandlerMapping​​​​HandlerInterceptor​​​​org.springframework.web.servlet​

  • ​preHandle(..)​​:在实际处理程序运行之前
  • ​postHandle(..)​​:处理程序运行后
  • ​afterCompletion(..)​​:完成请求后

该方法返回一个布尔值。您可以使用此方法中断或 继续处理执行链。当此方法返回时, 处理程序执行链继续。当它返回 false 时,假设拦截器本身已经处理了请求(例如,呈现了一个 适当的视图)并且不会继续执行其他拦截器和实际 执行链中的处理程序。​​preHandle(..)​​​​true​​​​DispatcherServlet​

有关如何MVC 配置的示例,请参阅 配置拦截器。您还可以通过在单个实现上使用资源库来直接注册它们。​​HandlerMapping​

​postHandle​​方法不太有用 withand方法 响应是在之前和之前编写和提交的。这意味着对响应进行任何更改为时已晚,例如添加 一个额外的标头。对于此类方案,您可以实现和 将其声明为控制器建议Bean 或直接对其进行配置。​​@ResponseBody​​​​ResponseEntity​​​​HandlerAdapter​​​​postHandle​​​​ResponseBodyAdvice​​​​RequestMappingHandlerAdapter​

1.1.8. 异常

网络通量

如果在请求映射期间发生异常或从请求处理程序引发异常(例如 a),委托给 Chain-Beans 来解决异常并提供替代处理,这通常是 错误响应。​​@Controller​​​​DispatcherServlet​​​​HandlerExceptionResolver​

下表列出了可用的实现:​​HandlerExceptionResolver​

表 2.处理程序异常解析器实现

​HandlerExceptionResolver​

描述

​SimpleMappingExceptionResolver​

异常类名和错误视图名之间的映射。用于渲染 浏览器应用程序中的错误页面。

DefaultHandlerExceptionResolver

解决Spring MVC引发的异常,并将它们映射到HTTP状态代码。 另请参阅替代和错误响应​。​​ResponseEntityExceptionHandler​

​ResponseStatusExceptionResolver​

使用注释解决异常并将其映射到 HTTP 状态 基于批注中的值的代码。​​@ResponseStatus​

​ExceptionHandlerExceptionResolver​

通过在 aor aclass 中调用 anmethod来解决异常。请参阅@ExceptionHandler方法​。​​@ExceptionHandler​​​​@Controller​​​​@ControllerAdvice​

解析器链

您可以通过在 Spring 配置中声明多个 bean 并根据需要设置它们的属性来形成异常解析器链。 order 属性越高,异常解析程序定位得越晚。​​HandlerExceptionResolver​​​​order​

的协定指定它可以返回:​​HandlerExceptionResolver​

  • a指向错误视图。ModelAndView
  • 如果异常是在解析程序中处理的,则为空。ModelAndView
  • ​null​​如果异常仍未解析,则供后续解析程序尝试,并且如果 异常保留在最后,它被允许冒泡到 Servlet 容器。

MVC 配置会自动为默认的 Spring MVC 声明内置解析器 异常、带注释的异常以及用于支持方法。您可以自定义或替换该列表。​​@ResponseStatus​​​​@ExceptionHandler​

容器错误页面

如果异常仍未由 anyand 解决,因此, 左以传播,或者如果响应状态设置为错误状态(即 4xx、5xx), Servlet 容器可以在 HTML 中呈现默认的错误页面。自定义默认值 容器的错误页,可以在错误页中声明映射。 以下示例演示如何执行此操作:​​HandlerExceptionResolver​​​​web.xml​

<error-page>
<location>/error</location>
</error-page>

给定前面的示例,当异常冒泡或响应具有错误状态时, Servlet 容器在容器内向配置的 URL 发出错误调度 (例如,)。然后由 处理,可能映射它 to a,可以实现以返回带有模型的错误视图名称 或呈现 JSON 响应,如以下示例所示:​​/error​​​​DispatcherServlet​​​​@Controller​

@RestController
public class ErrorController {

@RequestMapping(path = "/error")
public Map<String, Object> handle(HttpServletRequest request) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("status", request.getAttribute("jakarta.servlet.error.status_code"));
map.put("reason", request.getAttribute("jakarta.servlet.error.message"));
return map;
}
}

1.1.9. 视图分辨率

网络通量

Spring MVC 定义了允许您渲染的接口 浏览器中的模型,而不将您绑定到特定的视图技术。提供视图名称和实际视图之间的映射。解决准备问题 在移交给特定视图技术之前的数据。​​ViewResolver​​​​View​​​​ViewResolver​​​​View​

下表提供了有关层次结构的更多详细信息:​​ViewResolver​

表 3.视图解析器实现

视解析器

描述

​AbstractCachingViewResolver​

缓存的子类视图它们解析的实例。 缓存可提高某些视图技术的性能。您可以关闭 通过将属性设置为进行缓存。此外,如果您必须刷新 运行时的某个视图(例如,修改 FreeMarker 模板时), 您可以使用该方法。​​AbstractCachingViewResolver​​​​cache​​​​false​​​​removeFromCache(String viewName, Locale loc)​

​UrlBasedViewResolver​

影响直接的接口的简单实现 将逻辑视图名称解析为 URL,而无需显式映射定义。 如果您的逻辑名称与视图资源的名称匹配,则适合这样做 以简单的方式,无需任意映射。​​ViewResolver​

​InternalResourceViewResolver​

方便的子类支持(在 效果,Servlet 和 JSP)和子类,如 and。您可以 为此解析程序生成的所有视图指定视图类。 有关详细信息,请参阅UrlBasedViewResolver​javadoc。​​UrlBasedViewResolver​​​​InternalResourceView​​​​JstlView​​​​TilesView​​​​setViewClass(..)​

​FreeMarkerViewResolver​

方便的子类支持和 它们的自定义子类。​​UrlBasedViewResolver​​​​FreeMarkerView​

​ContentNegotiatingViewResolver​

基于 请求文件名或标头。请参阅内容协商​。​​ViewResolver​​​​Accept​

​BeanNameViewResolver​

将视图名称解释为 当前应用程序上下文中的 Bean 名称。这是一个非常灵活的变体,它 允许根据不同的视图名称混合和匹配不同的视图类型。 每个这样的都可以定义为一个 bean,例如在 XML 或配置类中。​​ViewResolver​​​​View​

处理

网络通量

您可以通过声明多个解析器 Bean 来链接视图解析器,如有必要,还可以通过 设置属性以指定排序。请记住,阶属性越高, 视图解析程序位于链中的位置越晚。​​order​

的协定指定它可以返回 null 以指示 找不到视图。但是,对于 JSP 和 确定 JSP 是否存在的唯一方法是执行调度。因此,必须始终将 anto 配置为视图解析程序总体顺序中的最后一个。​​ViewResolver​​​​InternalResourceViewResolver​​​​RequestDispatcher​​​​InternalResourceViewResolver​

配置视图分辨率就像向 Spring 中添加豆子一样简单 配置。MVC配置为视图解析器和添加无逻辑视图控制器提供了专用的配置 API,这对于 HTML 模板很有用 无控制器逻辑的渲染。​​ViewResolver​

重 定向

网络通量

视图名称中的 specialprefix 允许您执行重定向。(及其子类)将此视为一个指令 需要重定向。视图名称的其余部分是重定向 URL。​​redirect:​​​​UrlBasedViewResolver​

净效果与控制器返回 a 相同,但现在 控制器本身可以根据逻辑视图名称进行操作。逻辑视图 名称(例如)相对于当前重定向 Servlet 上下文,而诸如重定向到绝对 URL 之类的名称。​​RedirectView​​​​redirect:/myapp/some/resource​​​​redirect:https://myhost.com/some/arbitrary/path​

请注意,如果控制器方法带有注释,则注释 值优先于由此设置的响应状态。​​@ResponseStatus​​​​RedirectView​

转发

您还可以对以下视图名称使用特殊前缀: 最终由 and 子类解决。这将创建一个,它执行一个。 因此,此前缀对 and(对于 JSP) 没有用,但如果使用其他视图,它会有所帮助 技术,但仍希望强制转发资源由 Servlet/JSP 引擎。请注意,您也可以改为链接多个视图解析程序。​​forward:​​​​UrlBasedViewResolver​​​​InternalResourceView​​​​RequestDispatcher.forward()​​​​InternalResourceViewResolver​​​​InternalResourceView​

内容协商

网络通量

内容协商视图解析程序不解析视图本身,而是解析委托 到其他视图解析程序,并选择类似于所请求表示的视图 由客户。表示形式可以从标头或从 查询参数(例如,)。​​Accept​​​​"/path?format=pdf"​

选择适当的处理请求 通过将请求媒体类型与每个媒体类型(也称为)支持的媒体类型进行比较。这 在具有兼容的列表中的第一个返回表示形式 给客户。如果链无法提供兼容视图, 将查阅通过属性指定的视图列表。这 后一个选项适用于单例可以呈现适当的 当前资源的表示形式,而不考虑逻辑视图名称。标头可以包含通配符(例如),在这种情况下,awhoseisis 是兼容的匹配项。​​ContentNegotiatingViewResolver​​​​View​​​​Content-Type​​​​View​​​​ViewResolvers​​​​View​​​​Content-Type​​​​ViewResolver​​​​DefaultViews​​​​Views​​​​Accept​​​​text/*​​​​View​​​​Content-Type​​​​text/xml​

有关配置详细信息,请参阅MVC 配置下的查看解析程序。

1.1.10. 语言环境

Spring架构的大部分都支持国际化,如Spring网络。 MVC 框架可以,允许您自动解析消息 通过使用客户端的区域设置。这是通过对象完成的。​​DispatcherServlet​​​​LocaleResolver​

当请求进来时,会查找区域设置解析器,如果 找到一个,它会尝试使用它来设置区域设置。通过使用该方法,您始终可以检索由区域设置解析程序解析的区域设置。​​DispatcherServlet​​​​RequestContext.getLocale()​

除了自动区域设置解析之外,还可以将侦听器附加到 处理程序映射(有关处理程序的详细信息,请参阅拦截 映射拦截器)以在特定情况下更改区域设置(例如, 基于请求中的参数)。

区域设置解析器和侦听器在包中定义,并在应用程序中配置 以正常方式的上下文。以下区域设置解析程序选择包含在 春天。​​org.springframework.web.servlet.i18n​

  • 时区
  • 标头解析程序
  • 饼干解析器
  • 会话解析程序
  • 区域设置拦截器
时区

除了获取客户端的区域设置之外,了解其时区通常也很有用。 该接口提供了一个扩展,让 解析器提供更丰富的信息,其中可能包括时区信息。​​LocaleContextResolver​​​​LocaleResolver​​​​LocaleContext​

当可用时,通过使用该方法获取用户的扫描。自动使用时区信息 通过向 Spring 注册的任何日期/时间和对象。​​TimeZone​​​​RequestContext.getTimeZone()​​​​Converter​​​​Formatter​​​​ConversionService​

标头解析程序

此区域设置解析程序检查已发送请求中的标头 通过客户端(例如,Web 浏览器)。通常,此标头字段包含 客户端的操作系统。请注意,此解析程序不支持时区 信息。​​accept-language​

饼干解析器

此区域设置解析程序检查客户端上可能存在的 aoris 以查看是否指定了 aoris。如果是这样,它将使用指定的详细信息。通过使用 此区域设置解析器的属性,您可以指定 cookie 的名称以及 最大年龄。以下示例定义:​​Cookie​​​​Locale​​​​TimeZone​​​​CookieLocaleResolver​

<bean  class="org.springframework.web.servlet.i18n.CookieLocaleResolver">

<property name="cookieName" value="clientlanguage"/>

<!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->
<property name="cookieMaxAge" value="100000"/>

</bean>

下表描述了这些属性:​​CookieLocaleResolver​

表 4.CookieLocaleResolver 属性

财产

违约

描述

​cookieName​

类名 + 区域设置

饼干的名称

​cookieMaxAge​

Servlet 容器默认值

Cookie 在客户端上保留的最长时间。Ifis 指定, 饼干不会被保留。它仅在客户端关闭之前可用 浏览器。​​-1​

​cookiePath​

/

将 Cookie 的可见性限制在您网站的某个部分。当尼斯 指定时,Cookie 仅对该路径及其下方的路径可见。​​cookiePath​

会话解析程序

您检索的 thelet 和从 可能与用户请求关联的会话。与此相反,此策略将本地选择的区域设置存储在 Servlet 容器的。因此,这些设置是临时的 因此,在每个会话结束时都会丢失。​​SessionLocaleResolver​​​​Locale​​​​TimeZone​​​​CookieLocaleResolver​​​​HttpSession​

请注意,与外部会话管理机制没有直接关系, 比如春季会议项目。这评估和 根据电流修改相应的属性。​​SessionLocaleResolver​​​​HttpSession​​​​HttpServletRequest​

区域设置拦截器

您可以通过将区域设置添加到其中一个定义来启用区域设置的更改。它检测请求中的参数并更改区域设置 因此,在调度程序的 应用程序上下文。下一个示例显示对所有资源的调用 包含名为 Now 的参数会更改区域设置。所以,例如, 对 URL 的请求,,更改网站 荷兰语的语言。以下示例演示如何截获区域设置:​​LocaleChangeInterceptor​​​​HandlerMapping​​​​setLocale​​​​LocaleResolver​​​​*.view​​​​siteLanguage​​​​https://www.sf.net/home.view?siteLanguage=nl​

<bean 
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="siteLanguage"/>
</bean>

<bean
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>

<bean
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="localeChangeInterceptor"/>
</list>
</property>
<property name="mappings">
<value>/**/*.view=someController</value>
</property>
</bean>

1.1.11. 主题

您可以应用 Spring Web MVC 框架主题来设置您的整体外观 应用,从而增强用户体验。主题是静态的集合 影响 应用。

定义主题

要在 Web 应用程序中使用主题,必须设置接口的实现。接口扩展但将其职责委托给专用 实现。默认情况下,委托是一个实现 从类路径的根目录装入属性文件。要使用自定义实现或配置的基本名称前缀, 您可以使用保留名称在应用程序上下文中注册 Bean。 Web 应用程序上下文会自动检测具有该名称的 Bean 并使用它。​​org.springframework.ui.context.ThemeSource​​​​WebApplicationContext​​​​ThemeSource​​​​org.springframework.ui.context.support.ResourceBundleThemeSource​​​​ThemeSource​​​​ResourceBundleThemeSource​​​​themeSource​

当您使用时,主题是在一个简单的属性中定义的 文件。属性文件列出了组成主题的资源,如以下示例所示:​​ResourceBundleThemeSource​

styleSheet=/themes/cool/style.css
background=/themes/cool/img/coolBg.jpg

属性的键是引用视图中的主题元素的名称 法典。对于 JSP,通常使用自定义标记执行此操作,即 与标签非常相似。以下 JSP 片段使用主题 在上一示例中定义以自定义外观:​​spring:theme​​​​spring:message​

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<html>
<head>
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
</head>
<body style="background=<spring:theme code='background'/>">
...
</body>
</html>

默认情况下,使用空的基本名称前缀。结果, 属性文件从类路径的根目录装入。因此,您可以将主题定义放在类路径根目录下的目录中(对于 例如,在)。使用标准爪哇 资源包加载机制,允许主题完全国际化。为 例如,我们可以有一个引用一个特殊的 背景图片与荷兰语文字。​​ResourceBundleThemeSource​​​​cool.properties​​​​/WEB-INF/classes​​​​ResourceBundleThemeSource​​​​/WEB-INF/classes/cool_nl.properties​

解析主题

定义主题后,如上一节所述, 您决定使用哪个主题。寻找一个名为 bean 以找出要使用的实现。主题解析器的工作方式大致相同 方式作为A。它检测用于特定请求的主题,还可以 更改请求的主题。下表描述了 Spring 提供的主题解析器:​​DispatcherServlet​​​​themeResolver​​​​ThemeResolver​​​​LocaleResolver​

表 5.主题解析程序实现


描述

​FixedThemeResolver​

选择使用属性设置的固定主题。​​defaultThemeName​

​SessionThemeResolver​

主题在用户的 HTTP 会话中维护。它只需要为 设置一次 每个会话,但不在会话之间保留。

​CookieThemeResolver​

所选主题存储在客户端的 Cookie 中。

春天还提供了允许主题在每一个 使用简单的请求参数请求。​​ThemeChangeInterceptor​

1.1.12. 多部分解析器

网络通量

​MultipartResolver​​从包装是一种策略 用于解析分段请求,包括文件上传。有一个实现 基于共享资源文件上传和 另一个基于 Servlet 多部分请求解析。​​org.springframework.web.multipart​

要启用多部分处理,您需要在 abean 配置中声明名称为 of。 检测它并将其应用于传入请求。当开机自检时 对于内容类型 ofis 接收,解析程序将解析 内容包装当前作为 ATO 除了将部件公开为请求参数外,还提供对已解析文件的访问。​​MultipartResolver​​​​DispatcherServlet​​​​multipartResolver​​​​DispatcherServlet​​​​multipart/form-data​​​​HttpServletRequest​​​​MultipartHttpServletRequest​

Apache Commons ​​FileUpload​

要使用 Apache Commons,您可以配置一个名称为 的 bean。您还需要拥有 jar 作为对类路径的依赖关系。​​FileUpload​​​​CommonsMultipartResolver​​​​multipartResolver​​​​commons-fileupload​

此解析器变体委托给应用程序中的本地库,提供 跨 Servlet 容器的最大可移植性。作为替代方案,请考虑标准 Servlet 通过容器自己的解析器进行多部分解析,如下所述。

Servlet 多部分解析

Servlet 多部分解析需要通过 Servlet 容器配置来启用。 为此:

  • 在 Java 中,设置 Servlet 注册。MultipartConfigElement
  • 在中,将 asection 添加到 servlet 声明中。web.xml"<multipart-config>"

下面的示例演示如何设置 Servlet 注册:​​MultipartConfigElement​

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

// ...

@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {

// Optionally also set maxFileSize, maxRequestSize, fileSizeThreshold
registration.setMultipartConfig(new MultipartConfigElement("/tmp"));
}

}

一旦 Servlet 多部分配置就位,您就可以添加一个名称为 的 bean。​​StandardServletMultipartResolver​​​​multipartResolver​

1.1.13. 日志记录

网络通量

Spring MVC 中的调试级日志记录被设计为紧凑、最小和 人性化。它侧重于对和有用的高价值信息位 再次与仅在调试特定问题时有用的其他内容相比。

TRACE级日志记录通常遵循与DEBUG相同的原则(例如,也 不应是消防水带),但可用于调试任何问题。此外,一些日志 消息在跟踪和调试中可能显示不同级别的详细信息。

良好的日志记录来自使用日志的经验。如果你发现任何有用的东西 没有达到既定目标,请告诉我们。

敏感数据

网络通量

调试和跟踪日志记录可能会记录敏感信息。这就是为什么请求参数和 默认情况下,标头被屏蔽,并且必须显式启用其完整日志记录 通过属性上。​​enableLoggingRequestDetails​​​​DispatcherServlet​

以下示例演示如何使用 Java 配置执行此操作:

public class MyInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getRootConfigClasses() {
return ... ;
}

@Override
protected Class<?>[] getServletConfigClasses() {
return ... ;
}

@Override
protected String[] getServletMappings() {
return ... ;
}

@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("enableLoggingRequestDetails", "true");
}

}

1.2. 过滤器

网络通量

该模块提供了一些有用的过滤器:​​spring-web​

1.2.1. 表单数据

浏览器只能通过HTTP GET或HTTP POST提交表单数据,但非浏览器客户端也可以 使用 HTTP PUT、PATCH 和 DELETE。Servlet API 要求方法仅支持 HTTP POST 的表单字段访问。​​ServletRequest.getParameter*()​

该模块提供拦截 HTTP PUT、PATCH 和 DELETE 内容类型为的请求,从中读取表单数据 请求的正文,并包装以制作表单数据 可通过一系列方法获得。​​spring-web​​​​FormContentFilter​​​​application/x-www-form-urlencoded​​​​ServletRequest​​​​ServletRequest.getParameter*()​

1.2.2. 转发标头

网络通量

当请求通过代理(例如负载均衡器)时,主机、端口和 方案可能会改变,这使得创建指向正确链接成为一个挑战 从客户端角度看主机、端口和方案。

RFC 7239定义了 HTTP 标头 代理可用于提供有关原始请求的信息。还有其他 非标准标头也是如此,包括,,,,和。​​Forwarded​​​​X-Forwarded-Host​​​​X-Forwarded-Port​​​​X-Forwarded-Proto​​​​X-Forwarded-Ssl​​​​X-Forwarded-Prefix​

​ForwardedHeaderFilter​​是一个 Servlet 过滤器,它修改请求以便 a) 根据标头更改主机、端口和方案,以及 b) 删除它们 标头以消除进一步的影响。过滤器依赖于包装请求,并且 因此,它必须先于其他过滤器排序,例如, 应该使用修改后的请求而不是原始请求。​​Forwarded​​​​RequestContextFilter​

转发标头存在安全注意事项,因为应用程序无法知道 如果标头是由代理按预期添加的,或者是由恶意客户端添加的。这就是为什么 应将信任边界的代理配置为删除来自外部的不受信任标头。您还可以配置with,在这种情况下,它会删除但不使用标头。​​Forwarded​​​​ForwardedHeaderFilter​​​​removeOnly=true​

为了支持异步请求和错误调度,此 过滤器也应该映射。 如果使用 Spring 框架(参见Servlet Config),则所有过滤器都会自动注册到所有调度中。 类型。但是,如果通过 abe 在 Spring 启动中注册过滤器,请务必包括和此外。​​DispatcherType.ASYNC​​​​DispatcherType.ERROR​​​​AbstractAnnotationConfigDispatcherServletInitializer​​​​web.xml​​​​FilterRegistrationBean​​​​DispatcherType.ASYNC​​​​DispatcherType.ERROR​​​​DispatcherType.REQUEST​

1.2.3. 浅层ETag

过滤器通过缓存内容来创建“浅”ETag 写入响应并从中计算 MD5 哈希。下次客户端发送时, 它执行相同的操作,但它也会将计算值与请求标头进行比较,如果两者相等,则返回 304 (NOT_MODIFIED)。​​ShallowEtagHeaderFilter​​​​If-None-Match​

此策略可节省网络带宽,但不能节省 CPU,因为必须计算完整响应 对于每个请求。前面描述的控制器级别的其他策略可以避免 计算。请参阅HTTP 缓存。

此筛选器具有一个参数,用于将筛选器配置为写入弱 ETag 类似于以下内容:(如RFC 7232 第 2.3 节中所定义)。​​writeWeakETag​​​​W/"02a2d595e6ed9a0b24f027f2b63b134d6"​

为了支持异步请求,必须映射此筛选器 这样过滤器就可以延迟并成功生成 ETag 到最后一个异步调度的末尾。如果使用 Spring 框架(参见Servlet Config) 所有派单类型都会自动注册所有过滤器。但是,如果注册 通过 abe 的 Spring Boot 中的过滤器通道肯定包括。​​DispatcherType.ASYNC​​​​AbstractAnnotationConfigDispatcherServletInitializer​​​​web.xml​​​​FilterRegistrationBean​​​​DispatcherType.ASYNC​

1.2.4. CORS

网络通量

Spring MVC 通过注释为 CORS 配置提供细粒度支持 控制器。但是,当与 Spring 安全性一起使用时,我们建议依赖内置的,必须在 Spring Security 的过滤器链之前订购。​​CorsFilter​

有关更多详细信息,请参阅 CORS 和CORS 筛选器部分。

1.3. 带注释的控制者

网络通量

Spring MVC提供了一个基于注释的编程模型,其中组件使用注释来表达请求映射,请求输入, 异常处理等。带注释的控制器具有灵活的方法签名和 不必扩展基类,也不必实现特定的接口。 以下示例显示了由注释定义的控制器:​​@Controller​​​​@RestController​

@Controller
public class HelloController {

@GetMapping("/hello")
public String handle(Model model) {
model.addAttribute("message", "Hello World!");
return "index";
}
}

在前面的示例中,该方法接受 a,并返回视图名称作为 a, 但存在许多其他选项,本章稍后将对此进行解释。​​Model​​​​String​

1.3.1. 声明

网络通量

您可以通过在 仆人的。刻板印象允许自动检测, 与 Spring 对类路径中检测类的一般支持保持一致 并为它们自动注册 Bean 定义。它也充当 带注释的类,指示其作为 Web 组件的角色。​​WebApplicationContext​​​​@Controller​​​​@Component​

要启用此类豆的自动检测,您可以将组件扫描添加到 您的 Java 配置,如以下示例所示:​​@Controller​

@Configuration
@ComponentScan("org.example.web")
public class WebConfig {

// ...
}

以下示例显示了与上述示例等效的 XML 配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<context:component-scan base-package="org.example.web"/>

<!-- ... -->

</beans>

​@RestController​​是一个组合注释,即 本身元注释 withandto 表示其控制器 每个方法都继承类型级注释,因此写入 直接到响应正文与视图分辨率和使用 HTML 模板呈现。​​@Controller​​​​@ResponseBody​​​​@ResponseBody​

AOP 代理

网络通量

在某些情况下,您可能需要在运行时使用 AOP 代理修饰控制器。 一个例子是,如果您选择直接在 控制器。在这种情况下,特别是对于控制器,我们建议 使用基于类的代理。对于此类注释,情况会自动出现这种情况 直接在控制器上。​​@Transactional​

如果控制器实现接口,并且需要 AOP 代理,则可能需要 显式配置基于类的代理。例如,with您可以更改为,withyou可以更改为。​​@EnableTransactionManagement​​​​@EnableTransactionManagement(proxyTargetClass = true)​​​​<tx:annotation-driven/>​​​​<tx:annotation-driven proxy-target-class="true"/>​

1.3.2. 请求映射

网络通量

您可以使用注释将请求映射到控制器方法。它有 通过 URL、HTTP 方法、请求参数、标头和媒体匹配的各种属性 类型。您可以在类级别使用它来表示共享映射,也可以在方法级别使用它 以缩小到特定的终结点映射。​​@RequestMapping​

还有特定于 HTTP 方法的快捷方式变体:​​@RequestMapping​

  • ​@GetMapping​
  • ​@PostMapping​
  • ​@PutMapping​
  • ​@DeleteMapping​
  • ​@PatchMapping​

快捷方式是提供的自定义注释,因为, 可以说,大多数控制器方法应该映射到特定的HTTP方法,而不是 使用,默认情况下,它与所有 HTTP 方法匹配。 在类级别仍然需要 AI 来表达共享映射。​​@RequestMapping​​​​@RequestMapping​

以下示例具有类型和方法级别映射:

@RestController
@RequestMapping("/persons")
class PersonController {

@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
URI 模式

网络通量

​@RequestMapping​​可以使用 URL 模式映射方法。有两种选择:

  • ​PathPattern​​— 与同样预解析为 的 URL 路径匹配的预解析模式。该解决方案专为网络使用而设计,可有效处理编码和 路径参数,并有效匹配。PathContainer
  • ​AntPathMatcher​​— 将字符串模式与字符串路径匹配。这是原版 解决方案也用于 Spring 配置中,以选择类路径上的资源,在 文件系统和其他位置。它的效率较低,字符串路径输入为 有效处理 URL 编码和其他问题的挑战。

​PathPattern​​是 Web 应用程序的推荐解决方案,也是 Spring WebFlux.它从5.3版开始在Spring MVC中启用,并由 从版本 6.0 开始的默认值。请参阅MVC 配置 自定义路径匹配选项。

​PathPattern​​支持与 相同的模式语法。此外,它还 支持捕获模式,例如,用于匹配 0 个或多个路径段 在路径的末尾。还限制使用 for 匹配多个 路径段,以便仅在模式末尾允许。这消除了许多 为给定请求选择最佳匹配模式时出现歧义的情况。 有关完整的模式语法,请参阅 PathPattern 和AntPathMatcher。​​AntPathMatcher​​​​{*spring}​​​​PathPattern​​​​**​

一些示例模式:

  • ​"/resources/ima?e.png"​​- 匹配路径段中的一个字符
  • ​"/resources/*.png"​​- 匹配路径段中的零个或多个字符
  • ​"/resources/**"​​- 匹配多个路径段
  • ​"/projects/{project}/versions"​​- 匹配路径段并将其捕获为变量
  • ​"/projects/{project:[a-z]+}/versions"​​- 使用正则表达式匹配并捕获变量

可以使用 访问捕获的 URI 变量。例如:​​@PathVariable​

@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}

可以在类和方法级别声明 URI 变量,如以下示例所示:

@Controller
@RequestMapping("/owners/{ownerId}")
public class OwnerController {

@GetMapping("/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
}

URI 变量会自动转换为适当的类型,即引发的类型。默认情况下支持简单类型(,,,等),您可以 注册对任何其他数据类型的支持。 请参见类型转换和数据绑定程序。​​TypeMismatchException​​​​int​​​​long​​​​Date​

您可以显式命名 URI 变量(例如,),但您可以 如果名称相同,并且代码是通过调试编译的,则省略该详细信息 信息或带有 Java 8 上的编译器标志。​​@PathVariable("customId")​​​​-parameters​

语法声明一个 URI 变量,其正则表达式具有 的语法。例如,给定 URL,以下方法 提取名称、版本和文件扩展名:​​{varName:regex}​​​​{varName:regex}​​​​"/spring-web-3.0.5.jar"​

@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) {
// ...
}

URI 路径模式还可以具有在启动时解析的嵌入式占位符 通过使用针对本地、系统、环境和 其他属性来源。例如,您可以使用它根据 一些外部配置。​​${…}​​​​PropertySourcesPlaceholderConfigurer​

模式比较

网络通量

当多个模式与一个 URL 匹配时,必须选择最佳匹配模式。这是通过 以下之一,具体取决于是否启用了 Parsedis 的使用:​​PathPattern​

  • PathPattern.SPECIFICITY_COMPARATOR
  • AntPathMatcher.getPatternComparator(String path)

两者都有助于对模式进行排序,顶部有更具体的模式。在以下情况下,模式不太具体 它具有较低的 URI 变量计数(计为 1)、单个通配符(计为 1)、 和双通配符(计为 2)。给定相等的分数,选择较长的模式。 给定相同的分数和长度,具有比通配符更多的 URI 变量的模式是 选择。

默认映射模式 () 从评分中排除,并且始终 最后排序。此外,前缀模式(例如)被认为较少 比没有双通配符的其他模式更具体。​​/**​​​​/public/**​

有关完整详细信息,请点击上述模式比较器的链接。

后缀匹配

从 5.3 开始,默认情况下 Spring MVC 不再执行后缀模式 匹配控制器映射到的位置也是隐式映射到的。因此,不再使用路径扩展来解释 响应的请求内容类型,例如,,, 等等。​​.*​​​​/person​​​​/person.*​​​​/person.pdf​​​​/person.xml​

当浏览器用于发送标头时,以这种方式使用文件扩展名是必要的 很难一致地解释。目前,这不再是必需的, 使用标题应该是首选。​​Accept​​​​Accept​

随着时间的推移,文件扩展名的使用已被证明以多种方式存在问题。 当使用 URI 变量、路径参数和 URI 编码。关于基于 URL 的授权的推理 安全性(有关更多详细信息,请参阅下一节)也变得更加困难。

要在 5.3 之前的版本中完全禁用路径扩展,请设置以下内容:

  • ​useSuffixPatternMatching(false)​​,请参阅PathMatchConfigurer
  • ​favorPathExtension(false)​​,请参阅内容协商配置器

有一种方法可以通过标头以外的方式请求内容类型 有用,例如,在浏览器中键入 URL 时。路径扩展的安全替代方案是 以使用查询参数策略。如果必须使用文件扩展名,请考虑限制 它们通过ContentNegotiationConfigurer 的属性显式注册的扩展列表。​​"Accept"​​​​mediaTypes​

后缀匹配和 RFD

反射文件下载(RFD)攻击类似于XSS,因为它依赖于请求输入 (例如,查询参数和 URI 变量)反映在响应中。但是,而不是 将 JavaScript 插入 HTML 中,RFD 攻击依赖于浏览器切换来执行 下载响应并将其视为稍后双击时的可执行脚本。

在Spring MVC中,方法处于危险之中,因为 它们可以呈现不同的内容类型,客户端可以通过 URL 路径扩展请求这些内容类型。 禁用后缀模式匹配并使用路径扩展进行内容协商 降低风险,但不足以防止 RFD 攻击。​​@ResponseBody​​​​ResponseEntity​

为了防止RFD攻击,在呈现响应正文之前,Spring MVC添加了标头以建议固定和安全的下载 文件。仅当 URL 路径包含的文件扩展名既不是 允许为安全或明确注册用于内容协商。但是,它可以 直接在浏览器中键入 URL 时可能会产生副作用。​​Content-Disposition:inline;filename=f.txt​

默认情况下,许多公共路径扩展被允许为安全路径。具有自定义实现的应用程序可以显式注册内容的文件扩展名 协商以避免为这些扩展添加标头。 请参阅内容类型。​​HttpMessageConverter​​​​Content-Disposition​

有关其他信息CVE-2015-5211 与RFD相关的建议。

耗材介质类型

网络通量

您可以根据请求缩小请求映射的范围, 如以下示例所示:​​Content-Type​

@PostMapping(path = "/pets", consumes = "application/json") 
public void addPet(@RequestBody Pet pet) {
// ...
}

使用 aattribute 按内容类型缩小映射范围。​​consumes​

属性还支持否定表达式 — 例如,表示任何 内容类型除外。​​consumes​​​​!text/plain​​​​text/plain​

您可以在类级别声明共享属性。与大多数其他不同 但是,在类级别使用请求映射属性时,方法级别属性 重写而不是扩展类级声明。​​consumes​​​​consumes​

可生产介质类型

网络通量

您可以根据请求标头和列表缩小请求映射范围 控制器方法生成的内容类型,如以下示例所示:​​Accept​

@GetMapping(path = "/pets/{petId}", produces = "application/json") 
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}

使用 aattribute 按内容类型缩小映射范围。​​produces​

媒体类型可以指定字符集。支持否定表达式 — 例如,表示除“文本/纯文本”以外的任何内容类型。​​!text/plain​

您可以在类级别声明共享属性。与大多数其他不同 但是,在类级别使用请求映射属性时,方法级别属性 重写而不是扩展类级声明。​​produces​​​​produces​

参数、标头

网络通量

您可以根据请求参数条件缩小请求映射范围。您可以测试 存在请求参数 (),表示缺少请求参数 (),或 特定值 ()。以下示例演示如何测试特定值:​​myParam​​​​!myParam​​​​myParam=myValue​

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") 
public void findPet(@PathVariable String petId) {
// ...
}

测试是否相等。​​myParam​​​​myValue​

您还可以对请求标头条件使用相同的条件,如以下示例所示:

@GetMapping(path = "/pets", headers = "myHeader=myValue") 
public void findPet(@PathVariable String petId) {
// ...
}

测试是否相等。​​myHeader​​​​myValue​

HTTP 头, 选项

网络通量

​@GetMapping​​(和)支持HTTP HEAD 透明地用于请求映射。控制器方法不需要更改。 应用的响应包装器可确保将标头设置为写入的字节数(而不是实际写入响应)。​​@RequestMapping(method=HttpMethod.GET)​​​​jakarta.servlet.http.HttpServlet​​​​Content-Length​

​@GetMapping​​(和)隐式映射到 并支持 HTTP HEAD。HTTP HEAD 请求的处理方式就好像它是 HTTP GET 一样,除了 而不是写入正文,而是计算字节数并设置标头。​​@RequestMapping(method=HttpMethod.GET)​​​​Content-Length​

默认情况下,HTTP 选项是通过将响应标头设置为 HTTP 列表来处理的 具有匹配 URL 模式的所有方法中列出的方法。​​Allow​​​​@RequestMapping​

对于没有 HTTP 方法声明的 a,标头设置为 。控制器方法应始终声明 支持的 HTTP 方法(例如,通过使用 HTTP 方法特定的变体:、 和其他方法)。​​@RequestMapping​​​​Allow​​​​GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS​​​​@GetMapping​​​​@PostMapping​

您可以将该方法显式映射到HTTP HEAD和HTTP OPTIONS,但是 在常见情况下不是必需的。​​@RequestMapping​

自定义注释

网络通量

Spring MVC 支持使用组合注释进行请求映射。这些是本身被元注释的注释,并组成以重新声明具有更窄、更具体目的的属性子集(或全部)。​​@RequestMapping​​​​@RequestMapping​

​@GetMapping​​,,,,安代尔 组合批注的示例。之所以提供它们,是因为可以说,大多数 控制器方法应映射到特定的 HTTP 方法,而不是使用 默认情况下,它与所有 HTTP 方法匹配。如果您需要组合示例 注释,看看这些是如何声明的。​​@PostMapping​​​​@PutMapping​​​​@DeleteMapping​​​​@PatchMapping​​​​@RequestMapping​

Spring MVC 还支持具有自定义请求匹配的自定义请求映射属性 逻辑。这是一个更高级的选项,需要子类化和覆盖方法,其中 您可以检查自定义属性并返回您自己的属性。​​RequestMappingHandlerMapping​​​​getCustomMethodCondition​​​​RequestCondition​

显式注册

网络通量

可以通过编程方式注册处理程序方法,这些方法可用于动态 注册或高级案例,例如同一处理程序的不同实例 在不同的网址下。下面的示例注册处理程序方法:

@Configuration
public class MyConfig {

@Autowired
public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler)
throws NoSuchMethodException {

RequestMappingInfo info = RequestMappingInfo
.paths("/user/{id}").methods(RequestMethod.GET).build();

Method method = UserHandler.class.getMethod("getUser", Long.class);

mapping.registerMapping(info, handler, method);
}
}

注入控制器的目标处理程序和处理程序映射。

准备请求映射元数据。

获取处理程序方法。

添加注册。

1.3.3. 处理程序方法

网络通量

​@RequestMapping​​处理程序方法具有灵活的签名,可以从一系列 支持的控制器方法参数和返回值。

方法参数

网络通量

下表描述了支持的控制器方法参数。不支持反应式类型 对于任何参数。

JDK 8 的 sis 支持作为方法参数与 具有属性的批注(例如,,, 等)和等效。​​java.util.Optional​​​​required​​​​@RequestParam​​​​@RequestHeader​​​​required=false​

控制器方法参数

描述

​WebRequest​​​, ​​NativeWebRequest​

对请求参数以及请求和会话属性的通用访问,无需直接访问 使用 Servlet API。

​jakarta.servlet.ServletRequest​​​, ​​jakarta.servlet.ServletResponse​

选择任何特定的请求或响应类型,例如,,, 或春天的,。​​ServletRequest​​​​HttpServletRequest​​​​MultipartRequest​​​​MultipartHttpServletRequest​

​jakarta.servlet.http.HttpSession​

强制存在会话。因此,这样的论点永远不会。 请注意,会话访问不是线程安全的。考虑将实例的标志设置为多个 允许请求同时访问会话。​​null​​​​RequestMappingHandlerAdapter​​​​synchronizeOnSession​​​​true​

​jakarta.servlet.http.PushBuilder​

Servlet 4.0 推送生成器 API,用于编程 HTTP/2 资源推送。 请注意,根据 Servlet 规范,如果客户端 不支持该 HTTP/2 功能。​​PushBuilder​

​java.security.Principal​

当前经过身份验证的用户 — 可能是特定的实现类(如果已知)。​​Principal​

请注意,如果对此参数进行注释以允许自定义解析程序解析它,则不会急切地解决此参数 在回退到默认解决方案之前。 例如,Spring 安全实现和将通过以下方式注入,除非它也被注释,在这种情况下 由自定义 Spring 安全解析器通过解析。​​HttpServletRequest#getUserPrincipal​​​​Authentication​​​​Principal​​​​HttpServletRequest#getUserPrincipal​​​​@AuthenticationPrincipal​​​​Authentication#getPrincipal​

​HttpMethod​

请求的 HTTP 方法。

​java.util.Locale​

当前请求区域设置,由最具体的可用(在 效果,配置器)。​​LocaleResolver​​​​LocaleResolver​​​​LocaleContextResolver​

​java.util.TimeZone​​​ + ​​java.time.ZoneId​

与当前请求关联的时区,由 a 确定。​​LocaleContextResolver​

​java.io.InputStream​​​, ​​java.io.Reader​

用于访问由 Servlet API 公开的原始请求正文。

​java.io.OutputStream​​​, ​​java.io.Writer​

用于访问由 Servlet API 公开的原始响应正文。

​@PathVariable​

用于访问 URI 模板变量。请参阅URI 模式。

​@MatrixVariable​

用于访问 URI 路径段中的名称/值对。请参阅矩阵变量。

​@RequestParam​

用于访问 Servlet 请求参数,包括多部分文件。参数值 转换为声明的方法参数类型。也看@RequestParam​ 作为多部分。

请注意,对于简单参数值,使用 of 是可选的。 请参阅此表末尾的“任何其他参数”。​​@RequestParam​

​@RequestHeader​

用于访问请求标头。标头值将转换为声明的方法参数 类型。看@RequestHeader。

​@CookieValue​

用于访问饼干。Cookie 值将转换为声明的方法参数 类型。看@CookieValue。

​@RequestBody​

用于访问 HTTP 请求正文。正文内容转换为声明的方法 使用实现的参数类型。看@RequestBody​。​​HttpMessageConverter​

​HttpEntity<B>​

用于访问请求标头和正文。主体用 an. 请参阅HttpEntity​。​​HttpMessageConverter​

​@RequestPart​

要访问请求中的部件,转换部件的主体 请参阅多部分​。​​multipart/form-data​​​​HttpMessageConverter​

​java.util.Map​​​, , ​​org.springframework.ui.Model​​​​org.springframework.ui.ModelMap​

用于访问 HTML 控制器中使用的模型,并以 视图渲染的一部分。

​RedirectAttributes​

指定在重定向(即追加到查询)时要使用的属性 字符串)和 flash 属性要临时存储,直到请求重定向后。 请参阅重定向​属性和闪存属性。

​@ModelAttribute​

用于访问模型中的现有属性(如果不存在,则实例化) 应用了数据绑定和验证。请参阅@ModelAttribute​以及模型​和数据绑定器。

请注意,使用 of 是可选的(例如,设置其属性)。 请参阅此表末尾的“任何其他参数”。​​@ModelAttribute​

​Errors​​​, ​​BindingResult​

用于访问命令对象的验证和数据绑定中的错误 (即,aargument)或来自aorarguments验证的错误。你必须声明一个,或参数 紧跟在已验证的方法参数之后。​​@ModelAttribute​​​​@RequestBody​​​​@RequestPart​​​​Errors​​​​BindingResult​

​SessionStatus​​​+ 班级级别​​@SessionAttributes​

用于将表单处理标记为完成,这会触发会话属性的清理 通过类级注释声明。有关更多详细信息,请参阅@SessionAttributes​。​​@SessionAttributes​

​UriComponentsBuilder​

用于准备相对于当前请求的主机、端口、方案、上下文路径和 Servlet 映射的文本部分。请参阅URI 链接。

​@SessionAttribute​

用于访问任何会话属性,与存储在会话中的模型属性相反 作为类级声明的结果。有关更多详细信息,请参阅@SessionAttribute​。​​@SessionAttributes​

​@RequestAttribute​

用于访问请求属性。有关更多详细信息,请参阅@RequestAttribute。

任何其他参数

如果方法参数与此表中的任何早期值都不匹配,并且它是 一个简单的类型(由BeanUtils#isSimpleProperty​确定), 它被解析为 a。否则,它被解析为 a。@RequestParam@ModelAttribute

返回值

网络通量

下表描述了支持的控制器方法返回值。反应类型是 支持所有返回值。

控制器方法返回值

描述

​@ResponseBody​

返回值通过实现进行转换并写入 响应。看@ResponseBody​。​​HttpMessageConverter​

​HttpEntity<B>​​​, ​​ResponseEntity<B>​

指定完整响应(包括 HTTP 标头和正文)的返回值将被转换 通过实施并写入响应。 请参阅响应实体​。​​HttpMessageConverter​

​HttpHeaders​

用于返回带有标头且没有正文的响应。

​ErrorResponse​

若要在正文中呈现包含详细信息的 RFC 7807 错误响应, 请参阅错误响应

​ProblemDetail​

若要在正文中呈现包含详细信息的 RFC 7807 错误响应, 请参阅错误响应

​String​

要通过实现解析并与隐式一起使用的视图名称 模型 — 通过命令对象和方法确定。处理程序 方法还可以通过声明参数以编程方式丰富模型 (请参阅显式注册​)。​​ViewResolver​​​​@ModelAttribute​​​​Model​

​View​

用于与隐式模型一起渲染的实例 — 已确定 通过命令对象和方法。处理程序方法还可以 通过声明参数以编程方式丰富模型 (请参阅显式注册​)。​​View​​​​@ModelAttribute​​​​Model​

​java.util.Map​​​, ​​org.springframework.ui.Model​

要添加到隐式模型的属性,其中隐式确定视图名称 通过 a。​​RequestToViewNameTranslator​

​@ModelAttribute​

要添加到模型的属性,视图名称隐式确定为 一个。​​RequestToViewNameTranslator​

请注意,这是可选的。请参阅末尾的“任何其他返回值” 此表。​​@ModelAttribute​

​ModelAndView​​对象

要使用的视图和模型属性以及(可选)响应状态。

​void​

具有返回类型(或返回值)的方法被认为具有完全 处理响应(如果它也有 a、anargument或) 无注释。如果控制器进行了正数或时间戳检查,情况也是如此(有关详细信息,请参阅控制器​)。​​void​​​​null​​​​ServletResponse​​​​OutputStream​​​​@ResponseStatus​​​​ETag​​​​lastModified​

如果以上都不是真的,则返回类型也可以指示“无响应正文” REST 控制器或 HTML 控制器的默认视图名称选择。​​void​

​DeferredResult<V>​

从任何线程异步生成上述任何返回值,例如,作为 某些事件或回调的结果。请参阅异步请求​和延迟结果。

​Callable<V>​

在 Spring MVC 管理的线程中异步生成上述任何返回值。 请参阅异步请求和可调用。

​ListenableFuture<V>​​​, , ​​java.util.concurrent.CompletionStage<V>​​​​java.util.concurrent.CompletableFuture<V>​

为方便起见,替代(例如,当基础服务时 返回其中之一)。​​DeferredResult​

​ResponseBodyEmitter​​​, ​​SseEmitter​

异步发出对象流,以通过实现写入响应。也支持作为a的主体。 请参阅异步请求​和HTTP 流式处理​。​​HttpMessageConverter​​​​ResponseEntity​

​StreamingResponseBody​

异步写入响应。也支持作为a的主体。请参阅异步请求​和HTTP 流式处理​。​​OutputStream​​​​ResponseEntity​

反应器和其他反应类型通过​​ReactiveAdapterRegistry​

例如,单个值类型与返回相当。 例如,多值类型可以根据请求的流被视为流 媒体类型,例如“文本/事件流”、“应用程序/JSON +流”或其他 收集到列表并呈现为单个值。请参阅异步请求​和反应式类型​。​​Mono​​​​DeferredResult​​​​Flux​

其他返回值

如果返回值以任何其他方式仍未解析,则将其视为模型 属性,除非它是BeanUtils#isSimpleProperty 确定的简单类型, 在这种情况下,它仍然没有解决。

类型转换

网络通量

一些表示基于请求输入的带批注的控制器方法参数(例如,,,,和) 如果参数声明为非,则可能需要类型转换。​​String​​​​@RequestParam​​​​@RequestHeader​​​​@PathVariable​​​​@MatrixVariable​​​​@CookieValue​​​​String​

对于此类情况,将根据配置的转换器自动应用类型转换。 默认情况下,支持简单类型(,,, 和其他类型)。您可以自定义 类型转换通过 a(请参阅数据绑定程序)或通过注册。 请参阅弹簧字段格式。​​int​​​​long​​​​Date​​​​WebDataBinder​​​​Formatters​​​​FormattingConversionService​

类型转换中的一个实际问题是处理空的 String 源值。 如果此类值成为类型转换的结果,则将其视为缺失。 对于 和其他目标类型,可能就是这种情况。如果要允许注入,请在参数注释上使用标志,或声明 参数为。​​null​​​​Long​​​​UUID​​​​null​​​​required​​​​@Nullable​

矩阵变量

网络通量

RFC 3986讨论了 路径段。在Spring MVC中,我们将这些称为基于Tim Berners-Lee的“旧帖子”的“矩阵变量”,但它们 也可以称为 URI 路径参数。

矩阵变量可以出现在任何路径段中,每个变量用分号和 以逗号分隔的多个值(例如,)。倍数 还可以通过重复的变量名称(例如,)指定值。​​/cars;color=red,green;year=2012​​​​color=red;color=green;color=blue​

如果 URL 应包含矩阵变量,则控制器的请求映射 方法必须使用 URI 变量来屏蔽该变量内容并确保请求可以 成功匹配,不受矩阵变量顺序和存在的影响。 以下示例使用矩阵变量:

// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

// petId == 42
// q == 11
}

鉴于所有路径段都可能包含矩阵变量,有时可能需要 消除矩阵变量应位于哪个路径变量中的歧义。 以下示例演示如何执行此操作:

// GET /owners/42;q=11/pets/21;q=22

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable(name="q", pathVar="ownerId") int q1,
@MatrixVariable(name="q", pathVar="petId") int q2) {

// q1 == 11
// q2 == 22
}

矩阵变量可以定义为可选变量并指定默认值,如 以下示例显示:

// GET /pets/42

@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

// q == 1
}

若要获取所有矩阵变量,可以使用 a,如以下示例所示:​​MultiValueMap​

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap<String, String> matrixVars,
@MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) {

// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 22, "s" : 23]
}

请注意,您需要启用矩阵变量的使用。在 MVC Java 配置中, 您需要通过路径匹配进行设置。在 MVC XML 命名空间中,可以设置。​​UrlPathHelper​​​​removeSemicolonContent=false​​​​<mvc:annotation-driven enable-matrix-variables="true"/>​

​@RequestParam​

网络通量

您可以使用注释来绑定 Servlet 请求参数(即 查询参数或表单数据)到控制器中的方法参数。​​@RequestParam​

以下示例演示如何执行此操作:

@Controller
@RequestMapping("/pets")
public class EditPetForm {

// ...

@GetMapping
public String setupForm(@RequestParam("petId") int petId, Model model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}

// ...

}

用于绑定。​​@RequestParam​​​​petId​

默认情况下,使用此注释的方法参数是必需的,但您可以指定 方法参数是可选的,方法是通过使用包装器声明参数来设置注释的标志TOOR。​​@RequestParam​​​​required​​​​false​​​​java.util.Optional​

如果目标方法参数类型不是,则会自动应用类型转换。请参见类型转换。​​String​

将参数类型声明为数组或列表允许解析多个参数 相同参数名称的值。

当 anannotation 声明为 aor 时,注释中没有指定参数名称, 然后,使用每个给定参数名称的请求参数值填充映射。​​@RequestParam​​​​Map<String, String>​​​​MultiValueMap<String, String>​

请注意,使用 of 是可选的(例如,设置其属性)。 默认情况下,任何简单值类型的参数(由BeanUtils#isSimpleProperty 确定) 并且未被任何其他参数解析器解析,被视为已注释 跟。​​@RequestParam​​​​@RequestParam​

​@RequestHeader​

网络通量

您可以使用注释将请求标头绑定到方法参数 控制器。​​@RequestHeader​

请考虑以下带有标头的请求:

Host                    localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300

下面的示例获取 theandheader 的值:​​Accept-Encoding​​​​Keep-Alive​

@GetMapping("/demo")
public void handle(
@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}

获取标头的值。​​Accept-Encoding​

获取标头的值。​​Keep-Alive​

如果目标方法参数类型不是,则自动应用类型转换。请参见类型转换。​​String​

当在 a、、、或参数上使用 anannotation 时,将填充地图 包含所有标头值。​​@RequestHeader​​​​Map<String, String>​​​​MultiValueMap<String, String>​​​​HttpHeaders​

​@CookieValue​

网络通量

您可以使用注释将 HTTP cookie 的值绑定到方法参数 在控制器中。​​@CookieValue​

考虑使用以下 cookie 的请求:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的示例演示如何获取 cookie 值:

@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) {
//...
}

获取饼干的值。​​JSESSIONID​

如果目标方法参数类型不是,则会自动应用类型转换。 请参见类型转换。​​String​

​@ModelAttribute​

网络通量

您可以在方法参数上使用注释来访问属性 模型,或者如果不存在,则将其实例化。模型属性也覆盖了 来自名称与字段名称匹配的 HTTP Servlet 请求参数的值。这是参考的 作为数据绑定,它使您不必处理解析和转换单个 查询参数和表单字段。以下示例演示如何执行此操作:​​@ModelAttribute​

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) {
// method logic...
}

在旁边添加。​​BindingResult​​​​@ModelAttribute​

上面的实例通过以下方式之一获取:​​Pet​

  • 从可能已通过@ModelAttribute方法添加的模型中检索。
  • 如果模型属性列在 类级别@SessionAttributes批注。
  • 通过 awhere 获得的模型属性名称与 请求值,例如路径变量或请求参数(请参阅下一个示例)。Converter
  • 使用其默认构造函数实例化。
  • 通过带有与 Servlet 匹配的参数的“主构造函数”实例化 请求参数。参数名称是通过 JavaBeansor 通过字节码中运行时保留的参数名称确定的。@ConstructorProperties

使用 a@ModelAttribute 方法的一种替代方法 提供它或依靠框架来创建模型属性,是让 ATO 提供实例。当模型属性时应用此值 名称与请求值(如路径变量或请求)的名称匹配 参数,并且有 afromto 模型属性类型。 在以下示例中,模型属性名称是与 URI 匹配的 路径变量,并且有一个注册的 可以从数据存储中加载:​​Converter<String, T>​​​​Converter​​​​String​​​​account​​​​account​​​​Converter<String, Account>​​​​Account​

@PutMapping("/accounts/{account}")
public String save(@ModelAttribute("account") Account account) {
// ...
}

在旁边添加。​​BindingResult​​​​@ModelAttribute​

获取模型属性实例后,应用数据绑定。该类匹配 Servlet 请求参数名称(查询参数和表单 字段)到目标上的字段名称。匹配字段在类型后填充 必要时应用转换。有关数据绑定(和验证)的详细信息,请参阅验证。有关自定义数据绑定的详细信息,请参阅数据绑定程序。​​WebDataBinder​​​​Object​

数据绑定可能会导致错误。默认情况下,ais 已引发。但是,要检查 对于控制器方法中的此类错误,您可以立即在下一个添加参数 ,如以下示例所示:​​BindException​​​​BindingResult​​​​@ModelAttribute​

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}

设置。​​@ModelAttribute(binding=false)​

在某些情况下,您可能希望在不绑定数据的情况下访问模型属性。对于这样的 在这种情况下,您可以注入控制器并直接访问它, 或者,设置,如以下示例所示:​​Model​​​​@ModelAttribute(binding=false)​

@ModelAttribute
public AccountForm setUpForm() {
return new AccountForm();
}

@ModelAttribute
public Account findAccount(@PathVariable String accountId) {
return accountRepository.findOne(accountId);
}

@PostMapping("update")
public String update(@Valid AccountForm form, BindingResult result,
@ModelAttribute(binding=false) Account account) {
// ...
}

设置。​​@ModelAttribute(binding=false)​

您可以在数据绑定后通过添加注释或 Spring'san注释自动应用验证 (Bean验证和Spring 验证)。以下示例演示如何执行此操作:​​jakarta.validation.Valid​​​​@Validated​

@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) {
if (result.hasErrors()) {
return "petForm";
}
// ...
}

验证实例。​​Pet​

请注意,using是可选的(例如,设置其属性)。 默认情况下,任何不是简单值类型的参数(由BeanUtils#isSimpleProperty 确定) 并且未被任何其他参数解析器解析,就好像它被注释一样 跟。​​@ModelAttribute​​​​@ModelAttribute​

​@SessionAttributes​

网络通量

​@SessionAttributes​​用于在 HTTP Servlet 会话中存储模型属性 请求。它是一个类型级注释,用于声明 特定控制器。这通常列出模型属性的名称或类型 应透明地存储在会话中的模型属性以供后续使用 访问请求。

以下示例使用注释:​​@SessionAttributes​

@Controller
@SessionAttributes("pet")
public class EditPetForm {
// ...
}

使用注释。​​@SessionAttributes​

在第一个请求中,当将名称为 ,的模型属性添加到模型中时, 它会自动提升并保存在 HTTP Servlet 会话中。它仍然在那里 直到另一个控制器方法使用 aMethod 参数清除 存储,如以下示例所示:​​pet​​​​SessionStatus​

@Controller
@SessionAttributes("pet")
public class EditPetForm {

// ...

@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status) {
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}

将值存储在 Servlet 会话中。​​Pet​

从 Servlet 会话中清除值。​​Pet​

​@SessionAttribute​

网络通量

如果您需要访问全局管理的预先存在的会话属性 (即,在控制器外部 - 例如,通过过滤器)并且可能存在也可能不存在, 您可以在方法参数上使用注释, 如以下示例所示:​​@SessionAttribute​

@RequestMapping("/")
public String handle(@SessionAttribute User user) {
// ...
}

使用注释。​​@SessionAttribute​

对于需要添加或删除会话属性的用例,请考虑注入或注入控制器方法。​​org.springframework.web.context.request.WebRequest​​​​jakarta.servlet.http.HttpSession​

用于将模型属性作为控制器的一部分临时存储在会话中 工作流,请考虑使用如中所述@SessionAttributes。​​@SessionAttributes​

​@RequestAttribute​

网络通量

类似,您可以使用注释来 访问之前创建的预先存在的请求属性(例如,由 Servletor 创建):​​@SessionAttribute​​​​@RequestAttribute​​​​Filter​​​​HandlerInterceptor​

@GetMapping("/")
public String handle(@RequestAttribute Client client) {
// ...
}

使用注释。​​@RequestAttribute​

重定向属性

默认情况下,所有模型属性都被视为在 重定向网址。在其余属性中,那些是基元类型或 基元类型的集合或数组会自动追加为查询参数。

将基元类型属性追加为查询参数可能是所需的结果,如果 模型实例是专门为重定向准备的。但是,在注释中 控制器,模型可以包含为渲染目的而添加的其他属性(例如, 下拉字段值)。为了避免此类属性出现在 URL,一个方法可以声明一个类型和的参数 使用它来指定要提供给的确切属性。如果方法 确实重定向,使用的内容。否则,内容 使用模型。​​@RequestMapping​​​​RedirectAttributes​​​​RedirectView​​​​RedirectAttributes​

The提供了一个调用的标志,您可以使用该标志来指示在控制器方法重定向时不应使用默认值的内容。相反,控制器 方法应该声明 typeor 的属性,如果不这样做, 不应将任何属性传递给。MVC 命名空间和 MVC Java 配置将此标志设置为,以保持向后兼容性。 但是,对于新应用程序,我们建议将其设置为 。​​RequestMappingHandlerAdapter​​​​ignoreDefaultModelOnRedirect​​​​Model​​​​RedirectAttributes​​​​RedirectView​​​​false​​​​true​

请注意,来自当前请求的 URI 模板变量是自动生成的 展开重定向 URL 时可用,无需显式添加它们 通过者。以下示例演示如何定义重定向:​​Model​​​​RedirectAttributes​

@PostMapping("/files/{path}")
public String upload(...) {
// ...
return "redirect:files/{path}";
}

将数据传递到重定向目标的另一种方法是使用 flash 属性。与 其他重定向属性,Flash 属性保存在 HTTP 会话中(因此,执行 不显示在网址中)。有关详细信息,请参阅闪存属性。

闪光属性

Flash 属性为一个请求提供了一种存储用于 另一个。这是重定向时最常需要的 — 例如, 重定向后获取模式。Flash 属性在 重定向(通常在会话中)在 重定向并立即删除。

Spring MVC有两个主要的抽象来支持所使用的闪存 attributes.is 为了保存闪存属性,while 用于存储、检索和管理实例。​​FlashMap​​​​FlashMapManager​​​​FlashMap​

Flash 属性支持始终处于“打开”状态,不需要显式启用。 但是,如果不使用,它永远不会导致 HTTP 会话创建。在每个请求上,都有一个 “输入”使用从上一个请求(如果有)传递的属性和一个 “输出”具有要保存的属性以供后续请求使用。这两个实例都可以通过静态方法从Spring MVC中的任何位置访问。​​FlashMap​​​​FlashMap​​​​FlashMap​​​​RequestContextUtils​

带注释的控制器通常不需要直接使用。相反,amethod可以接受类型的参数并使用它 为重定向方案添加 Flash 属性。通过添加的 Flash 属性会自动传播到“输出”FlashMap。同样地 重定向后,来自“输入”的属性会自动添加到为目标 URL 提供服务的控制器中。​​FlashMap​​​​@RequestMapping​​​​RedirectAttributes​​​​RedirectAttributes​​​​FlashMap​​​​Model​

将请求与闪存属性匹配

闪存属性的概念存在于许多其他Web框架中,并且已被证明有时 面临并发问题。这是因为,根据定义,闪光属性 将存储到下一个请求。但是,“下一个”请求可能不是 预期收件人,但另一个异步请求(例如,轮询或资源请求), 在这种情况下,过早删除闪存属性。

为了减少此类问题的可能性,使用目标重定向 URL 的路径和查询参数自动“标记”实例。在 turn,默认值将该信息与传入请求匹配,当 它查找“输入”。​​RedirectView​​​​FlashMap​​​​FlashMapManager​​​​FlashMap​

这并不能完全消除并发问题的可能性,但 使用重定向 URL 中已有的信息大大减少它。 因此,我们建议您将闪存属性主要用于重定向方案。

多部件

网络通量

启用后,开机自检的内容 请求是解析的,可作为常规请求访问 参数。以下示例访问一个常规表单域和一个上载的表单域 文件:​​MultipartResolver​​​​multipart/form-data​

@Controller
public class FileUploadController {

@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {

if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}

将参数类型声明为允许解析多个参数 文件,以匹配相同的参数名称。​​List<MultipartFile>​

当注释声明为 aor 时,注释中没有指定参数名称, 然后,使用每个给定参数名称的多部分文件填充地图。​​@RequestParam​​​​Map<String, MultipartFile>​​​​MultiValueMap<String, MultipartFile>​

还可以将多部分内容用作命令对象数据绑定的一部分。例如,表单域 前面示例中的文件可以是表单对象上的字段, 如以下示例所示:

class MyForm {

private String name;

private MultipartFile file;

// ...
}

@Controller
public class FileUploadController {

@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
if (!form.getFile().isEmpty()) {
byte[] bytes = form.getFile().getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}

也可以从 RESTful 服务中的非浏览器客户端提交多部分请求 场景。以下示例显示了一个包含 JSON 的文件:

POST /someUrl
Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit

{
"name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...

您可以访问“元数据”部分,因为您将 可能希望它从 JSON 反序列化(类似于)。使用注释在转换多部分后访问多部分 使用HttpMessageConverter:​​@RequestParam​​​​String​​​​@RequestBody​​​​@RequestPart​

@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}

您可以结合使用或使用 Spring 的 sannotation,这两者都会导致应用标准 Bean 验证。 默认情况下,验证错误会导致 a,该错误被打开 转换为 400 (BAD_REQUEST) 响应。或者,您可以在本地处理验证错误 在控制器内通过无参数, 如以下示例所示:​​@RequestPart​​​​jakarta.validation.Valid​​​​@Validated​​​​MethodArgumentNotValidException​​​​Errors​​​​BindingResult​

爪哇岛

科特林

@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
​@RequestBody​

网络通量

您可以使用注释来读取请求正文,并通过HttpMessageConverter 将其反序列化为请求正文。 以下示例使用参数:​​@RequestBody​​​​Object​​​​@RequestBody​

@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
// ...
}

您可以使用MVC 配置的消息转换器选项来 配置或自定义消息转换。

您可以与 Spring 的 sannotation 结合使用,这两者都会导致应用标准 Bean 验证。 默认情况下,验证错误会导致 a,该错误被打开 转换为 400 (BAD_REQUEST) 响应。或者,您可以在本地处理验证错误 在控制器内通过无参数, 如以下示例所示:​​@RequestBody​​​​jakarta.validation.Valid​​​​@Validated​​​​MethodArgumentNotValidException​​​​Errors​​​​BindingResult​

@PostMapping("/accounts")
public void handle(@Valid @RequestBody Account account, BindingResult result) {
// ...
}
HttpEntity

网络通量

​HttpEntity​​或多或少与使用相同@RequestBody但基于 公开请求标头和正文的容器对象。下面的清单显示了一个示例:

@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
}
​@ResponseBody​

网络通量

可以在方法上使用注释来序列化返回 通过HttpMessageConverter 到响应正文。 下面的清单显示了一个示例:​​@ResponseBody​

@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
// ...
}

​@ResponseBody​​在类级别也受支持,在这种情况下,它由 所有控制器方法。这就是效果,仅此而已 而不是标记为 withand 的元注释。​​@RestController​​​​@Controller​​​​@ResponseBody​

可以与反应式类型一起使用。 有关更多详细信息,请参阅异步请求和反应式类型。​​@ResponseBody​

您可以使用MVC 配置的消息转换器选项来 配置或自定义消息转换。

可以将方法与 JSON 序列化视图结合使用。 有关详细信息,请参阅Jackson JSON。​​@ResponseBody​

响应实体

网络通量

​ResponseEntity​​就像@ResponseBody但带有状态和标题。例如:

@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).body(body);
}

Spring MVC 支持使用单值反应式类型异步生成,和/或单值和多值反应式 身体的类型。这允许以下类型的异步响应:​​ResponseEntity​

  • ​ResponseEntity<Mono<T>>​​或者做出响应状态和 标头在以后异步提供正文时立即已知。 使用如果主体由 0..1 个值组成,或者它可以生成多个值。ResponseEntity<Flux<T>>MonoFlux
  • ​Mono<ResponseEntity<T>>​​提供所有三个 — 响应状态、标头和正文, 在以后的点异步。这允许响应状态和标头变化 取决于异步请求处理的结果。
杰克逊·

Spring 提供对 Jackson JSON 库的支持。

JSON 视图

基于 Servlet API 并部署到 Servlet 容器

Spring MVC 为Jackson 的序列化视图提供内置支持, 仅允许呈现 AN 中所有字段的子集。若要使用 withorcontroller 方法,可以使用 Jackson sannotation 激活序列化视图类,如以下示例所示:​​Object​​​​@ResponseBody​​​​ResponseEntity​​​​@JsonView​

@RestController
public class UserController {

@GetMapping("/user")
@JsonView(User.WithoutPasswordView.class)
public User getUser() {
return new User("eric", "7!jd#h23");
}
}

public class User {

public interface WithoutPasswordView {};
public interface WithPasswordView extends WithoutPasswordView {};

private String username;
private String password;

public User() {
}

public User(String username, String password) {
this.username = username;
this.password = password;
}

@JsonView(WithoutPasswordView.class)
public String getUsername() {
return this.username;
}

@JsonView(WithPasswordView.class)
public String getPassword() {
return this.password;
}
}

如果要以编程方式执行上述操作,而不是声明 anannotation, 包装返回值并使用它来提供序列化视图:​​@JsonView​​​​MappingJacksonValue​

@RestController
public class UserController {

@GetMapping("/user")
public MappingJacksonValue getUser() {
User user = new User("eric", "7!jd#h23");
MappingJacksonValue value = new MappingJacksonValue(user);
value.setSerializationView(User.WithoutPasswordView.class);
return value;
}
}

对于依赖于视图分辨率的控制器,可以添加序列化视图类 到模型,如以下示例所示:

@Controller
public class UserController extends AbstractController {

@GetMapping("/user")
public String getUser(Model model) {
model.addAttribute("user", new User("eric", "7!jd#h23"));
model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class);
return "userView";
}
}

1.3.4. 模型

网络通量

您可以使用注释:​​@ModelAttribute​

  • 在方法参数方法上 创建或访问 ANFROM 模型,并通过 A 将其绑定到请求。@RequestMappingObjectWebDataBinder
  • 作为方法级注释 inorclasses 帮助 在 Any方法调用之前初始化模型。@Controller@ControllerAdvice@RequestMapping
  • 在一种方法上,标记其返回值是一个模型属性。@RequestMapping

本节讨论方法 — 前面列表中的第二项。 控制器可以有任意数量的方法。所有这些方法都是 在同一控制器中调用 before方法。Amethod也可以通过以下方式在控制器之间共享。有关更多详细信息,请参阅控制器建议部分。​​@ModelAttribute​​​​@ModelAttribute​​​​@RequestMapping​​​​@ModelAttribute​​​​@ControllerAdvice​

​@ModelAttribute​​方法具有灵活的方法签名。他们支持许多相同的 参数作为方法,除了它自己或任何东西 与请求正文相关。​​@RequestMapping​​​​@ModelAttribute​

以下示例显示了方法:​​@ModelAttribute​

@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
model.addAttribute(accountRepository.findAccount(number));
// add more ...
}

下面的示例仅添加一个属性:

@ModelAttribute
public Account addAccount(@RequestParam String number) {
return accountRepository.findAccount(number);
}

如果未显式指定名称,则会根据类型选择默认名称,如约定的​ javadoc 中所述。 始终可以使用重载方法或分配显式名称 通过属性 on(对于返回值)。​​Object​​​​addAttribute​​​​name​​​​@ModelAttribute​

您还可以将方法用作方法级注释, 在这种情况下,该方法的返回值被解释为模型 属性。这通常不是必需的,因为它是 HTML 控制器中的默认行为, 除非返回值为 a,否则将被解释为视图名称。还可以自定义模型属性名称,如以下示例所示:​​@ModelAttribute​​​​@RequestMapping​​​​@RequestMapping​​​​String​​​​@ModelAttribute​

@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
public Account handle() {
// ...
return account;
}