This part of the reference documentation covers Spring Framework’s support for the presentation tier (and specifically web-based presentation tiers) including support for WebSocket-style messaging in web applications.
这部分文档包含spring框架对于展示层的支持(并且特别指的是基于web的展示层)包括对于WebSocket风格的消息在一个web应用中。
Spring Framework’s own web framework, Spring Web MVC, is covered in the first couple of chapters. Subsequent chapters are concerned with Spring Framework’s integration with other web technologies, such as JSF.
spring框架自身的web框架,spring的web的mvc,是包含在章节的第一部分中。后续的章节包含了spring集成其他的web技术,例如JSF。
Following that is coverage of Spring Framework’s MVC portlet framework.
下面覆盖了spring框架mvc的指导框架。
The section then concludes with comprehensive coverage of the Spring Framework Chapter 26, WebSocket Support (including Section 26.4, “STOMP Over WebSocket Messaging Architecture”).
章节包含复杂的有关spring框架的26章节(包括章节26.4,“STOMP关于WebSocket消息的架构”)
Chapter 22, Web MVC framework
Chapter 23, View technologies
Chapter 24, Integrating with other web frameworks
Chapter 25, Portlet MVC Framework
Chapter 26, WebSocket Support
web mvc框架
22.1 Introduction to Spring Web MVC framework
介绍spring的web mvc框架
The Spring Web model-view-controller (MVC) framework is designed around a DispatcherServlet that dispatches requests to handlers, with configurable handler mappings, view resolution, locale, time zone and theme resolution as well as support for uploading files. The default handler is based on the @Controller and @RequestMapping annotations, offering a wide range of flexible handling methods. With the introduction of Spring 3.0, the @Controller mechanism also allows you to create RESTful Web sites and applications, through the @PathVariable annotation and other features.
spring的web 模型-视图-控制(MVC)框架设计围绕着DispatcherServlet来分发请求给处理器,配置处理器映射、视图处理、位置、失去和主题解决方案以及对于上传文件的支持。默认的处理器基于@Controller和@RequestMapping注解,提供了广泛的方便的处理方式。在spring的3.0中被引入,@Controller策略允许你创建RESTful风格的web站点和应用通过@PathVariable注解和其他特性。
"Open for extension…" A key design principle in Spring Web MVC and in Spring in general is the "Open for extension, closed for modification" principle.
“对扩展开发。。。”一个关键的设计理念在spring的web的mvc中并且通常在spring中是说“对于扩展开发,对于修改关闭”原则。
Some methods in the core classes of Spring Web MVC are marked final. As a developer you cannot override these methods to supply your own behavior. This has not been done arbitrarily, but specifically with this principle in mind.
一些在spring的web的mvc中的核心类是final的。作为开发者你不应该重写这些方法来支持你自己的行为。这不是一种武断,但是请记住这些原则。
For an explanation of this principle, refer to Expert Spring Web MVC and Web Flow by Seth Ladd and others; specifically see the section "A Look At Design," on page 117 of the first edition. Alternatively, see
对于这个原则的解释,请参考Expert Spring Web MVC and Web Flow,作者Seth Ladd等,尤其是章节“A Look At Design”在第一版的117页。也可以看
Bob Martin, The Open-Closed Principle (PDF)
You cannot add advice to final methods when you use Spring MVC. For example, you cannot add advice to the AbstractController.setSynchronizeOnSession() method. Refer to Section 11.6.1, “Understanding AOP proxies” for more information on AOP proxies and why you cannot add advice to final methods.
你不能添加advice对于final方法当你使用spring的mvc时。例如,你不能添加advice对于AbstractController.setSynchronizeOnSession()方法。参考11.6.1节,“理解AOP代理”来了解更多AOP代理及为什么你不能添加advice对于final方法。
In Spring Web MVC you can use any object as a command or form-backing object; you do not need to implement a framework-specific interface or base class. Spring’s data binding is highly flexible: for example, it treats type mismatches as validation errors that can be evaluated by the application, not as system errors. Thus you do not need to duplicate your business objects' properties as simple, untyped strings in your form objects simply to handle invalid submissions, or to convert the Strings properly. Instead, it is often preferable to bind directly to your business objects.
在spring的web的mvc中你可以使用任何object作为命令或支持的object,你不需要实现指定框架接口或基类。spring的数据绑定是高度自由的,例如,他处理类型匹配错误做为验证错误可以被应用处理,不是作为系统错误。你不需要重复定义你的业务object属性作为简单无类型的字符串在你的object来处理不合法的分配或适当的转换String。作为替代,可以直接绑定你的业务object。
Spring’s view resolution is extremely flexible. A Controller is typically responsible for preparing a model Map with data and selecting a view name but it can also write directly to the response stream and complete the request. View name resolution is highly configurable through file extension or Accept header content type negotiation, through bean names, a properties file, or even a custom ViewResolver implementation. The model (the M in MVC) is a Map interface, which allows for the complete abstraction of the view technology. You can integrate directly with template based rendering technologies such as JSP, Velocity and Freemarker, or directly generate XML, JSON, Atom, and many other types of content. The model Map is simply transformed into an appropriate format, such as JSP request attributes, a Velocity template model.
spring的视图处理是很方便的。一个控制器通常准备一个model的Map包含数据和视图名但是也可以直接是返回流和完整的请求。视图名可以配置通过文件扩展名或接受投上下文类型通过bean的名字、一个属性文件或自定义的ViewResolver实现。模型(MVC中的M)是一个Map接口,允许完整的视图技术抽象。你可以直接集成基于模板的技术如JSP、Velocity和Freemarker或直接生成XML、JSON、Atom和许多内容。model的映射可以简单转换为适当的形式,例如JSP请求属性,一个Velocity的模板模型。
22.1.1 Features of Spring Web MVC
spring的web的mvc的特性
Spring Web Flow
spring的web流
Spring Web Flow (SWF) aims to be the best solution for the management of web application page flow.
swf目的是对于web应用页面流实现最好的解决方案。
SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and Portlet environments. If you have a business process (or processes) that would benefit from a conversational model as opposed to a purely request model, then SWF may be the solution.
swf集成已有的框架例如spring的mvc和JSF,包括在Servlet和可变的环境中。如果你有一个业务处理(或多个处理)将从转换模型中获益作为纯净的请求模型,swf可以是一种方案。
SWF allows you to capture logical page flows as self-contained modules that are reusable in different situations, and as such is ideal for building web application modules that guide the user through controlled navigations that drive business processes.
swf允许你来抓取逻辑页面根据自包含的模块可以在不同的情况下重用,例如构建理想的web应用模块指导用户通过控制导航对于业务的流程。
For more information about SWF, consult the Spring Web Flow website.
关于更多有关swf的信息,参考spring的web流站点。
Spring’s web module includes many unique web support features:
spring的web模块包括许多独立的web支持特性:
Clear separation of roles. Each role?—?controller, validator, command object, form object, model object, DispatcherServlet, handler mapping, view resolver, and so on?—?can be fulfilled by a specialized object.
清晰的角色划分。每个角色————控制器、验证器、命令object、form的object、模型object、DispatcherServlet、处理匹配、视图解析等等————可以实现通过指定的object。
Powerful and straightforward configuration of both framework and application classes as JavaBeans. This configuration capability includes easy referencing across contexts, such as from web controllers to business objects and validators.
有力和直接的配置框架和应用类作为JavaBean。这个配置能力包括简单的引用跨越上下文,例如从web控制器到业务逻辑和验证。
Adaptability, non-intrusiveness, and flexibility. Define any controller method signature you need, possibly using one of the parameter annotations (such as @RequestParam, @RequestHeader, @PathVariable, and more) for a given scenario.
适应力、没有侵入性、方便的。定义任何控制器方法根据你的需要,使用参数注解中的一个(例如@RequestParam、@RequestHeader、@PathVariable等等)对于给定的场景。
Reusable business code, no need for duplication. Use existing business objects as command or form objects instead of mirroring them to extend a particular framework base class.
重用业务代码,不需要重复。使用已有的业务object作为命令或form的object镜像他们来执行特定框架基类。
Customizable binding and validation. Type mismatches as application-level validation errors that keep the offending value, localized date and number binding, and so on instead of String-only form objects with manual parsing and conversion to business objects.
自定义绑定和验证。类型不匹配例如应用层验证错误可以保持错误的值、日期和数值绑定等等来代替字符串————只有form的object使用手动解析和转换对于业务object。
Customizable handler mapping and view resolution. Handler mapping and view resolution strategies range from simple URL-based configuration, to sophisticated, purpose-built resolution strategies. Spring is more flexible than web MVC frameworks that mandate a particular technique.
自定义处理器匹配和视图处理。处理器匹配和视图解析策略来自简单的基于URL的配置,对于复杂的、构建目标的解决策略。spring是很方便的比web的mvc框架授权一个特定的技术。
Flexible model transfer. Model transfer with a name/value Map supports easy integration with any view technology.
方便的模型转换。模型转换使用name/value的Map支持简单的集成视图技术。
Customizable locale, time zone and theme resolution, support for JSPs with or without Spring tag library, support for JSTL, support for Velocity without the need for extra bridges, and so on.
自定义位置、时区和主题,支持JSP或不使用spring的标签库,支持JSTL,支持Velocity不需要额外的支持等等。
A simple yet powerful JSP tag library known as the Spring tag library that provides support for features such as data binding and themes. The custom tags allow for maximum flexibility in terms of markup code. For information on the tag library descriptor, see the appendix entitled Chapter 43, spring JSP Tag Library
一个简单有用的JSP标签库被知道是spring的标签库提供支持对于特性例如数据绑定和主题。自定义标签允许最大限度的自由在标记代码方面。关于标签描述的更多内容,见43章节,spring的标签库。
A JSP form tag library, introduced in Spring 2.0, that makes writing forms in JSP pages much easier. For information on the tag library descriptor, see the appendix entitled Chapter 44, spring-form JSP Tag Library
一个来自标签库的JSP,在spring2.0中被引入,使得更加简单的书写JSP页面。对于标签库描述符的更多信息,见章节44,spring风格的JSP标签库。
Beans whose lifecycle is scoped to the current HTTP request or HTTP Session. This is not a specific feature of Spring MVC itself, but rather of the WebApplicationContext container(s) that Spring MVC uses. These bean scopes are described in Section 7.5.4, “Request, session, global session, application, and WebSocket scopes”
bean的生命周期如果是当前HTTP请求或HTTP会话。不是spring的mvc本身的特定特性,但不是springmvc使用的WebApplicationContext容器。bean的范围描述在7.5.4章节,“请求、会话、全局会话、application和WebSocket范围”。
22.1.2 Pluggability of other MVC implementations
其他mvc实现的可插拔性
Non-Spring MVC implementations are preferable for some projects. Many teams expect to leverage their existing investment in skills and tools, for example with JSF.
非springmvc实现对于一些项目会更好。许多小组期望利用他们已经存在的技能和工具,例如JSF。
If you do not want to use Spring’s Web MVC, but intend to leverage other solutions that Spring offers, you can integrate the web MVC framework of your choice with Spring easily. Simply start up a Spring root application context through its ContextLoaderListener, and access it through its ServletContext attribute (or Spring’s respective helper method) from within any action object. No "plug-ins" are involved, so no dedicated integration is necessary. From the web layer’s point of view, you simply use Spring as a library, with the root application context instance as the entry point.
如果你不希望使用spring的web的mvc,但是试图利用其他spring提供的解决方案,你可以集成web mvc框架通过使用你的选择配合spring。简单的设置spring的根应用上下文通过他的ContextLoaderListener并且访问他通过ServletContext属性(或spring的各自助手方法)在任何action object中。没有插件被引入因此不需要专有的集成。根据web层的观点,你可以将spring当作一个库来使用,配合根应用上下文实例作为整个点。
Your registered beans and Spring’s services can be at your fingertips even without Spring’s Web MVC. Spring does not compete with other web frameworks in this scenario. It simply addresses the many areas that the pure web MVC frameworks do not, from bean configuration to data access and transaction handling. So you can enrich your application with a Spring middle tier and/or data access tier, even if you just want to use, for example, the transaction abstraction with JDBC or Hibernate.
你注册bean并且spring的服务可以在你的附近甚至不需要spring的web的mvc。spring在这种情况不会与其他web框架竞争。他简单的指示许多位置有些纯净的web的mvc框架不会有,来自bean的配置用于数据访问和事务处理。因此你可以丰富你的应用使用spring的中间层或数据访问层,即使你只是使用他们,例如,JDBC或Hibernate的事务翻译。
22.2 The DispatcherServlet
Spring’s web MVC framework is, like many other web MVC frameworks, request-driven, designed around a central Servlet that dispatches requests to controllers and offers other functionality that facilitates the development of web applications. Spring’s DispatcherServlet however, does more than just that. It is completely integrated with the Spring IoC container and as such allows you to use every other feature that Spring has.
spring的web的mvc框架是,像许多其他的web的mvc框架,基于请求,设计一个中间的servlet用于分发请求到控制器并且提供其他功能促进web应用的开发。spring的DispatcherServlet做的更多。他完全集成了IOC容器并且允许使用任何spring的特性。
The request processing workflow of the Spring Web MVC DispatcherServlet is illustrated in the following diagram. The pattern-savvy reader will recognize that the DispatcherServlet is an expression of the "Front Controller" design pattern (this is a pattern that Spring Web MVC shares with many other leading web frameworks).
spring的web mvc的DispatcherServlet的请求处理工作流是展示在下面的图片中的。对于模式理解的读者将意识到DispatcherServlet是一个“前端控制器”设计模式的表达(这是一个设计模式,spring web mvc框架想起和其他许多web框架共享使用)
Figure 22.1. The request processing workflow in Spring Web MVC (high level)
图22.1。在spring web mvc中请求处理工作流(高级)
The DispatcherServlet is an actual Servlet (it inherits from the HttpServlet base class), and as such is declared in your web application. You need to map requests that you want the DispatcherServlet to handle, by using a URL mapping. Here is a standard Java EE Servlet configuration in a Servlet 3.0+ environment:
DispatcherServlet是一个实际的servlet(他继承自HttpServlet基类),并且定义在你的web应用中。你需要映射你希望DispatcherServlet来处理的请求,通过使用URL匹配。这里给出一个标准JavaEE的Servlet配置在Servlet3.0以上的环境中:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/example/*");
}
}
In the preceding example, all requests starting with /example will be handled by the DispatcherServlet instance named example.
在之前的例子中,所有的请求以/example开始的都会被DispatcherServlet实例来处理。
WebApplicationInitializer is an interface provided by Spring MVC that ensures your code-based configuration is detected and automatically used to initialize any Servlet 3 container. An abstract base class implementation of this interface named AbstractAnnotationConfigDispatcherServletInitializer makes it even easier to register the DispatcherServlet by simply specifying its servlet mapping and listing configuration classes - it’s even the recommended way to set up your Spring MVC application. See Code-based Servlet container initialization for more details.
WebApplicationInitializer是一个接口由spring mvc提供保证你的基于代码的配置被自动探测并且被使用来初始化任何Servlet3容器。一个抽象基类实现这个接口是AbstractAnnotationConfigDispatcherServletInitializer使得他可以更加简单被注册DispatcherServlet通过简单指定他的servlet映射和监听器配置类————他甚至推荐设置你的spring mvc应用。见基于代码的Servlet容器初始化的更多内容。
The DispatcherServlet is an actual Servlet (it inherits from the HttpServlet base class), and as such is declared in the web.xml of your web application. You need to map requests that you want the DispatcherServlet to handle, by using a URL mapping in the same web.xml file. This is standard Java EE Servlet configuration; the following example shows such a DispatcherServlet declaration and mapping:
DispatcherServlet是一个实际的Servlet(他继承自HttpServlet基类),并且指定在你的web应用的web.xml文件中。你需要匹配你的请求当你希望DispatcherServlet来处理的时候,通过使用URL匹配在相同的web.xml文件中。这是标准的JavaEE的Servlet配置,后面的例子展示了这样一个DispatcherServlet声明和匹配。
Below is the web.xml equivalent of the above code based example:
下面的web.xml相当于上面的基于代码的例子:
As detailed in Section 7.15, “Additional Capabilities of the ApplicationContext”, ApplicationContext instances in Spring can be scoped. In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. The root WebApplicationContext should contain all the infrastructure beans that should be shared between your other contexts and Servlet instances. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.
详细细节在7.15章节,“ApplicationContext”的额外功能”,ApplicationContext实例在spring中是可以指定范文的。在web mvc框架中,每个DispatcherServlet有其自己的WebApplicationContext,继承所有的已经定义的bean在根WebApplicationContext中。根WebApplicationContext应当包含所有的基础bean应当被共享在你的其他上下文和Servlet实例之间。这些集成bean可以被覆盖在特定的servlet范围中,并且你可以定义新的指定范围的bean根据给定的Servlet实例。
Figure 22.2. Typical context hierarchy in Spring Web MVC
图22.2,典型的上下文结构咋spring的web mvc中
Upon initialization of a DispatcherServlet, Spring MVC looks for a file named [servlet-name]-servlet.xml in the WEB-INF directory of your web application and creates the beans defined there, overriding the definitions of any beans defined with the same name in the global scope.
上面DispatcherServlet的初始化,spring mvc查找一个文件名字为[servlet-name]-servlet.xml在你web应用的WEB-INF文件并且创建定义在那里的bean,覆盖任何bean定义在全局的范围的同名bean定义。
Consider the following DispatcherServlet Servlet configuration (in the web.xml file):
考虑下面的DispatcherServlet的Servlet配置(在web.xml文件中)
With the above Servlet configuration in place, you will need to have a file called /WEB-INF/golfing-servlet.xml in your application; this file will contain all of your Spring Web MVC-specific components (beans). You can change the exact location of this configuration file through a Servlet initialization parameter (see below for details).
使用上面的Servlet配置,你将需要有一个文件名字为/WEB-INF/golfing-servlet.xml在你的应用中;这个文件包含了你的spring的web指定mvc组件(bean)。你可以改变这个配置文件的实际位置通过Servlet初始化参数(见如下)
It is also possible to have just one root context for single DispatcherServlet scenarios.
他也可以有一个根上下文对于单个DispatcherServlet场景。
Figure 22.3. Single root context in Spring Web MVC
图22.3,单根上下文在spring的web mvc中
This can be configured by setting an empty contextConfigLocation servlet init parameter, as shown below:
这个可以被配置通过设置一个空的contextConfigLocation的Servlet初始化参数,展示如下:
The WebApplicationContext is an extension of the plain ApplicationContext that has some extra features necessary for web applications. It differs from a normal ApplicationContext in that it is capable of resolving themes (see Section 22.9, “Using themes”), and that it knows which Servlet it is associated with (by having a link to the ServletContext). The WebApplicationContext is bound in the ServletContext, and by using static methods on the RequestContextUtils class you can always look up the WebApplicationContext if you need access to it.
WebApplicationContext是一个普通ApplicationContext的扩展有一些额外的特性对于web应用是必须的。他和普通的ApplicationContext不同,他可以处理主题(见章节22.9,“使用主题”),并且他可以被servlet知道并连接(通过有一个到ServletContext的连接)。WebApplicationContext被绑定到ServletContext中,通过使用静态方法在RequestContextUtils类你可以查找WebApplicationContext如果你需要访问他的话。
Note that we can achieve the same with java-based configurations:
注意我们可以使用相同的基于java的配置。
public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class>[] getRootConfigClasses() {
// GolfingAppConfig defines beans that would be in root-context.xml
return new Class[] { GolfingAppConfig.class };
}
@Override
protected Class>[] getServletConfigClasses() {
// GolfingWebConfig defines beans that would be in golfing-servlet.xml
return new Class[] { GolfingWebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/golfing/*" };
}
}
22.2.1 Special Bean Types In the WebApplicationContext
在WebApplicationContext中指定bean的类型
The Spring DispatcherServlet uses special beans to process requests and render the appropriate views. These beans are part of Spring MVC. You can choose which special beans to use by simply configuring one or more of them in the WebApplicationContext. However, you don’t need to do that initially since Spring MVC maintains a list of default beans to use if you don’t configure any. More on that in the next section. First see the table below listing the special bean types the DispatcherServlet relies on.
spring的DispatcherServlet使用指定的bean来处理请求和解析适当的视图。这些bean作为spring mvc的一部分。你可以选择指定bean来使用通过简单的配置一个或多个在WebApplicationContext中。然而,你不需要最初这么做自从spring mvc包含了一个列表关于使用的默认bean如果你没有配置的话。在下一章节中会有介绍。首先让我们看一下下面的表格列出了DispatcherServlet依赖的指定bean的类型。
Table 22.1. Special bean types in the WebApplicationContext
表格22.1,在WebApplicationContext中指定的bean类型
Bean type bean类型 |
Explanation 解释 |
HandlerMapping |
Maps incoming requests to handlers and a list of pre- and post-processors (handler interceptors) based on some criteria the details of which vary by HandlerMapping implementation. The most popular implementation supports annotated controllers but other implementations exists as well. 映射捕获请求给处理器并且前或后的拦截器基于一些标准的处理根据不同的HandlerMapping的实现。最流行的实现支持注解控制但是其他实现也是存在的。 |
HandlerAdapter |
Helps the DispatcherServlet to invoke a handler mapped to a request regardless of the handler is actually invoked. For example, invoking an annotated controller requires resolving various annotations. Thus the main purpose of a HandlerAdapter is to shield the DispatcherServlet from such details. 帮助DispatcherServlet来调用一个处理对于一个请求的映射而不是实际的处理器的调用。例如,调用一个注解控制器要求解析不同的注解。HandlerAdapter的主要目的是屏蔽一些DispatcherServlet的细节。 |
HandlerExceptionResolver |
Maps exceptions to views also allowing for more complex exception handling code. 映射对于视图的异常运行较复杂的异常处理代码。 |
ViewResolver |
Resolves logical String-based view names to actual View types. 处理逻辑字符串基于视图名对于实际的视图类型 |
LocaleResolver & LocaleContextResolver |
Resolves the locale a client is using and possibly their time zone, in order to be able to offer internationalized views 处理客户端的位置被用于和可能的时区,用于提供国际化的视图 |
ThemeResolver |
Resolves themes your web application can use, for example, to offer personalized layouts 处理你web应用可以使用的主题,例如,提供独立的表示 |
MultipartResolver |
Parses multi-part requests for example to support processing file uploads from HTML forms. 解析多部分请求例如来支持处理文件上传来自HTML的表单。 |
FlashMapManager |
Stores and retrieves the "input" and the "output" FlashMap that can be used to pass attributes from one request to another, usually across a redirect. 存储和获得输入和输出的FlashMap可以用于传递属性从一个请求到另一个请求,通常是跨越转发的。 |
22.2.2 Default DispatcherServlet Configuration
默认的DispatcherServlet配置
As mentioned in the previous section for each special bean the DispatcherServlet maintains a list of implementations to use by default. This information is kept in the file DispatcherServlet.properties in the package org.springframework.web.servlet.
就像之前每个特定bean提到的DispatcherServlet维持默认的实现列表。这个信息保存在文件DispatcherServlet.properties中在org.springframework.web.servlet包中。
All special beans have some reasonable defaults of their own. Sooner or later though you’ll need to customize one or more of the properties these beans provide. For example it’s quite common to configure an InternalResourceViewResolver settings its prefix property to the parent location of view files.
所有的特殊的bean有一些原因默认。迟早你会需要自定义一个或多个这些bean提供的属性。例如,通常配置一个InternalResourceViewResolver设置它的前缀对于视图文件的父位置。
Regardless of the details, the important concept to understand here is that once you configure a special bean such as an InternalResourceViewResolver in your WebApplicationContext, you effectively override the list of default implementations that would have been used otherwise for that special bean type. For example if you configure an InternalResourceViewResolver, the default list of ViewResolver implementations is ignored.
尽管细节,重要的概念在这里需要理解是一旦你配置了指定bean的属性例如在你的web应用中的InternalResourceViewResolver,你影响的是默认实现列表将使用指定的bean类型。例如,如果你配置了一个InternalResourceViewResolver,默认的ViewResolver的列表会被忽略。
In Section 22.16, “Configuring Spring MVC” you’ll learn about other options for configuring Spring MVC including MVC Java config and the MVC XML namespace both of which provide a simple starting point and assume little knowledge of how Spring MVC works. Regardless of how you choose to configure your application, the concepts explained in this section are fundamental should be of help to you.
在章节22.16中,“配置spring的mvc”你将了解其他选项有关配置spring mvc包括mvc java配置和mvc xml命名空间提供简单的开始点和假设一点spring mvc的知识就可以工作。尽管你选择配置你的应用,在这节中解释的观点基本会帮助到你。
22.2.3 DispatcherServlet Processing Sequence
DispatcherServlet处理顺序
After you set up a DispatcherServlet, and a request comes in for that specific DispatcherServlet, the DispatcherServlet starts processing the request as follows:
在你设置一个DispatcherServlet之后,并且一个请求到来对于指定的DispatcherServlet,DispatcherServlet开始处理一个请求如下:
The WebApplicationContext is searched for and bound in the request as an attribute that the controller and other elements in the process can use. It is bound by default under the key DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE.
WebApplicationContext被查找和绑定在请求中作为一个属性使得控制器和其他处理中的元素可以使用。他绑定默认在关键的DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE中。
The locale resolver is bound to the request to enable elements in the process to resolve the locale to use when processing the request (rendering the view, preparing data, and so on). If you do not need locale resolving, you do not need it.
位置处理器绑定到请求中允许元素在处理中处理使用的位置当处理请求时(解析视图、处理数据等等)。如果你不需要位置解析,你可以不需要他。
The theme resolver is bound to the request to let elements such as views determine which theme to use. If you do not use themes, you can ignore it.
主题接替绑定到请求中使得元素例如视图决定应该使用的主题。如果你不需要使用主题,你可以忽略他。
If you specify a multipart file resolver, the request is inspected for multiparts; if multiparts are found, the request is wrapped in a MultipartHttpServletRequest for further processing by other elements in the process. See Section 22.10, “Spring’s multipart (file upload) support” for further information about multipart handling.
如果你指定多个文件解析器,请求是检查多个部分,如果多个部分被检查到,请求被包裹在一个MultipartHttpServletRequest对于更进一步的处理通过其他的元素在过程中。见22.10章节,“spring的多部分(文件上传)支持”来了解更多信息有关多部分处理。
An appropriate handler is searched for. If a handler is found, the execution chain associated with the handler (preprocessors, postprocessors, and controllers) is executed in order to prepare a model or rendering.
查找适当的处理器。如果一个处理器被找到,执行链连接处理器(处理器、后处理器和控制器)被按顺序执行来准备一个模型或解析。
If a model is returned, the view is rendered. If no model is returned, (may be due to a preprocessor or postprocessor intercepting the request, perhaps for security reasons), no view is rendered, because the request could already have been fulfilled.
如果一个模型被返回,视图被解析。如果没有模型被返回,(或许由于前处理器或后处理器拦截了请求,或者安全原因),没有试图被解析,应为请求已经被处理了。
Handler exception resolvers that are declared in the WebApplicationContext pick up exceptions that are thrown during processing of the request. Using these exception resolvers allows you to define custom behaviors to address exceptions.
处理异常解析定义在WebApplicationContext获得异常在处理请求时被抛出。使用这些异常解析允许你来定义自定义行为来处理异常。
The Spring DispatcherServlet also supports the return of the last-modification-date, as specified by the Servlet API. The process of determining the last modification date for a specific request is straightforward: the DispatcherServlet looks up an appropriate handler mapping and tests whether the handler that is found implements the LastModified interface. If so, the value of the long getLastModified(request) method of the LastModified interface is returned to the client.
spring的DispatcherServlet也支持返回最后修改日期,通过Servlet的API来定义。决定最后修改日期的处理对于特定的请求是直接的,DispatcherServlet查找一个适当的处理映射和测试当处理查找实现LastModified接口。如果这么做,getLastModified(request)方法的返回值被返回给客户端。
You can customize individual DispatcherServlet instances by adding Servlet initialization parameters ( init-param elements) to the Servlet declaration in the web.xml file. See the following table for the list of supported parameters.
你可以自定义独立的DispatcherServlet实例通过添加Servlet的初始化参数(init-param元素)对于servlet定义在web.xml文件中。见下面支持参数的表格。
Table 22.2. DispatcherServlet initialization parameters
表格22.2,DispatcherServlet初始化参数
Parameter 参数 |
Explanation 解释 |
contextClass |
Class that implements WebApplicationContext, which instantiates the context used by this Servlet. By default, the XmlWebApplicationContext is used. 类实现了WebApplicationContext,指定了被这个servlet使用的上下文。默认情况下,使用XmlWebApplicationContext。 |
contextConfigLocation |
String that is passed to the context instance (specified by contextClass) to indicate where context(s) can be found. The string consists potentially of multiple strings (using a comma as a delimiter) to support multiple contexts. In case of multiple context locations with beans that are defined twice, the latest location takes precedence. 传递给上下文实例的字符串(通过contextClass来指定)来指示可以被找到的上下文。字符串包括潜在的多字符串(使用逗号分隔)来支持多个上下文。由于多个上下文路径bean被定义两次,最后定义的优先级最高。 |
namespace |
Namespace of the WebApplicationContext. Defaults to [servlet-name]-servlet. WebApplicationContext的命名空间,默认是[servlet-name]-servlet |
22.3 Implementing Controllers
实现控制器
Controllers provide access to the application behavior that you typically define through a service interface. Controllers interpret user input and transform it into a model that is represented to the user by the view. Spring implements a controller in a very abstract way, which enables you to create a wide variety of controllers.
控制器提供访问对于应用的行为你通常定义通过一个服务接口。控制器拦截用户的输入并转换为一个模型被视图来使用。spring实现一个控制器以非常抽象的形式,允许你来创建一个不同的控制器。
Spring 2.5 introduced an annotation-based programming model for MVC controllers that uses annotations such as @RequestMapping, @RequestParam, @ModelAttribute, and so on. This annotation support is available for both Servlet MVC and Portlet MVC. Controllers implemented in this style do not have to extend specific base classes or implement specific interfaces. Furthermore, they do not usually have direct dependencies on Servlet or Portlet APIs, although you can easily configure access to Servlet or Portlet facilities.
spring2.5引入了一个基于注解的编程模型对于mvc的控制器使用注解例如@RequestMapping、@RequestParam、@ModelAttribute等等。注解执行对于Servlet mvc和porlet mvc。控制器实现以这样的风格不需要继承特定的基类或引入特定的接口。此外,他们不需要直接依赖于servlet或移动API,使得你可以简单的配置Servlet和Portlet设施。
[Tip]
提示
Available in the spring-projects Org on Github, a number of web applications leverage the annotation support described in this section including MvcShowcase, MvcAjax, MvcBasic, PetClinic, PetCare, and others.
在spring项目org的github主页,很多web应用利用的注解支持描述这个章节的内容包括MvcShowcase、MvcAjax、MvcBasic、PetClinic、PetCare等等。
@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
}
As you can see, the @Controller and @RequestMapping annotations allow flexible method names and signatures. In this particular example the method accepts a Model and returns a view name as a String, but various other method parameters and return values can be used as explained later in this section. @Controller and @RequestMapping and a number of other annotations form the basis for the Spring MVC implementation. This section documents these annotations and how they are most commonly used in a Servlet environment.
就像你看到的,@Controller和@RequestMapping注解允许方便的方法名和签名。在这特殊的例子中,方法接收一个Model并返回一个视图名字的字符串,但是多个其他方法参数和返回值可以被使用会在后面的章节中说明。@Controller和@RequestMapping和一些其他的注解来自基本spring的mvc的实现。这节说明了注解和他们是如何使用在servlet环境中的。
22.3.1 Defining a controller with @Controller
使用@Controller来定义一个控制器
The @Controller annotation indicates that a particular class serves the role of a controller. Spring does not require you to extend any controller base class or reference the Servlet API. However, you can still reference Servlet-specific features if you need to.
@Controller注解指示了一个特定的类作为一个控制器来工作。spring没有要求你来扩展任何控制器基类或引用Servlet的API。然而,你依然可以引用指定Servlet的特性如果你需要的话。
The @Controller annotation acts as a stereotype for the annotated class, indicating its role. The dispatcher scans such annotated classes for mapped methods and detects @RequestMapping annotations (see the next section).
@Controller注解扮演一个模板的角色对于注解类。dispatcher扫描这样的注解类对于匹配方法和探测@RequestMapping注解(见下一节)。
You can define annotated controller beans explicitly, using a standard Spring bean definition in the dispatcher’s context. However, the @Controller stereotype also allows for autodetection, aligned with Spring general support for detecting component classes in the classpath and auto-registering bean definitions for them.
你可以直接定义注解控制器bean,使用一个标准的spring的bean定义在dispatcher的上下文中。然而,@Controller依然允许自动探测,可以和spring的通用支持对于探测组件类在类路径和为他们自动注册bean定义。
To enable autodetection of such annotated controllers, you add component scanning to your configuration. Use the spring-context schema as shown in the following XML snippet:
为了允许自动探测这样的注解控制器,你添加组件扫描对于你的配置。使用spring-context的schema展示在下面的xml片段中:
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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
22.3.2 Mapping Requests With @RequestMapping
使用@RequestMapping来匹配请求
You use the @RequestMapping annotation to map URLs such as /appointments onto an entire class or a particular handler method. Typically the class-level annotation maps a specific request path (or path pattern) onto a form controller, with additional method-level annotations narrowing the primary mapping for a specific HTTP method request method ("GET", "POST", etc.) or an HTTP request parameter condition.
你使用@RequestMapping注解来匹配URL类似于/appointments和整个类或特殊的处理方法。通常类级别的注解匹配一个请求路径(或路径模式)对于一个控制器,此外方法级别的注解缩小了主匹配对于特定的HTTP方法请求方法(GET、POST等等)或一个HTTP请求参数条件。
The following example from the Petcare sample shows a controller in a Spring MVC application that uses this annotation:
下面的例子来自Petcare例子展示了一个控制器在spring的mvc应用中使用这个注解:
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
@RequestMapping(method = RequestMethod.GET)
public Map
return appointmentBook.getAppointmentsForToday();
}
@RequestMapping(path = "/{day}", method = RequestMethod.GET)
public Map
return appointmentBook.getAppointmentsForDay(day);
}
@RequestMapping(path = "/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
@RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
In the above example, @RequestMapping is used in a number of places. The first usage is on the type (class) level, which indicates that all handler methods in this controller are relative to the /appointments path. The get() method has a further @RequestMapping refinement: it only accepts GET requests, meaning that an HTTP GET for /appointments invokes this method. The add() has a similar refinement, and the getNewForm() combines the definition of HTTP method and path into one, so that GET requests for appointments/new are handled by that method.
在上面的例子中,@RequestMapping被用于很多位置。第一种用法是在类级别,指示所有的请求方法在这个控制器中都是相对于/appointments路径的。get方法返回一个@RequestMapping:他只接受get请求,意味着HTTP的get请求对于/appointments会调用这个方法。add有相同的签名,并且getNewForm组合定义了HTTP方法和李静,因此get请求对于appointments/new会被这个方法来处理。
The getForDay() method shows another usage of @RequestMapping: URI templates. (See the section called “URI Template Patterns”).
getForDay方法展示了另一种@RequestMapping的用法:URI模板。(见章节“URI模板形式”)
A @RequestMapping on the class level is not required. Without it, all paths are simply absolute, and not relative. The following example from the PetClinic sample application shows a multi-action controller using @RequestMapping:
@RequestMapping在类的级别是不必须的。不使用的话,所有的路径是简单的绝对路径而不是相对的。下面的例子来自PetClinic样例应用展示了多行为的控制器使用@RequestMapping:
@Controller
public class ClinicController {
private final Clinic clinic;
@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
@RequestMapping("/")
public void welcomeHandler() {
}
@RequestMapping("/vets")
public ModelMap vetsHandler() {
return new ModelMap(this.clinic.getVets());
}
}
The above example does not specify GET vs. PUT, POST, and so forth, because @RequestMapping maps all HTTP methods by default. Use @RequestMapping(method=GET) or @GetMapping to narrow the mapping.
上面的例子没有指定GET、PUT、POST等等,因为@RequestMapping默认匹配所有的http方法。使用@RequestMapping(method=GET)或@GetMapping来缩小匹配。
Composed @RequestMapping Variants
组合@RequestMapping变量
Spring Framework 4.3 introduces the following method-level composed variants of the @RequestMapping annotation that help to simplify mappings for common HTTP methods and better express the semantics of the annotated handler method. For example, a @GetMapping can be read as a GET @RequestMapping.
spring框架4.3引入了下面的方法级别的组合变量对于@RequestMapping注解来帮助简单的匹配通用的http方法和较好的展示注解处理方法的语义。例如,@GetMapping可以处理get方式的@RequestMapping。
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
The following example shows a modified version of the AppointmentsController from the previous section that has been simplified with composed @RequestMapping annotations.
下面的例子展示了一个修改版本的AppointmentsController来自前面的章节使用了简单组合@RequestMapping注解。
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
@GetMapping
public Map
return appointmentBook.getAppointmentsForToday();
}
@GetMapping("/{day}")
public Map
return appointmentBook.getAppointmentsForDay(day);
}
@GetMapping("/new")
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
@PostMapping
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}
@Controller and AOP Proxying
@Controller和AOP代理
In some cases a controller may need to be decorated with an AOP proxy at runtime. One example is if you choose to have @Transactional annotations directly on the controller. When this is the case, for controllers specifically, we recommend using class-based proxying. This is typically the default choice with controllers. However if a controller must implement an interface that is not a Spring Context callback (e.g. InitializingBean, *Aware, etc), you may need to explicitly configure class-based proxying. For example with
在一些情况一个控制器需要被修饰为aop代理在运行时。一个例子是如果你选择@Transactional注解直接来修饰控制器。当是这种情况,对于指定的控制器,我们建议使用基于类的代理。通常默认是控制器默认的选项。然而如果一个控制器必须实现接口而不是spring上下文的回调(例如,InitializingBean、*Aware等等),你可能需要直接配置基于类的代理。例如,使用
New Support Classes for @RequestMapping methods in Spring MVC 3.1
在spring的mvc3.1中对于@RequestMapping方法新的支持类
Spring 3.1 introduced a new set of support classes for @RequestMapping methods called RequestMappingHandlerMapping and RequestMappingHandlerAdapter respectively. They are recommended for use and even required to take advantage of new features in Spring MVC 3.1 and going forward. The new support classes are enabled by default by the MVC namespace and the MVC Java config but must be configured explicitly if using neither. This section describes a few important differences between the old and the new support classes.
spring3.1引入了一系列支持类对于@RequestMapping方法名字分别为RequestMappingHandlerMapping和RequestMappingHandlerAdapter。他们被建议使用甚至在spring3.1中有许多新的特性并且会延续下去。新的支持类由默认的mvc命名空间来允许并且mvc的java配置但是必须在使用的时候明确配置。这一节描述一个新的重要的不同关于以前和新的支持类。
Prior to Spring 3.1, type and method-level request mappings were examined in two separate stages — a controller was selected first by the DefaultAnnotationHandlerMapping and the actual method to invoke was narrowed down second by the AnnotationMethodHandlerAdapter.
在spring3.1之前,类型和方法级别的请求映射是解释在两个不同的情况————一个控制首先被DefaultAnnotationHandlerMapping来选择并且实际调用的缩小范围是通过AnnotationMethodHandlerAdapter。
With the new support classes in Spring 3.1, the RequestMappingHandlerMapping is the only place where a decision is made about which method should process the request. Think of controller methods as a collection of unique endpoints with mappings for each method derived from type and method-level @RequestMapping information.
在spring3.1新的支持类下,RequestMappingHandlerMapping是唯一的位置来决定哪个方法来处理请求。考虑控制器方法作为一个唯一的位置来匹配每个方法来源于类型和方法级别的@RequestMapping信息。
This enables some new possibilities. For once a HandlerInterceptor or a HandlerExceptionResolver can now expect the Object-based handler to be a HandlerMethod, which allows them to examine the exact method, its parameters and associated annotations. The processing for a URL no longer needs to be split across different controllers.
这允许一些新的可能。对于HandlerInterceptor或HandlerExceptionResolver可以期望基于object的处理器可以是一个HandlerMethod,允许他们来检查实际的方法,他的参数和关联的注解。处理一个URL不在需要分给不同的控制器。
There are also several things no longer possible:
下面的事情不在可能了:
Select a controller first with a SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping and then narrow the method based on @RequestMapping annotations.
选择一个控制器使用SimpleUrlHandlerMapping或BeanNameUrlHandlerMapping并且缩小方法范围对于@RequestMapping注解。
Rely on method names as a fall-back mechanism to disambiguate between two @RequestMapping methods that don’t have an explicit path mapping URL path but otherwise match equally, e.g. by HTTP method. In the new support classes @RequestMapping methods have to be mapped uniquely.
依赖一个方法名作为回调策略来消除两个@RequestMapping方法没有指定路径匹配URL路径但是其他匹配是相同的,例如通过HTTP方法。在新的支持类@RequestMapping方法必须唯一匹配。
Have a single default method (without an explicit path mapping) with which requests are processed if no other controller method matches more concretely. In the new support classes if a matching method is not found a 404 error is raised.
有一个单一的默认方法(不需要指定路径匹配)可以处理请求如果没有具体控制器方法匹配。在新的支持类如果一个匹配方法没有找到会返回404错误。
The above features are still supported with the existing support classes. However to take advantage of new Spring MVC 3.1 features you’ll need to use the new support classes.
上面的特性将一直支持因为存在的支持类。然而为了使用spring3.1新的特性,你将需要使用新的支持类。
URI Template Patterns
URI模板模式
URI templates can be used for convenient access to selected parts of a URL in a @RequestMapping method.
URI模板可以方便的使用来访问选择URL在@RequestMapping方法中。
A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the template becomes a URI. The proposed RFC for URI Templates defines how a URI is parameterized. For example, the URI Template http://www.example.com/users/{userId} contains the variable userId. Assigning the value fred to the variable yields http://www.example.com/users/fred.
一个URI模板是一个类似于URI的字符串,包含一个或多个变量名。当你替代这些变量值,模板将成为一个URI。RFC建议对于URI模板定义了一个URI是如何参数化的。例如,URI模板http://www.example.com/users/{userId}包含变量userId。分配变量值为fred则http://www.example.com/users/fred。
In Spring MVC you can use the @PathVariable annotation on a method argument to bind it to the value of a URI template variable:
在spring的mvc中你可以使用@PathVariable注解在方法上声明绑定URI模板变量的值:
@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
The URI Template " /owners/{ownerId}`" specifies the variable name `ownerId. When the controller handles this request, the value of ownerId is set to the value found in the appropriate part of the URI. For example, when a request comes in for /owners/fred, the value of ownerId is fred.
URI模板" /owners/{ownerId}`"指定变量名为`ownerId。当控制器处理请求,ownerId的值被根据URI适当的部分设置。例如,当一个请求来自/owners/fred,值就是fred。
[Tip]
提示
To process the @PathVariable annotation, Spring MVC needs to find the matching URI template variable by name. You can specify it in the annotation:
为了处理@PathVariable注解,spring的mvc需要找到URI模板中变量的名字。你可以在注解中指定:
@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
// implementation omitted
}
Or if the URI template variable name matches the method argument name you can omit that detail. As long as your code is compiled with debugging information or the -parameters compiler flag on Java 8, Spring MVC will match the method argument name to the URI template variable name:
或者如果URI模板变量名匹配方法参数名你可以省略细节。如果你的代码使用调试信息来编译通过java8,spring的mvc将匹配方法参数名对于URI模板的变量名:
@GetMapping("/owners/{ownerId}")
public String findOwner(@PathVariable String ownerId, Model model) {
// implementation omitted
}
A method can have any number of @PathVariable annotations:
一个方法可以用任意数量个@PathVariable注解:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
Pet pet = owner.getPet(petId);
model.addAttribute("pet", pet);
return "displayPet";
}
When a @PathVariable annotation is used on a Map
当一个@PathVariable注解被使用在一个Map
A URI template can be assembled from type and method level @RequestMapping annotations. As a result the findPet() method can be invoked with a URL such as /owners/42/pets/21.
一个URI模板可以装配类型和方法级别的@RequestMapping注解。由于findPet方法的结果可以是一个URL类似于/owners/42/pets/21。
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping("/pets/{petId}")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
A @PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. You can also register support for parsing additional data types. See the section called “Method Parameters And Type Conversion” and the section called “Customizing WebDataBinder initialization”.
一个@PathVariable参数可以是任意简单的类型例如int、long、Date等等。spring自动将转换相应的类型或抛出类型匹配错误如果转换失败的话。你也可以注册支持解析额外的数据类型。见章节“方法参数和类型转换”和章节“自定义WebDataBinder初始化”。
URI Template Patterns with Regular Expressions
URI模板模式使用正则表达式
Sometimes you need more precision in defining URI template variables. Consider the URL "/spring-web/spring-web-3.0.5.jar". How do you break it down into multiple parts?
有时你需要更精确的定义URI模板变量。考虑URL为"/spring-web/spring-web-3.0.5.jar"。你如何将其进行分解?
The @RequestMapping annotation supports the use of regular expressions in URI template variables. The syntax is {varName:regex} where the first part defines the variable name and the second - the regular expression. For example:
@RequestMapping注解支持使用正则表达式在URI模板变量。语法是{varName:regex}当第一部分定义变量名并且第二部分用横杠来区分正则表达式。例如:
@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String extension) {
// ...
}
Path Patterns
路径模式
In addition to URI templates, the @RequestMapping annotation and all composed @RequestMapping variants also support Ant-style path patterns (for example, /myPath/*.do). A combination of URI template variables and Ant-style globs is also supported (e.g. /owners/*/pets/{petId}).
此外对于URI模板,@RequestMapping注解和所有组合@RequestMapping变量支持ant风格的路径模式(例如/myPath/*.do)。一个URI模式的组合和ant风格也是支持的(例如/owners/*/pets/{petId})。
Path Pattern Comparison
路径模型比较
When a URL matches multiple patterns, a sort is used to find the most specific match.
当一个URL匹配多个路径模式时,在使用时会选择最匹配的。
A pattern with a lower count of URI variables and wild cards is considered more specific. For example /hotels/{hotel}/* has 1 URI variable and 1 wild card and is considered more specific than /hotels/{hotel}/** which as 1 URI variable and 2 wild cards.
一个模式有最少的URI变量和最广泛的考虑指定。例如 /hotels/{hotel}/* 中有一个URI的变量和一个通配符并且比/hotels/{hotel}/** 中的一个URI变量和两个通配符更有指定性。
If two patterns have the same count, the one that is longer is considered more specific. For example /foo/bar* is longer and considered more specific than /foo/*.
如果两个模式有相同的计数,其中一个比考虑更加指定。例如/foo/bar*就比/foo/*更加具体。
When two patterns have the same count and length, the pattern with fewer wild cards is considered more specific. For example /hotels/{hotel} is more specific than /hotels/*.
当两个模式有相同的计数和长度,模式会匹配最少的通配符。例如/hotels/{hotel}就比/hotels/*更加具体。
There are also some additional special rules:
还有两条额外指定的规则:
The default mapping pattern /** is less specific than any other pattern. For example /api/{a}/{b}/{c} is more specific.
默认的匹配模式/**是比其他模式更加没有具体。例如/api/{a}/{b}/{c}是比较具体的。
A prefix pattern such as /public/** is less specific than any other pattern that doesn’t contain double wildcards. For example /public/path3/{a}/{b}/{c} is more specific.
一个前缀模式例如/public/**就没有其他的模式具体并且没有包含两个通配符。例如/public/path3/{a}/{b}/{c}就更加具体。
For the full details see AntPatternComparator in AntPathMatcher. Note that the PathMatcher can be customized (see Section 22.16.11, “Path Matching” in the section on configuring Spring MVC).
参考AntPathMatcher中AntPatternComparator的更多细节。注意PathMatcher可以被自定义(见章节22.16.11,“模式匹配”在配置spring的mvc章节中)。
Path Patterns with Placeholders
带有占位符的路径模式
Patterns in @RequestMapping annotations support ${…} placeholders against local properties and/or system properties and environment variables. This may be useful in cases where the path a controller is mapped to may need to be customized through configuration. For more information on placeholders, see the javadocs of the PropertyPlaceholderConfigurer class.
在@RequestMapping注解中的模式支持${…}的占位符对于本地属性和/或系统属性和环境变量。这在有些情况下是有用的当一个控制器的路径匹配可能需要通过配置来实现自定义。对于更多通配符信息,见PropertyPlaceholderConfigurer类的javadocs。
Suffix Pattern Matching
后缀模式匹配
By default Spring MVC performs ".*" suffix pattern matching so that a controller mapped to /person is also implicitly mapped to /person.*. This makes it easy to request different representations of a resource through the URL path (e.g. /person.pdf, /person.xml).
默认spring的mvc提供了".*"的模式匹配因此一个控制匹配/person也会匹配/person.*。这会导致简单的请求不同的资源通过URL的路径(例如, /person.pdf、/person.xml)。
Suffix pattern matching can be turned off or restricted to a set of path extensions explicitly registered for content negotiation purposes. This is generally recommended to minimize ambiguity with common request mappings such as /person/{id} where a dot might not represent a file extension, e.g. /person/[email protected] vs /person/[email protected]. Furthermore as explained in the note below suffix pattern matching as well as content negotiation may be used in some circumstances to attempt malicious attacks and there are good reasons to restrict them meaningfully.
后缀模式匹配可以被关闭或明确指定限制于一些路径的扩展为了内容的处理。通常建议最小化冲突当使用相同的请求匹配例如/person/{id}当一个点不是代表一个文件的扩展,例如,/person/[email protected]和/person/[email protected]。更多文档的解释在后缀匹配和内容的处理可能被用在一些情况试图恶意攻击和有好的理由来进行有意义的限制。
See Section 22.16.11, “Path Matching” for suffix pattern matching configuration and also Section 22.16.6, “Content Negotiation” for content negotiation configuration.
见章节22.16.11,“路径匹配”对于后缀模式匹配配置和章节22.16.6,“内容协商”对于内容的处理配置。
Suffix Pattern Matching and RFD
后缀模式匹配和RFD
Reflected file download (RFD) attack was first described in a paper by Trustwave in 2014. The attack is similar to XSS in that it relies on input (e.g. query parameter, URI variable) being reflected in the response. However instead of inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a download and treating the response as an executable script if double-clicked based on the file extension (e.g. .bat, .cmd).
反射文件下载(RFD)攻击首先被Trustwave在2014年描述在论文中。这个攻击和XSS相似并且依赖于输入(例如,查询参数,URI变量)被反射在响应中。然而替代插入JavaScript到HTML中,一个RFD攻击依赖于浏览器打开执行一个下载并且将响应作为一个可执行脚本来处理如果双击基于文件系统(例如,bat或cmd)。
In Spring MVC @ResponseBody and ResponseEntity methods are at risk because they can render different content types which clients can request including via URL path extensions. Note however that neither disabling suffix pattern matching nor disabling the use of path extensions for content negotiation purposes alone are effective at preventing RFD attacks.
在spring的mvc中的@ResponseBody和ResponseEntity方法在一定的情况因为他可以处理不同的内容类型根据客户端的请求包括通过一个URL路径的扩展。注意然而关闭后缀匹配不会关闭使用路径扩展对于内容除了的目录并且有效的应对了RFD的攻击。
For comprehensive protection against RFD, prior to rendering the response body Spring MVC adds a Content-Disposition:inline;filename=f.txt header to suggest a fixed and safe download file filename. This is done only if the URL path contains a file extension that is neither whitelisted nor explicitly registered for content negotiation purposes. However it may potentially have side effects when URLs are typed directly into a browser.
对于比较复杂的RFD保护,为了返回响应体spring的mvc添加了一个Content-Disposition:inline;filename=f.txt头来建议一个固定和安全的下载文件名。只有当URL路径包含一个文件扩展名或指定白名单注册对于内容的处理。然而他可能潜在有一定的影响当URL通常直接指向浏览器。
Many common path extensions are whitelisted by default. Furthermore REST API calls are typically not meant to be used as URLs directly in browsers. Nevertheless applications that use custom HttpMessageConverter implementations can explicitly register file extensions for content negotiation and the Content-Disposition header will not be added for such extensions. See Section 22.16.6, “Content Negotiation”.
许多一般的路径扩展默认是在白名单中的。更多REST的API调用通常不会因为着被使用作为URL在浏览器中。除非应用使用自定义的HttpMessageConverter实现可以明确指定注册文件扩展对于内容除了和Content-Disposition的头将不会被添加到这样的扩展中。见章节22.16.6,“内容协商”。
[Note]
注意
This was originally introduced as part of work for CVE-2015-5211. Below are additional recommendations from the report:
最初引入这一部分是为了CVE-2015-5211。下面是对于报告的额外的建议。
Encode rather than escape JSON responses. This is also an OWASP XSS recommendation. For an example of how to do that with Spring see spring-jackson-owasp.
编码而不是逃开JSON返回。这也是一种OWASP XSS的建议。对于一个如何使用的例子对于spring见spring-jackson-owasp。
Configure suffix pattern matching to be turned off or restricted to explicitly registered suffixes only.
配置后缀模式匹配被关闭或只严格指定后缀注册。
Configure content negotiation with the properties "useJaf" and "ignoreUnknownPathExtensions" set to false which would result in a 406 response for URLs with unknown extensions. Note however that this may not be an option if URLs are naturally expected to have a dot towards the end.
配置内容协商使用属性"useJaf"和"ignoreUnknownPathExtensions"设置为false将导致406返回对于URL由于未知的扩展。注意然而这不会是一种选项如果URL是被指定有一个点在最后。
Add X-Content-Type-Options: nosniff header to responses. Spring Security 4 does this by default.
添加X-Content-Type-Options:响应中的nosniff头。spring security 4默认是这么做的。
Matrix Variables
矩阵变量
The URI specification RFC 3986 defines the possibility of including name-value pairs within path segments. There is no specific term used in the spec. The general "URI path parameters" could be applied although the more unique "Matrix URIs", originating from an old post by Tim Berners-Lee, is also frequently used and fairly well known. Within Spring MVC these are referred to as matrix variables.
URI指定RFC3986定义了包含name-value对和路径片段的可能。没有指定成对使用在特定的情况。通常“URL路径参数”可以应用尽管有更加唯一的“矩阵URI”,来自Tim Berners-Lee提出,也很方便使用为人所知。在spring的mvc中他们引用了矩阵变量。
Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon). For example: "/cars;color=red;year=2012". Multiple values may be either "," (comma) separated "color=red,green,blue" or the variable name may be repeated "color=red;color=green;color=blue".
矩阵变量可以出现在任何路径段中,每个矩阵变量使用一个分号分隔。例如:"/cars;color=red;year=2012"。多个值使用逗号分隔"color=red,green,blue"或变量名可以重复"color=red;color=green;color=blue"。
If a URL is expected to contain matrix variables, the request mapping pattern must represent them with a URI template. This ensures the request can be matched correctly regardless of whether matrix variables are present or not and in what order they are provided.
如果一个URL被期望包含矩阵变量,请求匹配模式可以代表使用一个URI模板。这保证了请求可以被正确匹配不管矩阵变量是否代表他们被提供的顺序。
Below is an example of extracting the matrix variable "q":
下面一个例如是扩展了矩阵变量“q”:
// GET /pets/42;q=11;r=22
@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {
// petId == 42
// q == 11
}
Since all path segments may contain matrix variables, in some cases you need to be more specific to identify where the variable is expected to be:
所有的变量段可能包含矩阵变量,在一些情况你需要明确指定当你期望如下的时候:
// 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
}
A matrix variable may be defined as optional and a default value specified:
一个矩阵变量可以被定义作为一个选项和一个默认值:
// GET /pets/42
@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
// q == 1
}
All matrix variables may be obtained in a Map:
所有的矩阵变量可以从一个map中获取:
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
@MatrixVariable MultiValueMap
@MatrixVariable(pathVar="petId"") MultiValueMap
// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
// petMatrixVars: ["q" : 11, "s" : 23]
}
Note that to enable the use of matrix variables, you must set the removeSemicolonContent property of RequestMappingHandlerMapping to false. By default it is set to true.
注意确保使用矩阵变量,你必须设置RequestMappingHandlerMapping中的removeSemicolonContent属性为false。默认他是true的。
[Tip]
提示
The MVC Java config and the MVC namespace both provide options for enabling the use of matrix variables.
mvc的java配置和mvc命名空间提供了选项来允许使用矩阵变量。
If you are using Java config, The Advanced Customizations with MVC Java Config section describes how the RequestMappingHandlerMapping can be customized.
如果你使用java配置,mvc的java配置中的高级自定义描述了RequestMappingHandlerMapping是如何被自定义的。
In the MVC namespace, the
在mvc的命名空间,
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
Consumable Media Types
处理的媒体类型
You can narrow the primary mapping by specifying a list of consumable media types. The request will be matched only if the Content-Type request header matches the specified media type. For example:
你可以缩小主要的匹配通过指定一个列表对于处理的媒体类型。请求将被匹配只有当Content-Type请求头匹配指定的媒体类型。例如:
@PostMapping(path = "/pets", consumes = "application/json")
public void addPet(@RequestBody Pet pet, Model model) {
// implementation omitted
}
Consumable media type expressions can also be negated as in !text/plain to match to all requests other than those with Content-Type of text/plain. Also consider using constants provided in MediaType such as APPLICATION_JSON_VALUE and APPLICATION_JSON_UTF8_VALUE.
处理的媒体类型表达式也可以使用否定的形式例如!text/plain来匹配所有的请求中除了text/plain的Content-Type的类型。也要考虑指定的数量对于媒体类型例如APPLICATION_JSON_VALUE和APPLICATION_JSON_UTF8_VALUE。
[Tip]
提示
The consumes condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level consumable types override rather than extend type-level consumable types.
处理条件被支持对于类型并且在方法级别。不像其他的条件,当使用在类型级别、方法级别的处理类型会覆盖类型级别的处理类型。
Producible Media Types
可扩展的媒体类型
You can narrow the primary mapping by specifying a list of producible media types. The request will be matched only if the Accept request header matches one of these values. Furthermore, use of the produces condition ensures the actual content type used to generate the response respects the media types specified in the produces condition. For example:
你可以缩小主要的匹配通过指定一个可扩展的媒体类型列表。请求将被匹配只有Accept的请求头匹配这些值。此外,使用可扩展的田间保证实际的内容类型使用通常生成相应代表媒体类型指定在生产条件。例如:
@GetMapping(path = "/pets/{petId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
// implementation omitted
}
[Note]
注意
Be aware that the media type specified in the produces condition can also optionally specify a character set. For example, in the code snippet above we specify the same media type than the default one configured in MappingJackson2HttpMessageConverter, including the UTF-8 charset.
意识到媒体类型定义在生产条件也可以选择指定一个字符集。例如,在上面的代码片段我们指定了相同的媒体类型而不是默认配置在MappingJackson2HttpMessageConverter中的,包括UTF-8字符集。
Just like with consumes, producible media type expressions can be negated as in !text/plain to match to all requests other than those with an Accept header value of text/plain. Also consider using constants provided in MediaType such as APPLICATION_JSON_VALUE and APPLICATION_JSON_UTF8_VALUE.
就像耗尽一样,生产媒体类型表达式可以忽略如!text/plain来匹配所有的请求除了Accept头值是text/plain。也考虑使用常量提供在MediaType中例如APPLICATION_JSON_VALUE和APPLICATION_JSON_UTF8_VALUE。
[Tip]
提示
The produces condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level producible types override rather than extend type-level producible types.
生产条件被支持在类型和方法级别。不像其他的条件,当使用在类型级别、方法级别生产类型覆盖而不是扩展类型级别的生产类型。
Request Parameters and Header Values
请求参数和头信息
You can narrow request matching through request parameter conditions such as "myParam", "!myParam", or "myParam=myValue". The first two test for request parameter presence/absence and the third for a specific parameter value. Here is an example with a request parameter value condition:
你可以缩小请求的匹配通过请求参数条件例如"myParam"、"!myParam"或"myParam=myValue"。首先的两个测试对于请求参数的有或者没有并且第三个用于指定参数值。这是一个例子展示了使用请求参数值作为条件:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
The same can be done to test for request header presence/absence or to match based on a specific request header value:
相同的也可以用于请求头有或者没有或者匹配指定的请求头参数值:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@GetMapping(path = "/pets", headers = "myHeader=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
[Tip]
提示
Although you can match to Content-Type and Accept header values using media type wild cards (for example "content-type=text/*" will match to "text/plain" and "text/html"), it is recommended to use the consumes and produces conditions respectively instead. They are intended specifically for that purpose.
尽管你可以匹配Content-Type和Accept的头信息使用媒体类型通配符(例如"content-type=text/*"将匹配"text/plain"和"text/html"),他要求使用消费和过程管理条件作为明显的替代。他们试图指定为了实现这种目的。
HTTP HEAD and HTTP OPTIONS
@RequestMapping methods mapped to "GET" are also implicitly mapped to "HEAD", i.e. there is no need to have "HEAD" explicitly declared. An HTTP HEAD request is processed as if it were an HTTP GET except instead of writing the body only the number of bytes are counted and the "Content-Length" header set.
@RequestMapping方法匹配"GET"也可以明确指定匹配"HEAD",例如不需要直接定义"HEAD"。一个http头请求被处理如果他是一个http的get而不是只有内容和"Content-Length"的头信息。
@RequestMapping methods have built-in support for HTTP OPTIONS. By default an HTTP OPTIONS request is handled by setting the "Allow" response header to the HTTP methods explicitly declared on all @RequestMapping methods with matching URL patterns. When no HTTP methods are explicitly declared the "Allow" header is set to "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS". Ideally always declare the HTTP method(s) that an @RequestMapping method is intended to handle, or alternatively use one of the dedicated composed @RequestMapping variants (see the section called “Composed @RequestMapping Variants”).
@RequestMapping方法有内置的对于http选项的支持。默认一个http选项请求被处理通过设置"Allow"响应头对于http方法明确定义对于所有的@RequestMapping方法使用匹配URL模式。当没有http方法被明确指定通过"Allow"头设置为"GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"。理想是定义http方法使得一个@RequestMapping方法可以去处理或使用其中的一个组合@RequestMapping变量(参见章节“组合@RequestMapping变量”)
Although not necessary an @RequestMapping method can be mapped to and handle either HTTP HEAD or HTTP OPTIONS, or both.
尽管没有必要一个@RequestMapping方法可以匹配http头或http选项或两者都匹配。
22.3.3 Defining @RequestMapping handler methods
定义@RequestMapping处理方法
@RequestMapping handler methods can have very flexible signatures. The supported method arguments and return values are described in the following section. Most arguments can be used in arbitrary order with the only exception being BindingResult arguments. This is described in the next section.
@RequestMapping处理方法可有多个方便的签名。支持方法参数和返回值被描述在后面的章节。大部分参数可以被使用以任意的顺序除了BindingResult参数。这会在下一章节中描述。
[Note]
注意
Spring 3.1 introduced a new set of support classes for @RequestMapping methods called RequestMappingHandlerMapping and RequestMappingHandlerAdapter respectively. They are recommended for use and even required to take advantage of new features in Spring MVC 3.1 and going forward. The new support classes are enabled by default from the MVC namespace and with use of the MVC Java config but must be configured explicitly if using neither.
spring3.1引入了一个新的集合支持类对于@RequestMapping方法名字为RequestMappingHandlerMapping和RequestMappingHandlerAdapter。他们被推荐使用当你需要spring的mvc3.1中的新的功能时。新的支持类默认是开启的并且作为mvc命名空间的默认并且使用mvc的java配置但是必须明确指定是否使用。
Supported method argument types
支持方法参数类型
The following are the supported method arguments:
下面是支持的方法参数:
Request or response objects (Servlet API). Choose any specific request or response type, for example ServletRequest or HttpServletRequest.
请求或响应object(Servlet API)。选择任何请求或响应类型,例如ServletRequest或HttpServletRequest。
Session object (Servlet API): of type HttpSession. An argument of this type enforces the presence of a corresponding session. As a consequence, such an argument is never null.
会话object(Servlet API):类型是HttpSession。一个这个类型的参数强制相应的会话出现。因此,这样的参数不会是null。
[Note]
注意
Session access may not be thread-safe, in particular in a Servlet environment. Consider setting the RequestMappingHandlerAdapter's "synchronizeOnSession" flag to "true" if multiple requests are allowed to access a session concurrently.
会话访问可能不是线程安全的,特别是在Servlet环境中。考虑设置RequestMappingHandlerAdapter的"synchronizeOnSession"标识为"true"如果多个请求被允许同步访问一个会话。
org.springframework.web.context.request.WebRequest or org.springframework.web.context.request.NativeWebRequest. Allows for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API.
允许一般的请求参数访问包括请求/会话属性访问,而不需要绑定本地的Servlet/Portlet的API。
java.util.Locale for the current request locale, determined by the most specific locale resolver available, in effect, the configured LocaleResolver / LocaleContextResolver in an MVC environment.
java.util.Locale用于当前的请求,通过大部分本地解析被决定,实际上,配置LocaleResolver / LocaleContextResolver在mvc的环境。
java.util.TimeZone (Java 6+) / java.time.ZoneId (on Java 8) for the time zone associated with the current request, as determined by a LocaleContextResolver.
java.util.TimeZone (Java 6+) / java.time.ZoneId (on Java 8)对于时区和当前的请求有关,通过LocaleContextResolver来决定。
java.io.InputStream / java.io.Reader for access to the request’s content. This value is the raw InputStream/Reader as exposed by the Servlet API.
java.io.InputStream / java.io.Reader对于请求内容。这个只是InputStream/Reader通过Servlet的API暴露出来。
java.io.OutputStream / java.io.Writer for generating the response’s content. This value is the raw OutputStream/Writer as exposed by the Servlet API.
java.io.OutputStream / java.io.Writer用于生成响应的内容。这个值是OutputStream/Writer通过Servlet的API暴露出来。
org.springframework.http.HttpMethod for the HTTP request method.
org.springframework.http.HttpMethod用于http请求方法。
java.security.Principal containing the currently authenticated user.
java.security.Principal包含当前的已经认证的用户。
@PathVariable annotated parameters for access to URI template variables. See the section called “URI Template Patterns”.
@PathVariable注解的参数用于访问uri模型变量。见章节“URI模板模式”。
@MatrixVariable annotated parameters for access to name-value pairs located in URI path segments. See the section called “Matrix Variables”.
@MatrixVariable注解的参数用于访问键值对在uri的路径中。见章节“矩阵变量”。
@RequestParam annotated parameters for access to specific Servlet request parameters. Parameter values are converted to the declared method argument type. See the section called “Binding request parameters to method parameters with @RequestParam”.
@RequestParam注解参数用于访问指定的Servlet请求参数。参数值可以转化为指定的方法参数类型。见章节“绑定请求参数对于方法参数通过@RequestParam”。
@RequestHeader annotated parameters for access to specific Servlet request HTTP headers. Parameter values are converted to the declared method argument type. See the section called “Mapping request header attributes with the @RequestHeader annotation”.
@RequestHeader注解参数用于访问指定的Servlet请求的http头。参数值转化为指定的方法参数类型。见章节“匹配请求头属性通过@RequestHeader注解”。
@RequestBody annotated parameters for access to the HTTP request body. Parameter values are converted to the declared method argument type using HttpMessageConverters. See the section called “Mapping the request body with the @RequestBody annotation”.
@RequestBody注解参数用于访问http请求体。参数值被转换为指定方法参数类型使用HttpMessageConverters。见章节“匹配请求体通过@RequestBody注解”。
@RequestPart annotated parameters for access to the content of a "multipart/form-data" request part. See Section 22.10.5, “Handling a file upload request from programmatic clients” and Section 22.10, “Spring’s multipart (file upload) support”.
@RequestPart注解参数用于访问"multipart/form-data"的请求部分。见章节22.10.5,“处理文件上传请求来自客户端”和章节22.10,“spring对不同的部分(文件上传)的支持”。
@SessionAttribute annotated parameters for access to existing, permanent session attributes (e.g. user authentication object) as opposed to model attributes temporarily stored in the session as part of a controller workflow via @SessionAttributes.
@SessionAttribute注解参数用于访问已经存在、持久的会话属性(例如,用户的权限object)作为模型属性临时存储在会话中作为控制器流的一部分通过@SessionAttributes。
@RequestAttribute annotated parameters for access to request attributes.
@RequestAttribute注解参数用于访问请求属性。
HttpEntity> parameters for access to the Servlet request HTTP headers and contents. The request stream will be converted to the entity body using HttpMessageConverters. See the section called “Using HttpEntity”.
HttpEntity>参数用于访问Servlet请求http头和内容。请求流将被转换为实体body通过使用HttpMessageConverters。见章节“使用HttpEntity”。
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap for enriching the implicit model that is exposed to the web view.
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap用于丰富实现模型定义在web视图中。
org.springframework.web.servlet.mvc.support.RedirectAttributes to specify the exact set of attributes to use in case of a redirect and also to add flash attributes (attributes stored temporarily on the server-side to make them available to the request after the redirect). See the section called “Passing Data To the Redirect Target” and Section 22.6, “Using flash attributes”.
org.springframework.web.servlet.mvc.support.RedirectAttributes为了指定属性集用于转发并且也可以添加闪存属性(临时存储属性在服务端来使得请求在转发之后)。将章节“传递数据给转发目标”和章节22.6,“使用闪存属性”。
Command or form objects to bind request parameters to bean properties (via setters) or directly to fields, with customizable type conversion, depending on @InitBinder methods and/or the HandlerAdapter configuration. See the webBindingInitializer property on RequestMappingHandlerAdapter. Such command objects along with their validation results will be exposed as model attributes by default, using the command class name - e.g. model attribute "orderAddress" for a command object of type "some.package.OrderAddress". The ModelAttribute annotation can be used on a method argument to customize the model attribute name used.
命令或用于object绑定请求参数对于bean属性(通过set方法)或直接定义在field使用自定义的类型转换,依赖于@InitBinder方法或HandlerAdapter的配置。见webBindingInitializer属性对于RequestMappingHandlerAdapter。这样的命令object有他们的验证结果将被默认暴露给模型属性,使用命令类名字例如模型属性"orderAddress"对于一个命令object的类型。
org.springframework.validation.Errors / org.springframework.validation.BindingResult validation results for a preceding command or form object (the immediately preceding method argument).
org.springframework.validation.Errors / org.springframework.validation.BindingResult验证结果对于之前的命令或form的object(直接处理方法参数)。
org.springframework.web.bind.support.SessionStatus status handle for marking form processing as complete, which triggers the cleanup of session attributes that have been indicated by the @SessionAttributes annotation at the handler type level.
org.springframework.web.bind.support.SessionStatus状态处理标记处理过程如果完成了,将引起会话属性的清理并且通过@SessionAttributes表明在处理器类型级别。
org.springframework.web.util.UriComponentsBuilder a builder for preparing a URL relative to the current request’s host, port, scheme, context path, and the literal part of the servlet mapping.
org.springframework.web.util.UriComponentsBuilder一个构建器用于准备url相对于当前的请求主机、端口、schema、上下文路径和Servlet匹配的迭代。
The Errors or BindingResult parameters have to follow the model object that is being bound immediately as the method signature might have more than one model object and Spring will create a separate BindingResult instance for each of them so the following sample won’t work:
错误或BindingResult参数遵循下面的模型object可以直接绑定作为方法签名而不是模型object和spring将创建一个分别的BindingResult实例对于其中的每一个因此下面的例子不可能工作:
Invalid ordering of BindingResult and @ModelAttribute.
错误的BindingResult和@ModelAttribute的顺序
@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, Model model, BindingResult result) { ... }
Note, that there is a Model parameter in between Pet and BindingResult. To get this working you have to reorder the parameters as follows:
注意,这是一个Model参数在Pet和BindingResult之间。为了使得其工作你不得不记录参数如下:
@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }
[Note]
注意
JDK 1.8’s java.util.Optional is supported as a method parameter type with annotations that have a required attribute (e.g. @RequestParam, @RequestHeader, etc. The use of java.util.Optional in those cases is equivalent to having required=false.
JDK 1.8的java.util.Optional支持作为方法参数类型通过注解有一个必须属性(例如,@RequestParam、@RequestHeader等等。使用java.util.Optional在这种情况和设置required=false相同)。
Supported method return types
支持方法的返回类型
The following are the supported return types:
下面是支持的返回类型:
A ModelAndView object, with the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
ModelAndView的object,有模型来增强命令object和@ModelAttribute的结果注解引用了数据访问方法。
A Model object, with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
Model的object,有视图名明确定义通过@RequestToViewNameTranslator和模型来增强命令object和@ModelAttribute的结果引用了数据访问方法。
A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator and the model implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
Map的object用于暴露一个模型使用明确的视图名定义通过RequestToViewNameTranslator并且模型来增强命令object和@ModelAttribute的结果引用了数据访问方法。
A View object, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
视图object,有模型决定通过命令object和@ModelAttribute注解引用数据访问方法。处理器方法也可以编程来增强通过定义一个模型参数(见上面)。
A String value that is interpreted as the logical view name, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
字符串被理解为逻辑视图名,模型明确决定通过命令object和@ModelAttribute注解引用数据访问方法。处理器方法也可以编程来增强通过定义一个模型参数(见上面)。
void if the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse / HttpServletResponse for that purpose) or if the view name is supposed to be implicitly determined through a RequestToViewNameTranslator (not declaring a response argument in the handler method signature).
void如果方法处理的响应本身(通过直接写请求上下文,定义一个参数类型ServletResponse / HttpServletResponse为目的)或如果视图名已经明确通过RequestToViewNameTranslator指定(没有定义一个响应参数在处理器方法签名中)。
If the method is annotated with @ResponseBody, the return type is written to the response HTTP body. The return value will be converted to the declared method argument type using HttpMessageConverters. See the section called “Mapping the response body with the @ResponseBody annotation”.
如果方法注解使用@ResponseBody,返回类型将写到http体中。返回值将被转换为定义的方法参数类型通过使用HttpMessageConverters。见章节名字为“匹配响应体使用@ResponseBody注解”。
An HttpEntity> or ResponseEntity> object to provide access to the Servlet response HTTP headers and contents. The entity body will be converted to the response stream using HttpMessageConverters. See the section called “Using HttpEntity”.
HttpEntity>或ResponseEntity>的object用于提供访问对于Servlet响应http头和内容。实体将被转换为响应流使用HttpMessageConverters。见章节“使用HttpEntity”。
An HttpHeaders object to return a response with no body.
HttpHeaders的object用于返回值当没有响应体的时候。
A Callable> can be returned when the application wants to produce the return value asynchronously in a thread managed by Spring MVC.
Callable>可以被返回当应用希望异步处理一个返回值在线程中并且由spring的mvc来管理。
A DeferredResult> can be returned when the application wants to produce the return value from a thread of its own choosing.
DeferredResult>可以被返回当应用希望处理一个返回值来自他自己选择的线程中时。
A ListenableFuture> can be returned when the application wants to produce the return value from a thread of its own choosing.
ListenableFuture>可以被返回当应用希望处理一个返回值来自他自己选择的线程中时。
A ResponseBodyEmitter can be returned to write multiple objects to the response asynchronously; also supported as the body within a ResponseEntity.
ResponseBodyEmitter可以被返回用于异步写多个object,并且支持在ResponseEntity定义响应体。
An SseEmitter can be returned to write Server-Sent Events to the response asynchronously; also supported as the body within a ResponseEntity.
SseEmitter可以被返回用于异步写服务器发送时间对于响应并且支持在ResponseEntity定义响应体。
A StreamingResponseBody can be returned to write to the response OutputStream asynchronously; also supported as the body within a ResponseEntity.
StreamingResponseBody可以被返回当异步写响应输出流时,也支持在ResponseEntity定义响应体。
Any other return type is considered to be a single model attribute to be exposed to the view, using the attribute name specified through @ModelAttribute at the method level (or the default attribute name based on the return type class name). The model is implicitly enriched with command objects and the results of @ModelAttribute annotated reference data accessor methods.
另外的返回类型将被考虑一个单独的模型属性用于扩展视图,使用属性名通过@ModelAttribute在方法级别定义(或默认属性名基于返回类型类名)。模型是直接增强使用命令object并且@ModelAttribute注解的值应用数据访问方法。
Binding request parameters to method parameters with @RequestParam
绑定请求参数对于方法参数使用@RequestParam
Use the @RequestParam annotation to bind request parameters to a method parameter in your controller.
使用@RequestParam注解来绑定请求参数对于方法参数在你的控制器中。
The following code snippet shows the usage:
下面的代码片段展示了使用方法:
@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
// ...
@GetMapping
public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...
}
Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting @RequestParam's required attribute to false (e.g., @RequestParam(name="id", required=false)).
参数使用了这个注解默认被要求,但是你指定一个参数是可选的通过设置@RequestParam的required属性为false(例如@RequestParam(name="id", required=false))。
Type conversion is applied automatically if the target method parameter type is not String. See the section called “Method Parameters And Type Conversion”.
类型转换是自动被使用的如果目标方法参数类型不是字符串。见章节“方法参数和类型转换”。
When an @RequestParam annotation is used on a Map
当@RequestParam注解被使用于Map
Mapping the request body with the @RequestBody annotation
匹配请求体通过@RequestBody注解
The @RequestBody method parameter annotation indicates that a method parameter should be bound to the value of the HTTP request body. For example:
@RequestBody方法参数注解指示了一个方法参数应当被绑定http请求体的值。例如:
@PutMapping("/something")
public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}
You convert the request body to the method argument by using an HttpMessageConverter. HttpMessageConverter is responsible for converting from the HTTP request message to an object and converting from an object to the HTTP response body. The RequestMappingHandlerAdapter supports the @RequestBody annotation with the following default HttpMessageConverters:
你转换请求体为方法参数通过使用HttpMessageConverter。HttpMessageConverter是用于将http请求信息转换为一个object并转换一个object为http响应体。RequestMappingHandlerAdapter支持@RequestBody注解使用下面默认的HttpMessageConverters。
ByteArrayHttpMessageConverter converts byte arrays.
ByteArrayHttpMessageConverter转换字节数组。
StringHttpMessageConverter converts strings.
StringHttpMessageConverter转换字符串。
FormHttpMessageConverter converts form data to/from a MultiValueMap
FormHttpMessageConverter转换数据和MultiValueMap
SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.
SourceHttpMessageConverter转换javax.xml.transform.Source。
For more information on these converters, see Message Converters. Also note that if using the MVC namespace or the MVC Java config, a wider range of message converters are registered by default. See Section 22.16.1, “Enabling the MVC Java Config or the MVC XML Namespace” for more information.
关于这些转化器的更多信息,见消息转换。也注意如果使用mvc命名空间或mvc的java配置,一个大范围的信息转换被默认注册。见章节22.16.1,“允许MVC的java配置或mvc的xml命名空间”来了解更多信息。
If you intend to read and write XML, you will need to configure the MarshallingHttpMessageConverter with a specific Marshaller and an Unmarshaller implementation from the org.springframework.oxm package. The example below shows how to do that directly in your configuration but if your application is configured through the MVC namespace or the MVC Java config see Section 22.16.1, “Enabling the MVC Java Config or the MVC XML Namespace” instead.
如果你试图读和写xml,你将需要配置MarshallingHttpMessageConverter使用指定的Marshaller和Unmarshaller实现来自org.springframework.oxm包。下面的例子展示了如何直接在你的配置但是如果你的应用被配置通过mvc命名空间或mvc的java的配置见章节22.16.1,“允许mvc的java配置或mvc的xml命名空间”作为补充。
class="org.springframework.http.converter.StringHttpMessageConverter"/> class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> An @RequestBody method parameter can be annotated with @Valid, in which case it will be validated using the configured Validator instance. When using the MVC namespace or the MVC Java config, a JSR-303 validator is configured automatically assuming a JSR-303 implementation is available on the classpath. 一个@RequestBody方法参数可以注解通过@Valid,因此他将确认使用配置的Validator实例。当使用mvc命名空间或mvc的java配置,一个JSR303验证将被自动配置假设jsr303实现可以在classpath中出现。 Just like with @ModelAttribute parameters, an Errors argument can be used to examine the errors. If such an argument is not declared, a MethodArgumentNotValidException will be raised. The exception is handled in the DefaultHandlerExceptionResolver, which sends a 400 error back to the client. 就像使用@ModelAttribute参数,一个错误参数可以被使用来检查错误。如果这样的一个参数没有被定义,MethodArgumentNotValidException会被抛出。这个异常被处理通过DefaultHandlerExceptionResolver,发送一个400错误返回给客户端。 [Note] 注意 Also see Section 22.16.1, “Enabling the MVC Java Config or the MVC XML Namespace” for information on configuring message converters and a validator through the MVC namespace or the MVC Java config. 见章节22.16.1,“允许MVC的java配置或mvc的xml命名空间”来了解更多信息有关配置信息转换和验证通过mvc的命名空间或mvc的java配置。 Mapping the response body with the @ResponseBody annotation 使用@ResponseBody注解来匹配响应体 The @ResponseBody annotation is similar to @RequestBody. This annotation can be placed on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name). For example: @ResponseBody注解和@RequestBody注解类似。这个注解可以修饰一个方法和指定返回类型应当书写通过http响应体(而不是在一个model中或作为一个视图来拦截)。例如: @GetMapping("/something") @ResponseBody public String helloWorld() { return "Hello World"; } The above example will result in the text Hello World being written to the HTTP response stream. 上面的例子将导致在文本的Hello World将被写入到http的响应流中。 As with @RequestBody, Spring converts the returned object to a response body by using an HttpMessageConverter. For more information on these converters, see the previous section and Message Converters. 由于@RequestBody,spring的转换返回的object为响应体通过使用HttpMessageConverter。关于这些转换器的更多信息,见之前的章节和Message Converters。 Creating REST Controllers with the @RestController annotation 创建rest的控制器使用@RestController注解 It’s a very common use case to have Controllers implement a REST API, thus serving only JSON, XML or custom MediaType content. For convenience, instead of annotating all your @RequestMapping methods with @ResponseBody, you can annotate your controller Class with @RestController. 通常使用使用控制器实现一个rest的api,例如json、xml或自定义的MediaType内容。为了方便,代替注解所有你的@RequestMapping方法使用@ResponseBody注解,你可以注解你的控制器类使用@RestController。 @RestController is a stereotype annotation that combines @ResponseBody and @Controller. More than that, it gives more meaning to your Controller and also may carry additional semantics in future releases of the framework. @RestController是一个模板注解组合了@ResponseBody和@Controller。此外,他对于你的控制器给予了更多的含义并且也可以包含额外的语义在未来框架的发布版本中。 As with regular @Controllers, a @RestController may be assisted by @ControllerAdvice or @RestControllerAdvice beans. See the the section called “Advising controllers with @ControllerAdvice and @RestControllerAdvice” section for more details. 由于常规的@Controllers、@RestController可以辅助通过@ControllerAdvice或@RestController的bean。见章节“通知控制器使用@ControllerAdvice和@RestControllerAdvice”来了解更多细节。 Using HttpEntity 使用HttpEntity The HttpEntity is similar to @RequestBody and @ResponseBody. Besides getting access to the request and response body, HttpEntity (and the response-specific subclass ResponseEntity) also allows access to the request and response headers, like so: HttpEntity相似于@RequestBody和@RequestBody。此外获得访问对于请求和响应体,HttpEntity(和指定的响应子类ResponseEntity)也允许访问请求和响应头,例如: @RequestMapping("/something") public ResponseEntity String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader")); byte[] requestBody = requestEntity.getBody(); // do something with request header and body HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("MyResponseHeader", "MyValue"); return new ResponseEntity } The above example gets the value of the MyRequestHeader request header, and reads the body as a byte array. It adds the MyResponseHeader to the response, writes Hello World to the response stream, and sets the response status code to 201 (Created). 上面的例子获得了MyRequestHeader请求头的值,并且读取请求作为一个字节数组。他添加MyResponseHeader到响应中,写入Hello World到响应流中并且设置响应状态码为201(创建)。 As with @RequestBody and @ResponseBody, Spring uses HttpMessageConverter to convert from and to the request and response streams. For more information on these converters, see the previous section and Message Converters. 由于@RequestBody和@ResponseBody,spring使用HttpMessageConverter来转换请求和响应流。关于这些转换器更多的信息见之前的章节和Message Converters。 Using @ModelAttribute on a method 使用@ModelAttribute来修饰方法 The @ModelAttribute annotation can be used on methods or on method arguments. This section explains its usage on methods while the next section explains its usage on method arguments. @ModelAttribute注解可以用于方法上或方法参数上。这一节介绍这种用法在方法上并且下一节将介绍方法参数上的使用。 An @ModelAttribute on a method indicates the purpose of that method is to add one or more model attributes. Such methods support the same argument types as @RequestMapping methods but cannot be mapped directly to requests. Instead @ModelAttribute methods in a controller are invoked before @RequestMapping methods, within the same controller. A couple of examples: 在方法上使用@ModelAttribute指示了这个方法的目的并添加一个或多个模型属性。这样的方法支持相同的参数类型作为@RequestMapping方法但是不能直接匹配请求。代替@ModelAttribute方法在一个控制器中被调用在@RequestMapping方法之前,在相同的控制器中。例如: // Add one attribute // 添加一个属性 // The return value of the method is added to the model under the name "account" // 返回方法值中添加model以名字为account // You can customize the name via @ModelAttribute("myAccount") // 你可以自定义名字通过@ModelAttribute("myAccount") @ModelAttribute public Account addAccount(@RequestParam String number) { return accountManager.findAccount(number); } // Add multiple attributes // 添加多个属性 @ModelAttribute public void populateModel(@RequestParam String number, Model model) { model.addAttribute(accountManager.findAccount(number)); // add more ... } @ModelAttribute methods are used to populate the model with commonly needed attributes for example to fill a drop-down with states or with pet types, or to retrieve a command object like Account in order to use it to represent the data on an HTML form. The latter case is further discussed in the next section. @ModelAttribute方法被使用用于暴露model通常需要属性例如填满drop-down通过状态或pet的类型,或获得一个命令object例如Account用于使用来代表html表单中的数据。后续的例子在下一节中讨论。 Note the two styles of @ModelAttribute methods. In the first, the method adds an attribute implicitly by returning it. In the second, the method accepts a Model and adds any number of model attributes to it. You can choose between the two styles depending on your needs. 注意两个类型的@ModelAttribute方法。首先,这个方法添加属性用于返回。第二,这个方法接收一个Model并添加任意数量的模型参数。你可以选择其中的一个依据你的需要。 A controller can have any number of @ModelAttribute methods. All such methods are invoked before @RequestMapping methods of the same controller. 一个控制器可以有任意数量的@ModelAttribute方法。所有这样的方法被调用在@RequestMapping方法之前对于相同的控制器。 @ModelAttribute methods can also be defined in an @ControllerAdvice-annotated class and such methods apply to many controllers. See the the section called “Advising controllers with @ControllerAdvice and @RestControllerAdvice” section for more details. @ModelAttribute方法也可以定义在@ControllerAdvice-annotated类并且这样的方法应用于多个控制器。见章节“修饰控制器使用@ControllerAdvice和@RestControllerAdvice”来了解更多信息。 [Tip] 提示 What happens when a model attribute name is not explicitly specified? In such cases a default name is assigned to the model attribute based on its type. For example if the method returns an object of type Account, the default name used is "account". You can change that through the value of the @ModelAttribute annotation. If adding attributes directly to the Model, use the appropriate overloaded addAttribute(..) method - i.e., with or without an attribute name. 当一个model属性没有指定时会发生什么?在一些情况一个默认的名字为赋值对于一个model属性根据他的类型。例如若果方法返回一个Account类型的object,默认的name是account。你可以改变通过@ModelAttribute注解。如果直接添加属性给model。如果直接添加属性给model,使用适当的重载的addAttribute方法,使用或不使用属性名。 The @ModelAttribute annotation can be used on @RequestMapping methods as well. In that case the return value of the @RequestMapping method is interpreted as a model attribute rather than as a view name. The view name is then derived based on view name conventions instead, much like for methods returning void — see Section 22.13.3, “The View - RequestToViewNameTranslator”. @ModelAttribute注解可以被使用在@RequestMapping方法上。在这种情况@RequestMapping方法的返回值被拦截作为一个model属性而不是一个视图名。视图名基于视图名转换来处理,就像方法返回void————见章节22.13.3,“视图————RequestToViewNameTranslator”” Using @ModelAttribute on a method argument 在方法参数上使用@ModelAttribute As explained in the previous section @ModelAttribute can be used on methods or on method arguments. This section explains its usage on method arguments. 在之前的章节中解释过@ModelAttribute可以修饰方法或方法参数。这一节将解释他在方法参数上的使用。 An @ModelAttribute on a method argument indicates the argument should be retrieved from the model. If not present in the model, the argument should be instantiated first and then added to the model. Once present in the model, the argument’s fields should be populated from all request parameters that have matching names. This is known as data binding in Spring MVC, a very useful mechanism that saves you from having to parse each form field individually. 在方法参数上使用@ModelAttribute指示参数应当是来自model的。如果没有表现在model中,参数应当被首先实例化并且添加到model中。只要出现model中,参数应当暴露给所有的请求参数有匹配的名字。这个被spring的mvc的参数绑定知道,一个非常有用的策略使得你不用读了的处理每个field。 @PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute Pet pet) { } Given the above example where can the Pet instance come from? There are several options: 给出上面的例子中Pet实例是哪里来的?这里有几个选项: It may already be in the model due to use of @SessionAttributes?—?see the section called “Using @SessionAttributes to store model attributes in the HTTP session between requests”. 他已经在model中由于使用了@SessionAttributes————见章节“使用@SessionAttributes来存储model属性在http的session中在两个请求之间”。 It may already be in the model due to an @ModelAttribute method in the same controller?—?as explained in the previous section. 他已经在model中由于一个@ModelAttribute方法在相同的控制器中————在之前的章节中解释过。 It may be retrieved based on a URI template variable and type converter (explained in more detail below). 他来自基于URI模板变量和类型转换(在后面会进行讲述其中的细节) It may be instantiated using its default constructor. 他可以被实例化使用它的默认构造器。 An @ModelAttribute method is a common way to retrieve an attribute from the database, which may optionally be stored between requests through the use of @SessionAttributes. In some cases it may be convenient to retrieve the attribute by using an URI template variable and a type converter. Here is an example: @ModelAttribute方法是一种通用的方法来获得一个来自数据库的属性,可以选择存储在请求之间尽管使用了@SessionAttributes。在一些情况他可以很方便来获得属性通过使用一个URI模板变量和一个类型转换器。例如: @PutMapping("/accounts/{account}") public String save(@ModelAttribute("account") Account account) { // ... } In this example the name of the model attribute (i.e. "account") matches the name of a URI template variable. If you register Converter 在这个例如中model属性的名字(例如,account)匹配URI模板变量的名字。如果你注册Converter The next step is data binding. The WebDataBinder class matches request parameter names?—?including query string parameters and form fields?—?to model attribute fields by name. Matching fields are populated after type conversion (from String to the target field type) has been applied where necessary. Data binding and validation are covered in Chapter 9, Validation, Data Binding, and Type Conversion. Customizing the data binding process for a controller level is covered in the section called “Customizing WebDataBinder initialization”. 下一步是数据绑定。WebDataBinder类匹配请求参数名————包括查询字符串参数和表单域————对于model属性域通过名字。匹配域被暴露在类型转换之后(来自字符串到目标类型)当需要的时候可以应用。数据绑定和验证在第9章已经有过介绍,验证、数据绑定和类型转换。自定义数据绑定访问对于一个控制器级别在章节中有介绍“自定义WebDataBinder初始化”。 As a result of data binding there may be errors such as missing required fields or type conversion errors. To check for such errors add a BindingResult argument immediately following the @ModelAttribute argument: 由于数据绑定的结果可以有错误例如丢失请求域或类型转换错误。为了检查这样的错误添加一个BindingResult结果直接来自@ModelAttribute参数: @PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { if (result.hasErrors()) { return "petForm"; } // ... } With a BindingResult you can check if errors were found in which case it’s common to render the same form where the errors can be shown with the help of Spring’s 使用BindingResult你可以检查如果错误被发现由于提出了相同的表单并且错误发生可以展示通过spring的 Note that in some cases it may be useful to gain access to an attribute in the model without data binding. For such cases you may inject the Model into the controller or alternatively use the binding flag on the annotation: 注意在一些情况可能有用关于获得访问一个属性在model中而不需要数据绑定。对于这样的情况,你可以将model注入到控制器或选择使用绑定的标识在注解上: @ModelAttribute public AccountForm setUpForm() { return new AccountForm(); } @ModelAttribute public Account findAccount(@PathVariable String accountId) { return accountRepository.findOne(accountId); } @PostMapping("update") public String update(@Valid AccountUpdateForm form, BindingResult result, @ModelAttribute(binding=false) Account account) { // ... } In addition to data binding you can also invoke validation using your own custom validator passing the same BindingResult that was used to record data binding errors. That allows for data binding and validation errors to be accumulated in one place and subsequently reported back to the user: 此外对于数据绑定你也可以调用验证通过使用你自己的自定义验证器来传递相同的BindingResult可以被用于记录数据绑定错误。他允许绑定和验证错误被累计在一个位置并且在后续汇报给用户。 @PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { new PetValidator().validate(pet, result); if (result.hasErrors()) { return "petForm"; } // ... } Or you can have validation invoked automatically by adding the JSR-303 @Valid annotation: 或者你可以验证自动调用通过添加JSR303中的@Valid注解: @PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { if (result.hasErrors()) { return "petForm"; } // ... } See Section 9.8, “Spring Validation” and Chapter 9, Validation, Data Binding, and Type Conversion for details on how to configure and use validation. 见章节9.8,“spring的验证”和第9张,验证、数据绑定和类型转换来了解配置和验证的细节。 Using @SessionAttributes to store model attributes in the HTTP session between requests 使用@SessionAttributes来存储model属性在http的会话中在两个请求之间 The type-level @SessionAttributes annotation declares session attributes used by a specific handler. This will typically list the names of model attributes or types of model attributes which should be transparently stored in the session or some conversational storage, serving as form-backing beans between subsequent requests. 类型级别的@SessionAttributes注解定义的会话属性使用通过一个特定的处理器。这将通常列出model属性的名字或model属性的类型应当被存储在session或一些内容的存储,服务于bean在请求之间。 The following code snippet shows the usage of this annotation, specifying the model attribute name: 下面的代码片段展示了这个注解的使用方式,指定了model属性名: @Controller @RequestMapping("/editPet.do") @SessionAttributes("pet") public class EditPetForm { // ... } Using @SessionAttribute to access pre-existing global session attributes 使用@SessionAttribute来访问已经存在的全局session属性 If you need access to pre-existing session attributes that are managed globally, i.e. outside the controller (e.g. by a filter), and may or may not be present use the @SessionAttribute annotation on a method parameter: 如果你需要访问已经存在的被全局控制的session属性,例如,在控制器之外(例如,通过过滤器),可以或不可以表现使用@SessionAttribute注解在一个方法参数上。 @RequestMapping("/") public String handle(@SessionAttribute User user) { // ... } For use cases that require adding or removing session attributes consider injecting org.springframework.web.context.request.WebRequest or javax.servlet.http.HttpSession into the controller method. 对于使用案例要求添加或删除session属性考虑注入org.springframework.web.context.request.WebRequest或javax.servlet.http.HttpSession到控制器方法中。 For temporary storage of model attributes in the session as part of a controller workflow consider using SessionAttributes as described in the section called “Using @SessionAttributes to store model attributes in the HTTP session between requests”. 对于临时存储model属性在session作为一个控制器流的一部分考虑使用SessionAttributes描述在之前的章节的名字为“使用@SessionAttributes来存储model属性在http的session在两个请求之间”。 Using @RequestAttribute to access request attributes 使用@RequestAttribute来访问请求属性 Similar to @SessionAttribute the @RequestAttribute annotation can be used to access pre-existing request attributes created by a filter or interceptor: 相似于@SessionAttribute,@RequestAttribute注解可以被使用来访问已经存在的请求属性通过过滤器或拦截器创建的。 @RequestMapping("/") public String handle(@RequestAttribute Client client) { // ... } Working with "application/x-www-form-urlencoded" data 使用"application/x-www-form-urlencoded"类型的数据 The previous sections covered use of @ModelAttribute to support form submission requests from browser clients. The same annotation is recommended for use with requests from non-browser clients as well. However there is one notable difference when it comes to working with HTTP PUT requests. Browsers can submit form data via HTTP GET or HTTP POST. Non-browser clients can also submit forms via HTTP PUT. This presents a challenge because the Servlet specification requires the ServletRequest.getParameter*() family of methods to support form field access only for HTTP POST, not for HTTP PUT. 之前的章节包含@ModelAttribute的使用来支持表单提交请求来自浏览器客户端。相同的注解被推荐使用通过请求来自非浏览器。然而这是一个值得注意的不同点当他通过http的put请求来工作。浏览器可以提交数据通过http的get或http的post。非浏览器客户端也可以提交通过http的put。这是一个挑战因为Servlet规范要求ServletRequest.getParameter*()的方法类来支持表单域来访问对于http的post而不是http的put。 To support HTTP PUT and PATCH requests, the spring-web module provides the filter HttpPutFormContentFilter, which can be configured in web.xml: 为了支持http的put和patch请求,spring-web模块提供了过滤器HttpPutFormContentFilter,可以被配置在web.xml中: The above filter intercepts HTTP PUT and PATCH requests with content type application/x-www-form-urlencoded, reads the form data from the body of the request, and wraps the ServletRequest in order to make the form data available through the ServletRequest.getParameter*() family of methods. 上面的过滤器拦截http的put和patch请求使用内容类型application/x-www-form-urlencoded,读取表单数据来自请求体,并且包裹ServletRequest为了使得表单数据可以通过ServletRequest.getParameter*()的方法类来获取。 [Note] 注意 As HttpPutFormContentFilter consumes the body of the request, it should not be configured for PUT or PATCH URLs that rely on other converters for application/x-www-form-urlencoded. This includes @RequestBody MultiValueMap 由于HttpPutFormContentFilter消费了请求体,他不会被配置为了put或patch的url依赖于其他的转换对于application/x-www-form-urlencoded。这包括@RequestBody的MultiValueMap Mapping cookie values with the @CookieValue annotation 使用@CookieValue注解来匹配cookie的值 The @CookieValue annotation allows a method parameter to be bound to the value of an HTTP cookie. @CookieValue注解允许一个方法参数被绑定一个http的cookie中的值。 Let us consider that the following cookie has been received with an http request: 让我们考虑下面的cookie接收来自http的请求: JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84 The following code sample demonstrates how to get the value of the JSESSIONID cookie: 下面的代码样例描述了如何获得cookie中的JSESSIONID中的值: @RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) { //... } Type conversion is applied automatically if the target method parameter type is not String. See the section called “Method Parameters And Type Conversion”. 类型转换被自动应用如果目标方法参数类型不是字符串。见章节“方法参数和类型转换”。 This annotation is supported for annotated handler methods in Servlet and Portlet environments. 这个注解被支持对于注解处理方法在servlet和porlet的环境中。 Mapping request header attributes with the @RequestHeader annotation 匹配请求头属性通过@RequestHeader注解 The @RequestHeader annotation allows a method parameter to be bound to a request header. @RequestHeader注解允许一个方法参数被绑定到请求头中。 Here is a sample request header: 这是一个简单的请求头: 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 The following code sample demonstrates how to get the value of the Accept-Encoding and Keep-Alive headers: 下面的代码样例展示了如何获得Accept-Encoding和Keep-Alive的值: @RequestMapping("/displayHeaderInfo.do") public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive") long keepAlive) { //... } Type conversion is applied automatically if the method parameter is not String. See the section called “Method Parameters And Type Conversion”. 类型转换被自动应用如果方法参数不是字符串类型。见章节“方法参数和类型转换”。 When an @RequestHeader annotation is used on a Map 当一个@RequestHeader注解被用于Map [Tip] 提示 Built-in support is available for converting a comma-separated string into an array/collection of strings or other types known to the type conversion system. For example a method parameter annotated with @RequestHeader("Accept") may be of type String but also String[] or List 内置的支持被可用对于转换一个逗号分隔的字符串为一个数组/集合或其他类型对于类型转换系统。例如一个方法参数注解使用了@RequestHeader("Accept")可以是字符串类型不仅仅是字符串数组或List This annotation is supported for annotated handler methods in Servlet and Portlet environments. 这个注解被支持注解处理器方法在Servlet和portlet环境中。 Method Parameters And Type Conversion 方法参数和类型转换 String-based values extracted from the request including request parameters, path variables, request headers, and cookie values may need to be converted to the target type of the method parameter or field (e.g., binding a request parameter to a field in an @ModelAttribute parameter) they’re bound to. If the target type is not String, Spring automatically converts to the appropriate type. All simple types such as int, long, Date, etc. are supported. You can further customize the conversion process through a WebDataBinder (see the section called “Customizing WebDataBinder initialization”) or by registering Formatters with the FormattingConversionService (see Section 9.6, “Spring Field Formatting”). 基于字符串的值来自请求包括请求参数、路径变量、请求头和cookie值可以需要被转换为目标类型的方法参数或field(例如,绑定一个请求参数对于一个field在一个@ModelAttribute参数)绑定。如果目标类型不是字符串,spring自动转换为适当的类型。所有简单的类型例如int、long、Date等等都是被支持的。你也可以自定义转换程序通过一个WebDataBinder(见章节“自定义WebDataBinder初始化”)或通过注册Formatters使用FormattingConversionService(见章节9.6,“spring的field的格式化”)。 Customizing WebDataBinder initialization 自定义WebDataBinder初始化 To customize request parameter binding with PropertyEditors through Spring’s WebDataBinder, you can use @InitBinder-annotated methods within your controller, @InitBinder methods within an @ControllerAdvice class, or provide a custom WebBindingInitializer. See the the section called “Advising controllers with @ControllerAdvice and @RestControllerAdvice” section for more details. 为了自定义请求参数绑定使用PropertyEditors通过spring的WebDataBinder,你可以使用@InitBinder注解方法在你的控制器中,@InitBinder方法使用@ControllerAdvice类或提供一个自定义的WebBindingInitializer。见章节“Advising控制器通过@ControllerAdvice和@RestControllerAdvice”来了解更多信息。 Customizing data binding with @InitBinder 使用@InitBinder来自定义数据绑定 Annotating controller methods with @InitBinder allows you to configure web data binding directly within your controller class. @InitBinder identifies methods that initialize the WebDataBinder that will be used to populate command and form object arguments of annotated handler methods. 注解控制器方法使用@InitBinder允许你来直接配置web数据绑定使用你的控制器类。@InitBinder定义方法初始化了WebDataBinder将被使用命令和表单object参数来自注解的处理器方法。 Such init-binder methods support all arguments that @RequestMapping methods support, except for command/form objects and corresponding validation result objects. Init-binder methods must not have a return value. Thus, they are usually declared as void. Typical arguments include WebDataBinder in combination with WebRequest or java.util.Locale, allowing code to register context-specific editors. 这样的init-binder方法支持所有的参数@RequestMapping方法支持的,除了命令/表单object和跨验证结果的object。Init-binder方法不能有返回值。因此,他们通常声明为void。通常参数包括WebDataBinder组合了WebRequest或java.util.Locale,允许代码来注册指定的上下文编辑器。 The following example demonstrates the use of @InitBinder to configure a CustomDateEditor for all java.util.Date form properties. 下面的例子描述了@InitBinder的使用来配置一个CustomDateEditor对于所有的java.util.Date类型的表单属性。 @Controller public class MyFormController { @InitBinder protected void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } // ... } Alternatively, as of Spring 4.2, consider using addCustomFormatter to specify Formatter implementations instead of PropertyEditor instances. This is particularly useful if you happen to have a Formatter-based setup in a shared FormattingConversionService as well, with the same approach to be reused for controller-specific tweaking of the binding rules. 作为替代,由于spring4.2,考虑使用addCustomFormatter来指定Formatter实现来替代PropertyEditor的实例。这是很有用的如果你希望有一个基于格式化的设置在一个共享的FormattingConversionService中,使用相同的方式来减少对于指定控制器对绑定规则的指定。 @Controller public class MyFormController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); } // ... } Configuring a custom WebBindingInitializer 配置一个自定义的WebBindingInitializer To externalize data binding initialization, you can provide a custom implementation of the WebBindingInitializer interface, which you then enable by supplying a custom bean configuration for an AnnotationMethodHandlerAdapter, thus overriding the default configuration. 为了使得数据绑定实例化,你可以提供一个自定义实现WebBindingInitializer接口,然后你可以允许提供一个自定义的bean的配置对于AnnotationMethodHandlerAdapter,来覆盖默认的配置。 The following example from the PetClinic application shows a configuration using a custom implementation of the WebBindingInitializer interface, org.springframework.samples.petclinic.web.ClinicBindingInitializer, which configures PropertyEditors required by several of the PetClinic controllers. 下面的例子来自PetClinic应用展示了一个配置使用一个自定义的实现了WebBindingInitializer接口,org.springframework.samples.petclinic.web.ClinicBindingInitializer,根据PetClinic控制器的需要配置了PropertyEditors。
@InitBinder methods can also be defined in an @ControllerAdvice-annotated class in which case they apply to matching controllers. This provides an alternative to using a WebBindingInitializer. See the the section called “Advising controllers with @ControllerAdvice and @RestControllerAdvice” section for more details.
@InitBinder方法也可以定义在@ControllerAdvice-annotated类中用于应用来匹配控制器。参考章节“修饰控制器通过@ControllerAdvice和@RestControllerAdvice”来了解更多细节信息。
Advising controllers with @ControllerAdvice and @RestControllerAdvice
修饰控制器使用@ControllerAdvice和@RestControllerAdvice
The @ControllerAdvice annotation is a component annotation allowing implementation classes to be auto-detected through classpath scanning. It is automatically enabled when using the MVC namespace or the MVC Java config.
@ControllerAdvice注解是一个组件注解允许实现类可以自动被探测通过类路径扫描。他也自动被允许当使用mvc命名空间或mvc的java配置时。
Classes annotated with @ControllerAdvice can contain @ExceptionHandler, @InitBinder, and @ModelAttribute annotated methods, and these methods will apply to @RequestMapping methods across all controller hierarchies as opposed to the controller hierarchy within which they are declared.
使用了@ControllerAdvice的注解类可以包含@ExceptionHandler、@InitBinder和@ModelAttribute注解方法,并且这些方法将被应用于@RequestMapping方法在多个控制器结构之间和他们定义的控制器结构截然相反。
@RestControllerAdvice is an alternative where @ExceptionHandler methods assume @ResponseBody semantics by default.
@RestControllerAdvice是一个代替当@ExceptionHandler方法默认使用了@ResponseBody的语义。
Both @ControllerAdvice and @RestControllerAdvice can target a subset of controllers:
@ControllerAdvice和@RestControllerAdvice可以标记一个控制器的子集:
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class AnnotationAdvice {}
// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class BasePackageAdvice {}
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class AssignableTypesAdvice {}
Check out the @ControllerAdvice documentation for more details.
参考@ControllerAdvice文档来了解更多信息。
Jackson Serialization View Support
Jackson序列化视图的支持
It can sometimes be useful to filter contextually the object that will be serialized to the HTTP response body. In order to provide such capability, Spring MVC has built-in support for rendering with Jackson’s Serialization Views.
有时从上下文中实现过滤是有意义的,object将被序列化传递给http的响应体。为了提供这样的功能,spring的mvc有一个内置的支持对于处理Jackson的序列化视图。
To use it with an @ResponseBody controller method or controller methods that return ResponseEntity, simply add the @JsonView annotation with a class argument specifying the view class or interface to be used:
为了使用@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;
}
}
[Note]
注意
Note that despite @JsonView allowing for more than one class to be specified, the use on a controller method is only supported with exactly one class argument. Consider the use of a composite interface if you need to enable multiple views.
注意尽管@JsonView允许多个类被指定,使用一个控制器方法支持恰好一个类参数。考虑使用组合接口如果你需要启动多个视图的话。
For controllers relying on view resolution, simply add the serialization view class to the model:
对于控制器返回视图,简单添加序列化视图类给model:
@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";
}
}
Jackson JSONP Support
In order to enable JSONP support for @ResponseBody and ResponseEntity methods, declare an @ControllerAdvice bean that extends AbstractJsonpResponseBodyAdvice as shown below where the constructor argument indicates the JSONP query parameter name(s):
为了对于@ResponseBody和ResponseEntity方法启动JSONP支持,定义一个@ControllerAdvice的bean来继承AbstractJsonpResponseBodyAdvice展示如下当构造器蚕食指示了JSONP的查询参数名:
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
For controllers relying on view resolution, JSONP is automatically enabled when the request has a query parameter named jsonp or callback. Those names can be customized through jsonpParameterNames property.
对于依赖视图的控制器,JSONP被自动允许当请求有一个查询参数名为jsonp或callback。这些名字也可以被自定义通过jsonpParameterNames属性。
22.3.4 Asynchronous Request Processing
异步的请求处理
Spring MVC 3.2 introduced Servlet 3 based asynchronous request processing. Instead of returning a value, as usual, a controller method can now return a java.util.concurrent.Callable and produce the return value from a Spring MVC managed thread. Meanwhile the main Servlet container thread is exited and released and allowed to process other requests. Spring MVC invokes the Callable in a separate thread with the help of a TaskExecutor and when the Callable returns, the request is dispatched back to the Servlet container to resume processing using the value returned by the Callable. Here is an example of such a controller method:
spring的mvc3.2引入了基于Servlet3的异步的请求处理。代替像通常一样返回一个值,一个控制器方法可以返回一个java.util.concurrent.Callable和产生返回值来自spring的mvc管理的线程。同时主servlet容器线程被推出并释放允许处理其他的请求。spring的mvc调用分离线程中的Callable通过TaskExecutor的帮助当一个Callable返回的时候,请求被转发给servlet容器来继续处理使用Callable返回的值。下面是一个这样的控制器方法:
@PostMapping
public Callable
return new Callable
public String call() throws Exception {
// ...
return "someView";
}
};
}
Another option is for the controller method to return an instance of DeferredResult. In this case the return value will also be produced from any thread, i.e. one that is not managed by Spring MVC. For example the result may be produced in response to some external event such as a JMS message, a scheduled task, and so on. Here is an example of such a controller method:
另一个选项对于控制器方法返回一个DeferredResult的实例。在这种情况返回值也将来自另一个线程,例如,一个没有被spring的mvc管理的线程。例如来自响应的结果对于一些外部的事件例如JMS消息、一个定时任务等等。下面是一个这样的控制器方法:
@RequestMapping("/quotes")
@ResponseBody
public DeferredResult
DeferredResult
// Save the deferredResult somewhere..
return deferredResult;
}
// In some other thread...
deferredResult.setResult(data);
This may be difficult to understand without any knowledge of the Servlet 3.0 asynchronous request processing features. It would certainly help to read up on that. Here are a few basic facts about the underlying mechanism:
没有Servlet3.0异步请求处理特性的知识理解这个是有困难的。他可以帮助我们仔细研读。这里给出一个基本的事实有关内部的策略:
A ServletRequest can be put in asynchronous mode by calling request.startAsync(). The main effect of doing so is that the Servlet, as well as any Filters, can exit but the response will remain open to allow processing to complete later.
一个ServletRequest可以被放入到异步模式通过调用request.startAsync()。主要这么做的影响是servlet、也包括过滤器可以推出但是响应依然会保留打开的状态允许以后来处理。
The call to request.startAsync() returns AsyncContext which can be used for further control over async processing. For example it provides the method dispatch, that is similar to a forward from the Servlet API except it allows an application to resume request processing on a Servlet container thread.
调用request.startAsync()返回AsyncContext可以被使用来进行进一步的控制通过异步的处理。例如他提供了方法的重定向,和转发来自Servlet的api相似除了他允许一个应用来恢复请求的处理在一个servlet容器线程中。
The ServletRequest provides access to the current DispatcherType that can be used to distinguish between processing the initial request, an async dispatch, a forward, and other dispatcher types.
ServletRequest提供访问对于当前的DispatcherType可以被使用来区分处理最初的请求、一个异步的派遣、一个转发和其他分配类型。
With the above in mind, the following is the sequence of events for async request processing with a Callable:
知道了上面的内容,下面是事件的顺序对于异步请求处理通过使用Callable:
Controller returns a Callable.
控制器返回一个Callable。
Spring MVC starts asynchronous processing and submits the Callable to a TaskExecutor for processing in a separate thread.
spring的mvc开始异步处理并提交Callable给TaskExecutor来在一个独立的线程中进行处理。
The DispatcherServlet and all Filter’s exit the Servlet container thread but the response remains open.
DispatcherServlet和所有的过滤器推出servlet容器线程但是响应依然是打开的。
The Callable produces a result and Spring MVC dispatches the request back to the Servlet container to resume processing.
Callable处理一个结果并且spring的mvc分发请求给Servlet容器来继续处理。
The DispatcherServlet is invoked again and processing resumes with the asynchronously produced result from the Callable.
DispatcherServlet被再次调用来恢复处理异步产生的结果来自Callable。
The sequence for DeferredResult is very similar except it’s up to the application to produce the asynchronous result from any thread:
DeferredResult的顺序是很相似的除了他启动一个应用来产生一个异步的结果来自任意的线程:
Controller returns a DeferredResult and saves it in some in-memory queue or list where it can be accessed.
控制器返回一个DeferredResult并且保持在内存的队列或列表中当他被访问的时候。
Spring MVC starts async processing.
spring的mvc开始异步的处理。
The DispatcherServlet and all configured Filter’s exit the request processing thread but the response remains open.
DispatcherServlet和所有配置的过滤器退出请求处理线程但是响应依然是打开的。
The application sets the DeferredResult from some thread and Spring MVC dispatches the request back to the Servlet container.
应用设置了DeferredResult来自一些线程并且spring的mvc分配请求返回给Servlet容器。
The DispatcherServlet is invoked again and processing resumes with the asynchronously produced result.
DispatcherServlet被再次调用并处理恢复的异步的产生结果。
For further background on the motivation for async request processing and when or why to use it please read this blog post series.
关于异步请求处理的内部斜街和何时为什么使用它请读取这篇博文系列。
Exception Handling for Async Requests
异步结果的异常处理
What happens if a Callable returned from a controller method raises an Exception while being executed? The short answer is the same as what happens when a controller method raises an exception. It goes through the regular exception handling mechanism. The longer explanation is that when a Callable raises an Exception Spring MVC dispatches to the Servlet container with the Exception as the result and that leads to resume request processing with the Exception instead of a controller method return value. When using a DeferredResult you have a choice whether to call setResult or setErrorResult with an Exception instance.
如果从控制器返回的Callable抛出了一个异常在执行的过程中会发生什么?简单的答案就是和控制器方法抛出一个异常是一样的。他走正常的异常处理策略。详细的解释是当一个Callable抛出一个异常spring的mvc分配给Servlet容器提供异常的结果并且将导致恢复请求的处理异常代理控制器方法返回的值。当使用DeferredResult你有一个选择就是是否调用setResult或setErrorResult对于一个异常实例。
Intercepting Async Requests
拦截异步请求
A HandlerInterceptor can also implement AsyncHandlerInterceptor in order to implement the afterConcurrentHandlingStarted callback, which is called instead of postHandle and afterCompletion when asynchronous processing starts.
一个HandlerInterceptor也可以实现AsyncHandlerInterceptor来实现afterConcurrentHandlingStarted的回调,被调用代替postHandle和afterCompletion当异步处理开始的时候。
A HandlerInterceptor can also register a CallableProcessingInterceptor or a DeferredResultProcessingInterceptor in order to integrate more deeply with the lifecycle of an asynchronous request and for example handle a timeout event. See the Javadoc of AsyncHandlerInterceptor for more details.
一个HandlerInterceptor也可以注册一个CallableProcessingInterceptor或一个DeferredResultProcessingInterceptor来整合异步请求的生命周期和例如处理一个超时的事件。参见AsyncHandlerInterceptor的javadocs来了解更多信息。
The DeferredResult type also provides methods such as onTimeout(Runnable) and onCompletion(Runnable). See the Javadoc of DeferredResult for more details.
DeferredResult类型也提供方法例如onTimeout(Runnable)和onCompletion(Runnable)。见DeferredResult的javadocs来了解详情。
When using a Callable you can wrap it with an instance of WebAsyncTask which also provides registration methods for timeout and completion.
当使用Callable,你可以使用一个WebAsyncTask的实例来包装他,并且提供注册方法用于超时和完成。
HTTP Streaming
http流
A controller method can use DeferredResult and Callable to produce its return value asynchronously and that can be used to implement techniques such as long polling where the server can push an event to the client as soon as possible.
一个控制器方法可以使用DeferredResult和Callable来异步产生他的返回值并且可以被使用来实现技术例如长时间轮询当服务器可以及时推送一个事件给客户端。
What if you wanted to push multiple events on a single HTTP response? This is a technique related to "Long Polling" that is known as "HTTP Streaming". Spring MVC makes this possible through the ResponseBodyEmitter return value type which can be used to send multiple Objects, instead of one as is normally the case with @ResponseBody, where each Object sent is written to the response with an HttpMessageConverter.
如果你希望推送多个事件在单个http响应中时会怎么样?这里有一项技术和“长时间轮询”有关就是“HTTP流”。spring的mvc实现这个响应通过ResponseBodyEmitter返回值类型可以被使用来发送多个object,代替一个使用@ResponseBody,每个object发送使用HttpMessageConverter写入到响应中。
Here is an example of that:
下面是一个例子:
@RequestMapping("/events")
public ResponseBodyEmitter handle() {
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
// Save the emitter somewhere..
return emitter;
}
// In some other thread
emitter.send("Hello once");
// and again later on
emitter.send("Hello again");
// and done at some point
emitter.complete();
Note that ResponseBodyEmitter can also be used as the body in a ResponseEntity in order to customize the status and headers of the response.
注意ResponseBodyEmitter也可以被使用作为一个内容在ResponseEntity中用于自定义响应的状态和头信息。
HTTP Streaming With Server-Sent Events
使用服务端发送事件的http流
SseEmitter is a sub-class of ResponseBodyEmitter providing support for Server-Sent Events. Server-sent events is a just another variation on the same "HTTP Streaming" technique except events pushed from the server are formatted according to the W3C Server-Sent Events specification.
SseEmitter是ResponseBodyEmitter的一个子类支持服务器端发送事件。服务器发送事件只是另一个在相同的http流的一个变化技术需要事件推送从服务端根据W3C的规定来定义格式化。
Server-Sent Events can be used for their intended purpose, that is to push events from the server to clients. It is quite easy to do in Spring MVC and requires simply returning a value of type SseEmitter.
服务端发送事件可以被使用用于他们内部的目的,用于推送事件从服务端到客户端。这在spring的mvc中做起来是比较容易的并且要求简单返回SseEmitter类型的值。
Note however that Internet Explorer does not support Server-Sent Events and that for more advanced web application messaging scenarios such as online games, collaboration, financial applicatinos, and others it’s better to consider Spring’s WebSocket support that includes SockJS-style WebSocket emulation falling back to a very wide range of browsers (including Internet Explorer) and also higher-level messaging patterns for interacting with clients through a publish-subscribe model within a more messaging-centric architecture. For further background on this see the following blog post.
注意,然而IE不支持服务端发送事件并且对于更多高级的web应用消息场景例如在线游戏、合作、金融应用和需要考虑spring的websocket支持包括SockJS风格的websocket仿真对于大范围的浏览器(例如IE)和高级别的消息模式对于内部客户端通过发布订阅模型使用以消息为中心的架构。对于更多的背景见下面的博客清单。
HTTP Streaming Directly To The OutputStream
直接到OutputStream的http流
ResponseBodyEmitter allows sending events by writing Objects to the response through an HttpMessageConverter. This is probably the most common case, for example when writing JSON data. However sometimes it is useful to bypass message conversion and write directly to the response OutputStream for example for a file download. This can be done with the help of the StreamingResponseBody return value type.
ResponseBodyEmitter允许通过写object来发送事件给响应通过HttpMessageConverter。这是大部分的场景,例如写JSON数据。然而有时绕开消息转换和直接写给响应的OutputStream也是有用的例如对于一次文件的下载。这可以通过StreamingResponseBody返回值类型来完成。
Here is an example of that:
下面是一个这样的例子:
@RequestMapping("/download")
public StreamingResponseBody handle() {
return new StreamingResponseBody() {
@Override
public void writeTo(OutputStream outputStream) throws IOException {
// write...
}
};
}
Note that StreamingResponseBody can also be used as the body in a ResponseEntity in order to customize the status and headers of the response.
注意StreamingResponseBody也可以用作为ResponseEntity中的内容来使用用于自定义响应的状态和头信息。
Configuring Asynchronous Request Processing
配置异步请求处理
Servlet Container Configuration
Servlet容器配置
For applications configured with a web.xml be sure to update to version 3.0:
对于配置应用通过web.xml保证升级到版本3.0:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> ...
Asynchronous support must be enabled on the DispatcherServlet through the
异步支持必须被启用对于DispatcherServlet通过
Below is some example web.xml configuration:
下面是一个web.xml的配置样例:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
If using Servlet 3, Java based configuration for example via WebApplicationInitializer, you’ll also need to set the "asyncSupported" flag as well as the ASYNC dispatcher type just like with web.xml. To simplify all this configuration, consider extending AbstractDispatcherServletInitializer, or better AbstractAnnotationConfigDispatcherServletInitializer which automatically set those options and make it very easy to register Filter instances.
如果使用servlet3,java的基本配置对于样例通过WebApplicationInitializer,你将需要设置asyncSupported标志对于ASYNC分发类型例如使用web.xml。为了简化配置,考虑扩展AbstractDispatcherServletInitializer或使用自动化的AbstractAnnotationConfigDispatcherServletInitializer设置这个选项使得对于注册过滤器实例更加的简单。
Spring MVC Configuration
spring的mvc的配置
The MVC Java config and the MVC namespace provide options for configuring asynchronous request processing. WebMvcConfigurer has the method configureAsyncSupport while
mvc的java配置和mvc的命名空间提供了选项对于配置异步的请求处理。WebMvcConfigurer有方法configureAsyncSupport当
Those allow you to configure the default timeout value to use for async requests, which if not set depends on the underlying Servlet container (e.g. 10 seconds on Tomcat). You can also configure an AsyncTaskExecutor to use for executing Callable instances returned from controller methods. It is highly recommended to configure this property since by default Spring MVC uses SimpleAsyncTaskExecutor. The MVC Java config and the MVC namespace also allow you to register CallableProcessingInterceptor and DeferredResultProcessingInterceptor instances.
他们允许你来配置默认的超时对于使用异步请求,如果不设置依赖底层的Servlet容器(例如Tomcat是10秒)。你也可以配置一个AsyncTaskExecutor来用于使用执行Callable实例返回来自控制器方法。推荐配置这个属性默认使用spring的mvc的SimpleAsyncTaskExecutor。mvc的Java配置和mvc的命名空间允许你注册CallableProcessingInterceptor和DeferredResultProcessingInterceptor实例。
If you need to override the default timeout value for a specific DeferredResult, you can do so by using the appropriate class constructor. Similarly, for a Callable, you can wrap it in a WebAsyncTask and use the appropriate class constructor to customize the timeout value. The class constructor of WebAsyncTask also allows providing an AsyncTaskExecutor.
如果你需要覆盖默认的超时对于指定DeferredResult,你也可以使用适当的类构造器。相似的对于一个Callable方法,你可以使用WebAsyncTask来包装他并且使用适当的类构造器来自定义超时值。WebAsyncTask的类构造器也提供了一个AsyncTaskExecutor。
22.3.5 Testing Controllers
测试控制器
The spring-test module offers first class support for testing annotated controllers. See Section 15.6, “Spring MVC Test Framework”.
spring-test模块提供了支持对于测试注册控制器。见章节15.6”spring的mvc的测试框架“。