【Spring】Spring Framework Reference Documentation中文版19

22.4 Handler mappings

处理器匹配

 

In previous versions of Spring, users were required to define one or more HandlerMapping beans in the web application context to map incoming web requests to appropriate handlers. With the introduction of annotated controllers, you generally dont need to do that because the RequestMappingHandlerMapping automatically looks for @RequestMapping annotations on all @Controller beans. However, do keep in mind that all HandlerMapping classes extending from AbstractHandlerMapping have the following properties that you can use to customize their behavior:

之前版本的spring中,用户被要求定义一个或多个HandlerMappingbean在一个web应用上下文来匹配输入的web请求对于适当的处理器。由于注册控制器被引入,你不需要这样做由于RequestMappingHandlerMapping自动来查找@RequestMapping注解对于所有的@Controllerbean。然而,但是要知道所有的HandlerMapping类扩展自AbstractHandlerMapping有下面的属性你会用于自定义他们的行为:

 

    interceptors List of interceptors to use. HandlerInterceptors are discussed in Section 22.4.1, Intercepting requests with a HandlerInterceptor.

使用拦截器的拦截列表。HandlerInterceptors22.4.1中讨论,”使用HandlerInterceptor来拦截请求“

    defaultHandler Default handler to use, when this handler mapping does not result in a matching handler.

使用defaultHandler的默认处理器,当这个处理器匹配结果不是在一个匹配的处理器中。

    order Based on the value of the order property (see the org.springframework.core.Ordered interface), Spring sorts all handler mappings available in the context and applies the first matching handler.

顺序基于order属性的值(见org.springframework.core.Ordered接口),spring存储所有的处理器匹配在上下文中并且应用首先匹配处理。

    alwaysUseFullPath If true , Spring uses the full path within the current Servlet context to find an appropriate handler. If false (the default), the path within the current Servlet mapping is used. For example, if a Servlet is mapped using /testing/* and the alwaysUseFullPath property is set to true, /testing/viewPage.html is used, whereas if the property is set to false, /viewPage.html is used.

alwaysUseFullPath如果为truespring使用全路径在当前的servlet上下文用于找到适当的处理器。如果为false(默认值),使用当前的Servlet匹配路径。例如,如果一个servlet匹配/testing/*并且alwaysUseFullPath属性为true/testing/viewPage.html被使用,如果属性设置为false,则使用/viewPage.html

    urlDecode Defaults to true, as of Spring 2.5. If you prefer to compare encoded paths, set this flag to false. However, the HttpServletRequest always exposes the Servlet path in decoded form. Be aware that the Servlet path will not match when compared with encoded paths.

urlDecode默认为true,在spring2.5中。如果你倾向于比较编码路径,设置标志位为false。然而,HttpServletRequest暴露Servlet路径在编码的形式下。注意Servlet路径将匹配根据编码路径。

 

The following example shows how to configure an interceptor:

下面的例子展示配置一个拦截器:

 

<beans>

    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

        <property name="interceptors">

            <bean class="example.MyInterceptor"/>

        </property>

    </bean>

<beans>

 

22.4.1 Intercepting requests with a HandlerInterceptor

使用HandlerInterceptor来拦截请求

 

Springs handler mapping mechanism includes handler interceptors, which are useful when you want to apply specific functionality to certain requests, for example, checking for a principal.

spring的处理器匹配策略包括处理器拦截,当你希望应用指定的功能对于特定的请求时有用,例如,主要为了检测。

 

Interceptors located in the handler mapping must implement HandlerInterceptor from the org.springframework.web.servlet package. This interface defines three methods: preHandle(..) is called before the actual handler is executed; postHandle(..) is called after the handler is executed; and afterCompletion(..) is called after the complete request has finished. These three methods should provide enough flexibility to do all kinds of preprocessing and postprocessing.

拦截器定义在处理器匹配必须实现org.springframework.web.servlet包中的HandlerInterceptor接口。这个接口定义了三个方法:preHandle被调用在实际处理执行之前;postHandle被调用在处理执行之后;并且afterCompletion被调用在整个请求完成之后。这三个方法应当方便的提供用于实现各种处理前后的操作。

 

The preHandle(..) method returns a boolean value. You can use this method to break or continue the processing of the execution chain. When this method returns true, the handler execution chain will continue; when it returns false, the DispatcherServlet assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain.

preHandle方法返回一个boolean值。你可以使用这个方法来breakcontinue执行链。当方法返回true,处理器执行链将会继续,当返回falseDispatcherServlet会假设拦截器自身处理的请求(并且,例如返回适当的视图)并且不需要继续执行其他的拦截器并且实际的处理在执行链中。

 

Interceptors can be configured using the interceptors property, which is present on all HandlerMapping classes extending from AbstractHandlerMapping. This is shown in the example below:

拦截器可以被配置使用interceptors属性,所有的HandlerMapping类扩展自AbstractHandlerMapping。展示在下面的例子中:

 

<beans>

    <bean id="handlerMapping"

            class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">

        <property name="interceptors">

            <list>

                <ref bean="officeHoursInterceptor"/>

            </list>

        </property>

    </bean>

 

    <bean id="officeHoursInterceptor"

            class="samples.TimeBasedAccessInterceptor">

        <property name="openingTime" value="9"/>

        <property name="closingTime" value="18"/>

    </bean>

</beans>

 

package samples;

 

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

 

    private int openingTime;

    private int closingTime;

 

    public void setOpeningTime(int openingTime) {

        this.openingTime = openingTime;

    }

 

    public void setClosingTime(int closingTime) {

        this.closingTime = closingTime;

    }

 

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,

            Object handler) throws Exception {

        Calendar cal = Calendar.getInstance();

        int hour = cal.get(HOUR_OF_DAY);

        if (openingTime <= hour && hour < closingTime) {

            return true;

        }

        response.sendRedirect("http://host.com/outsideOfficeHours.html");

        return false;

    }

}

 

Any request handled by this mapping is intercepted by the TimeBasedAccessInterceptor. If the current time is outside office hours, the user is redirected to a static HTML file that says, for example, you can only access the website during office hours.

任何请求处理通过这个匹配是通过TimeBasedAccessInterceptor来拦截的。如果当前时间是在小时之外,用户将被定向到一个静态的html文件并且展示,例如,你可能只能在上班时间访问网站。

 

[Note]

注意

 

When using the RequestMappingHandlerMapping the actual handler is an instance of HandlerMethod which identifies the specific controller method that will be invoked.

当使用RequestMappingHandlerMapping实际的处理器是一个HandlerMethod的实例定义了指定的控制器方法被调用。

 

As you can see, the Spring adapter class HandlerInterceptorAdapter makes it easier to extend the HandlerInterceptor interface.

你看到,spring适配器类HandlerInterceptorAdapter使得扩展HandlerInterceptor的接口很简单。

 

[Tip]

提示

 

In the example above, the configured interceptor will apply to all requests handled with annotated controller methods. If you want to narrow down the URL paths to which an interceptor applies, you can use the MVC namespace or the MVC Java config, or declare bean instances of type MappedInterceptor to do that. See Section 22.16.1, Enabling the MVC Java Config or the MVC XML Namespace.

在上面的例子中,配置拦截器将应用于所有的使用了注解方法的请求处理。如果你希望缩小URL路径匹配的范围,你可以使用mvc命名空间或mvcjava配置,或定义MappedInterceptor类型的bean实例来实现这个功能。将章节22.16.1,“允许mvcjava配置或mvcxml命名空间”。

 

Note that the postHandle method of HandlerInterceptor is not always ideally suited for use with @ResponseBody and ResponseEntity methods. In such cases an HttpMessageConverter writes to and commits the response before postHandle is called which makes it impossible to change the response, for example to add a header. Instead an application can implement ResponseBodyAdvice and either declare it as an @ControllerAdvice bean or configure it directly on RequestMappingHandlerAdapter.

注意HandlerInterceptor的后处理方法理想上并不是适合使用@ResponseBodyResponseEntity方法。在这种情况,一个HttpMessageConverter写到并提交响应在后处理方法之前被叫做不可能改变响应,例如添加一个头信息。代替一个应用可以实现ResponseBodyAdvice和定义一个@ControllerAdvicebean或直接在RequestMappingHandlerAdapter上进行配置。

 

22.5 Resolving views

解析视图

 

All MVC frameworks for web applications provide a way to address views. Spring provides view resolvers, which enable you to render models in a browser without tying you to a specific view technology. Out of the box, Spring enables you to use JSPs, Velocity templates and XSLT views, for example. See Chapter 23, View technologies for a discussion of how to integrate and use a number of disparate view technologies.

所有的mvc框架对于web应用提供了一种方式来处理视图。spring提供了视图解析,允许你在浏览器中提出模型而不需要你来指定一个视图技术。在箱子外,spring允许你来使用jspVelocity模板和xslt视图,例如。将章节23,视图技术是为了用于讨论如何继承和使用一系列分离的视图技术。

 

The two interfaces that are important to the way Spring handles views are ViewResolver and View. The ViewResolver provides a mapping between view names and actual views. The View interface addresses the preparation of the request and hands the request over to one of the view technologies.

这两个接口对于spring的处理方式是重要的是ViewResolverViewViewResolver提供了一个匹配在视图名和实际的视图之间。View接口描述了请求的准备和处理请求在其中一个视图技术中。

 

22.5.1 Resolving views with the ViewResolver interface

使用ViewResolver接口来解析视图

 

As discussed in Section 22.3, Implementing Controllers, all handler methods in the Spring Web MVC controllers must resolve to a logical view name, either explicitly (e.g., by returning a String, View, or ModelAndView) or implicitly (i.e., based on conventions). Views in Spring are addressed by a logical view name and are resolved by a view resolver. Spring comes with quite a few view resolvers. This table lists most of them; a couple of examples follow.

由于22.3节中的讨论,“实现控制器”、所有的处理方法在springwebmvc控制器中必须解析为一个逻辑视图名、尤其是(例如,返回一个字符串、ViewModelAndView)或者隐含的(例如,基于管理)。spring中的Views通过一个逻辑视图名并且通过视图解析器来解析。spring使用一些视图解析器。下面的表格列出了大部分,有一组例子如下。

 

Table 22.3. View resolvers

视图解析器

ViewResolver

视图解析器

Description

描述

AbstractCachingViewResolver

Abstract view resolver that caches views. Often views need preparation before they can be used; extending this view resolver provides caching.

抽象的解析器可以缓存视图。经常使用的视图需要在使用之前被缓存,括者这个视图解析器提供缓存

XmlViewResolver

Implementation of ViewResolver that accepts a configuration file written in XML with the same DTD as Springs XML bean factories. The default configuration file is /WEB-INF/views.xml.

实现视图解析器接收一个xml的配置文件使用springxmlbean工厂中的dtd。默认配置是/WEB-INF/views.xml。

ResourceBundleViewResolver

Implementation of ViewResolver that uses bean definitions in a ResourceBundle, specified by the bundle base name. Typically you define the bundle in a properties file, located in the classpath. The default file name is views.properties.

实现视图解析器使用bean定义在ResourceBundle中,指定一个绑定名。通常你定义绑定在属性文件中,文件在classpath中。默认的文件名是views.properties。

UrlBasedViewResolver

Simple implementation of the ViewResolver interface that effects the direct resolution of logical view names to URLs, without an explicit mapping definition. This is appropriate if your logical names match the names of your view resources in a straightforward manner, without the need for arbitrary mappings.

简单实现视图解析器接口影响逻辑视图名到url的解析,不需要明确的匹配定义。适用于如果你的逻辑名匹配你的视图资源名在一种直接的情况而不需要使用任意的匹配的情况下。

InternalResourceViewResolver

Convenient subclass of UrlBasedViewResolver that supports InternalResourceView (in effect, Servlets and JSPs) and subclasses such as JstlView and TilesView. You can specify the view class for all views generated by this resolver by using setViewClass(..). See the UrlBasedViewResolver javadocs for details.

UrlBasedViewResolver的方便的子类支持InternalResourceView(实际上,ServletJSP)和子类例如JstlView和TilesView。你可以定义视图类对于所有的视图有这个解析器生成通过使用setViewClass方法。详见UrlBasedViewResolver的javadocs

VelocityViewResolver / FreeMarkerViewResolver

Convenient subclass of UrlBasedViewResolver that supports VelocityView (in effect, Velocity templates) or FreeMarkerView ,respectively, and custom subclasses of them.

UrlBasedViewResolver的方便的子类支持VelocityView(事实上是Velocity和模板)或FreeMarkerView,分别和他们的自定义子类。

ContentNegotiatingViewResolver

Implementation of the ViewResolver interface that resolves a view based on the request file name or Accept header. See Section 22.5.4, ContentNegotiatingViewResolver.

实现ViewResolver接口解决了依赖于请求文件名的视图或接收头。见章节22.5.4,“ContentNegotiatingViewResolver”

As an example, with JSP as a view technology, you can use the UrlBasedViewResolver. This view resolver translates a view name to a URL and hands the request over to the RequestDispatcher to render the view.

作为一个例子,使用JSP作为视图技术,你可以使用UrlBasedViewResolver。视图解析器翻译视图名为URL和处理请求在RequestDispatcher上用于渲染视图。

 

<bean id="viewResolver"

        class="org.springframework.web.servlet.view.UrlBasedViewResolver">

    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

    <property name="prefix" value="/WEB-INF/jsp/"/>

    <property name="suffix" value=".jsp"/>

</bean>

 

When returning test as a logical view name, this view resolver forwards the request to the RequestDispatcher that will send the request to /WEB-INF/jsp/test.jsp.

当返回test作为一个逻辑视图名,视图解析器转发请求给RequestDispatcher并且将发送请求给/WEB-INF/jsp/test.jsp

 

When you combine different view technologies in a web application, you can use the ResourceBundleViewResolver:

当你合并不同的视图技术在一个web应用中时,你可以使用ResourceBundleViewResolver

 

<bean id="viewResolver"

        class="org.springframework.web.servlet.view.ResourceBundleViewResolver">

    <property name="basename" value="views"/>

    <property name="defaultParentView" value="parentView"/>

</bean>

 

The ResourceBundleViewResolver inspects the ResourceBundle identified by the basename, and for each view it is supposed to resolve, it uses the value of the property [viewname].(class) as the view class and the value of the property [viewname].url as the view url. Examples can be found in the next chapter which covers view technologies. As you can see, you can identify a parent view, from which all views in the properties file "extend". This way you can specify a default view class, for example.

ResourceBundleViewResolver通过返回路径中的文件名来检查ResourceBundle,并且对于每一个视图都支持解析,他使用[viewname].(class)的属性作为一个视图类和[viewname].url属性作为一个视图的URL。例子在下一章节中出现并且包含视图技术。你可以看见,你可以定义一个父视图,对于所有的视图在属性文件中的"extend"。这种方式你可以指定默认的视图类,例如。

 

[Note]

注意

 

Subclasses of AbstractCachingViewResolver cache view instances that they resolve. Caching improves performance of certain view technologies. Its possible to turn off the cache by setting the cache property to false. Furthermore, if you must refresh a certain view at runtime (for example when a Velocity template is modified), you can use the removeFromCache(String viewName, Locale loc) method.

AbstractCachingViewResolver的子类缓存解析过的视图实例。缓存可以提高视图技术的性能。可以关闭缓存通过设置cache属性为false。此外,如果你必须要在运行时刷新视图(例如当一个Velocity模板被修改),你可以使用removeFromCache(String viewName, Locale loc)方法。

 

22.5.2 Chaining ViewResolvers

视图解析器链

 

Spring supports multiple view resolvers. Thus you can chain resolvers and, for example, override specific views in certain circumstances. You chain view resolvers by adding more than one resolver to your application context and, if necessary, by setting the order property to specify ordering. Remember, the higher the order property, the later the view resolver is positioned in the chain.

spring支持多个视图解析器。你可以将他们链化,例如,覆盖指定的视图在特定的环境中。你的链视图解析通过添加多个视图解析器在你的应用上下文中,如果可以,通过设置order属性来定义顺序。记住,order属性越高,视图解析器就越在链子的后面。

 

In the following example, the chain of view resolvers consists of two resolvers, an InternalResourceViewResolver, which is always automatically positioned as the last resolver in the chain, and an XmlViewResolver for specifying Excel views. Excel views are not supported by the InternalResourceViewResolver.

在下面的例子中,视图解析链包含两个视图解析器,InternalResourceViewResolver,用于自动确定位置在解析链的最后,XmlViewResolver用于指定的Excel视图。Excel视图不被InternalResourceViewResolver支持。

 

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

    <property name="prefix" value="/WEB-INF/jsp/"/>

    <property name="suffix" value=".jsp"/>

</bean>

 

<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">

    <property name="order" value="1"/>

    <property name="location" value="/WEB-INF/views.xml"/>

</bean>

 

<!-- in views.xml -->

 

<beans>

    <bean name="report" class="org.springframework.example.ReportExcelView"/>

</beans>

 

If a specific view resolver does not result in a view, Spring examines the context for other view resolvers. If additional view resolvers exist, Spring continues to inspect them until a view is resolved. If no view resolver returns a view, Spring throws a ServletException.

如果一个指定的视图解析没有解析为一个视图,spring检查其他视图解析的上下文。如果存在额外的视图解析器,spring继续检查他们直到一个视图被解析。如果没有视图解析器返回一个视图,spring抛出一个ServletException异常。

 

The contract of a view resolver specifies that a view resolver can return null to indicate the view could not be found. Not all view resolvers do this, however, because in some cases, the resolver simply cannot detect whether or not the view exists. For example, the InternalResourceViewResolver uses the RequestDispatcher internally, and dispatching is the only way to figure out if a JSP exists, but this action can only execute once. The same holds for the VelocityViewResolver and some others. Check the javadocs of the specific view resolver to see whether it reports non-existing views. Thus, putting an InternalResourceViewResolver in the chain in a place other than the last results in the chain not being fully inspected, because the InternalResourceViewResolver will always return a view!

视图解析器规定一个视图解析器可以返回null来指定视图没有被找到。并不是所有的视图解析器都这么做,然而,因为在一些情况,解析器不能简单的探测到是否存在视图。例如,InternalResourceViewResolver内部使用RequestDispatcher,并且分发只是唯一的方式来指定JSP的存在,但是这个动作只会执行一次。相同的处理对于VelocityViewResolver和其他的解析器。检查特定视图解析器的javadocs来确定他返回的不存在视图。因此,将InternalResourceViewResolver放在解析链中使得最后链中的结果没有被全部检查,因为InternalResourceViewResolver将返回一个视图。

 

22.5.3 Redirecting to Views

重定向到视图

 

As mentioned previously, a controller typically returns a logical view name, which a view resolver resolves to a particular view technology. For view technologies such as JSPs that are processed through the Servlet or JSP engine, this resolution is usually handled through the combination of InternalResourceViewResolver and InternalResourceView, which issues an internal forward or include via the Servlet APIs RequestDispatcher.forward(..) method or RequestDispatcher.include() method. For other view technologies, such as Velocity, XSLT, and so on, the view itself writes the content directly to the response stream.

之前提到过,一个控制器通常返回一个逻辑视图名,一个视图解析器解析一个特定的视图技术。对于视图技术例如JSP通过ServletJSP引擎来处理,这个解决方案通常使用InternalResourceViewResolverInternalResourceView来组合处理,声明一个内部的转发或通过ServletAPIRequestDispatcher.forward方法或RequestDispatcher.include方法。对于其他的视图技术,例如VelocityXSLT等等,视图本身将直接写入响应流中。

 

It is sometimes desirable to issue an HTTP redirect back to the client, before the view is rendered. This is desirable, for example, when one controller has been called with POST data, and the response is actually a delegation to another controller (for example on a successful form submission). In this case, a normal internal forward will mean that the other controller will also see the same POST data, which is potentially problematic if it can confuse it with other expected data. Another reason to perform a redirect before displaying the result is to eliminate the possibility of the user submitting the form data multiple times. In this scenario, the browser will first send an initial POST; it will then receive a response to redirect to a different URL; and finally the browser will perform a subsequent GET for the URL named in the redirect response. Thus, from the perspective of the browser, the current page does not reflect the result of a POST but rather of a GET. The end effect is that there is no way the user can accidentally re- POST the same data by performing a refresh. The refresh forces a GET of the result page, not a resend of the initial POST data.

有时直接返回一个HTTP到客户端,在视图被解析之前。这是被希望的,例如,当一个控制器已经被POST的数据调用,并且响应实际委托给另一个控制器(例如一个成功的提交)。在这种情况,一个普通的内部转发意味着另一个控制器将看到相同是POST数据,可能会有潜在的问题如果和其他的数据混淆的话。另一个理由来执行转发在展示一个结果之前结果被清楚使得用户可以多次的提交数据。在这个场景中,浏览器将首先发送一个最初的POST,将收到一个响应给不同的URL,并且最终浏览器将执行一个后续的GET操作对于URL在转发的响应中。因此,从浏览器的视角来看,当前的页面不需要反射一个POST结果而不是GET结果。没有方法用户可以意外的重新POST相同的数据通过执行刷新。刷新强制结果页面的GET,不会在发送一个内部的POST数据。

 

RedirectView

 

One way to force a redirect as the result of a controller response is for the controller to create and return an instance of Springs RedirectView. In this case, DispatcherServlet does not use the normal view resolution mechanism. Rather because it has been given the (redirect) view already, the DispatcherServlet simply instructs the view to do its work. The RedirectView in turn calls HttpServletResponse.sendRedirect() to send an HTTP redirect to the client browser.

一种方式来转发作为控制器响应的结果是对于控制器的创建和返回一个springRedirectView的实例。在这种情况,DispatcherServlet不会使用通常的视图解析策略。而且因为他已经给予了视图,DispatcherServlet简单的指定了视图来做这件事。RedirectView反过来调用HttpServletResponse.sendRedirect来发送http请求转发给客户端浏览器。

 

If you use RedirectView and the view is created by the controller itself, it is recommended that you configure the redirect URL to be injected into the controller so that it is not baked into the controller but configured in the context along with the view names. The the section called The redirect: prefixfacilitates this decoupling.

如果你使用RedirectView并且视图被控制器创建,建议你来配置转发URL注入到控制器以方便不会注入控制器当时配置在上下文通过视图名。这一节名为“The redirect: prefix”来实现解耦。

 

Passing Data To the Redirect Target

传递数据给转发目标

 

By default all model attributes are considered to be exposed as URI template variables in the redirect URL. Of the remaining attributes those that are primitive types or collections/arrays of primitive types are automatically appended as query parameters.

默认情况下所有的model属性被考虑用于扩展URI模板变量来转发URL。剩余的属性是原始类型或集合/数组包含原始类型被自动作为查询参数。

 

Appending primitive type attributes as query parameters may be the desired result if a model instance was prepared specifically for the redirect. However, in annotated controllers the model may contain additional attributes added for rendering purposes (e.g. drop-down field values). To avoid the possibility of having such attributes appear in the URL, an @RequestMapping method can declare an argument of type RedirectAttributes and use it to specify the exact attributes to make available to RedirectView. If the method does redirect, the content of RedirectAttributes is used. Otherwise the content of the model is used.

追加原始类型属性作为查询参数可以作为期望的结果如果一个model实例被准备用于转发。然而,在注解控制器model可以包含额外的属性添加到处理的目的(例如,下来域值)。为了避免有这样的属性出现在URL中,一个@RequestMapping方法可以定义RedirectAttributes类型的属性并且使用它来指定额外的属性使得对于RedirectView有效。如果方法被转发,RedirectAttributes的内容被使用。此外model的内容被属性。

 

The RequestMappingHandlerAdapter provides a flag called "ignoreDefaultModelOnRedirect" that can be used to indicate the content of the default Model should never be used if a controller method redirects. Instead the controller method should declare an attribute of type RedirectAttributes or if it doesnt do so no attributes should be passed on to RedirectView. Both the MVC namespace and the MVC Java config keep this flag set to false in order to maintain backwards compatibility. However, for new applications we recommend setting it to true

RequestMappingHandlerAdapter提供了一个标志名为“ignoreDefaultModelOnRedirect”可以被使用来指定默认model的内容不会被使用如果一个控制器方法转发。作为代替控制器方法应当被定义RedirectAttributes类型的属性或如果他没有这么做因此没有属性被传递给RedirectViewmvc的命名空间和mvcjava配置设置为false使得保持向后兼容性。然而,对于新的应用我们建议设置为true

 

Note that URI template variables from the present request are automatically made available when expanding a redirect URL and do not need to be added explicitly neither through Model nor RedirectAttributes. For example:

注意URI模板变量来自目前的请求使得有效当扩展一个转发URL并且不需要明确添加通过Model而不是RedirectAttributes。例如:

 

@PostMapping("/files/{path}")

public String upload(...) {

    // ...

    return "redirect:files/{path}";

}

 

Another way of passing data to the redirect target is via Flash Attributes. Unlike other redirect attributes, flash attributes are saved in the HTTP session (and hence do not appear in the URL). See Section 22.6, Using flash attributesfor more information.

另一种方法来传递数据为转发目标是通过Flash属性。不像其他的转发转发属性,flash属性被保存到HTTP的会话中(并且因此没有出现在URL中)。见章节22.6“使用false属性”来了解更多信息。

 

The redirect: prefix

redirect前缀

 

While the use of RedirectView works fine, if the controller itself creates the RedirectView, there is no avoiding the fact that the controller is aware that a redirection is happening. This is really suboptimal and couples things too tightly. The controller should not really care about how the response gets handled. In general it should operate only in terms of view names that have been injected into it.

RedirectView的使用工作正常是,如果控制器本身创建了RedirectView,将不会避免事实就是控制器意识到转发的发生。这是次优的并且之间是联系紧密的。控制器应当不会关心响应如何获得处理。通常他应当操作只有通过视图名并且注入到其中。

 

The special redirect: prefix allows you to accomplish this. If a view name is returned that has the prefix redirect:, the UrlBasedViewResolver (and all subclasses) will recognize this as a special indication that a redirect is needed. The rest of the view name will be treated as the redirect URL.

特定的redirect:前缀允许你来完成这些。如果一个视图名是返回并且有前缀redirect:,UrlBasedViewResolver(和所有的子类)将意识到这是一个特殊的指示需要转发。剩下的视图名将被作为转发的URL

 

The net effect is the same as if the controller had returned a RedirectView, but now the controller itself can simply operate in terms of logical view names. A logical view name such as redirect:/myapp/some/resource will redirect relative to the current Servlet context, while a name such as redirect:http://myhost.com/some/arbitrary/path will redirect to an absolute URL.

网络影响是相同的如果控制器返回一个RedirectView,但是现在控制器本身可以简单的操作逻辑视图名。一个逻辑视图名例如redirect:/myapp/some/resource将转发相关的内容到当前的Servlet上下文,例如一个名字为redirect:http://myhost.com/some/arbitrary/path将转发到一个绝对的URL

 

Note that the controller handler is annotated with the @ResponseStatus, the annotation value takes precedence over the response status set by RedirectView.

注意控制器处理器是使用了注解@ResponseStatus,注解值优于响应状态通过RedirectView来设置。

 

The forward: prefix

forward:前缀

 

It is also possible to use a special forward: prefix for view names that are ultimately resolved by UrlBasedViewResolver and subclasses. This creates an InternalResourceView (which ultimately does a RequestDispatcher.forward()) around the rest of the view name, which is considered a URL. Therefore, this prefix is not useful with InternalResourceViewResolver and InternalResourceView (for JSPs for example). But the prefix can be helpful when you are primarily using another view technology, but still want to force a forward of a resource to be handled by the Servlet/JSP engine. (Note that you may also chain multiple view resolvers, instead.)

可以使用指定的forward:前缀用于视图名最后通过UrlBasedViewResolver和其子类来解析。创建一个InternalResourceView(最后是RequestDispatcher.forward)在剩余的视图名如果考虑为一个URL。因此,这个前缀不是有用配合InternalResourceViewResolverInternalResourceView(例如对于JSP)。但是前缀可以有帮助当你主要使用另一种视图技术,但是依然希望强制转发响应通过Servlet/JSP引擎来处理。(注意你也可以连接多个视图解析器作为替代。)

 

As with the redirect: prefix, if the view name with the forward: prefix is injected into the controller, the controller does not detect that anything special is happening in terms of handling the response.

由于redirect:前缀,如果视图名使用了forward:前缀被注入到控制器,控制器将探测任何特殊的在处理响应的时候。

 

22.5.4 ContentNegotiatingViewResolver

 

The ContentNegotiatingViewResolver does not resolve views itself but rather delegates to other view resolvers, selecting the view that resembles the representation requested by the client. Two strategies exist for a client to request a representation from the server:

ContentNegotiatingViewResolver不会处理视图本身而是委托给其他的视图解析器,选择视图通过客户端的请求。两个策略存在对于一个客户端请求来自服务端:

 

    Use a distinct URI for each resource, typically by using a different file extension in the URI. For example, the URI http://www.example.com/users/fred.pdf requests a PDF representation of the user fred, and http://www.example.com/users/fred.xml requests an XML representation.

使用独立的URI对于每个资源,通常使用不同的文件扩展在URI中。例如,URI http://www.example.com/users/fred.pdf请求一个pdf来表现fred用户,并且http://www.example.com/users/fred.xml用于请求xml的表现。

    Use the same URI for the client to locate the resource, but set the Accept HTTP request header to list the media types that it understands. For example, an HTTP request for http://www.example.com/users/fred with an Accept header set to application/pdf requests a PDF representation of the user fred, while http://www.example.com/users/fred with an Accept header set to text/xml requests an XML representation. This strategy is known as content negotiation.

使用相同的URI对于客户端来确定资源的位置,但是设置接受http请求头尾列出的媒体类型是可以理解的。例如,一个http请求对于http://www.example.com/users/fred附带一个接受头信息设置为application/pdf请求一个pdf来代表用户fredhttp://www.example.com/users/fred附带一个请求头为text/xml则请求一个xml的代表。这个策略被内容协商已知。

 

[Note]

注意

 

One issue with the Accept header is that it is impossible to set it in a web browser within HTML. For example, in Firefox, it is fixed to:

一个有关请求头的问题是不可能使用html将其设置在web浏览器中。例如,在firefox中,他默认是:

 

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

 

For this reason it is common to see the use of a distinct URI for each representation when developing browser based web applications.

由于这个原因通常使用uri对于每种不同的代表当开发基于浏览器的web应用时。

 

To support multiple representations of a resource, Spring provides the ContentNegotiatingViewResolver to resolve a view based on the file extension or Accept header of the HTTP request. ContentNegotiatingViewResolver does not perform the view resolution itself but instead delegates to a list of view resolvers that you specify through the bean property ViewResolvers.

为了支持多个资源的代表,spring提供了ContentNegotiatingViewResolver来解析视图基于文件扩展名或http请求中的接受头信息。ContentNegotiatingViewResolver没有表现视图解析本身但是作为代替为视图解析列表你通过ViewResolversbean的属性来定义的。

 

The ContentNegotiatingViewResolver selects an appropriate View to handle the request by comparing the request media type(s) with the media type (also known as Content-Type) supported by the View associated with each of its ViewResolvers. The first View in the list that has a compatible Content-Type returns the representation to the client. If a compatible view cannot be supplied by the ViewResolver chain, then the list of views specified through the DefaultViews property will be consulted. This latter option is appropriate for singleton Views that can render an appropriate representation of the current resource regardless of the logical view name. The Accept header may include wild cards, for example text/*, in which case a View whose Content-Type was text/xml is a compatible match.

ContentNegotiatingViewResolver选择适当的视图来处理请求通过比较请求的媒体类型(也包括Content-Type)通过视图支持连接每个视图解析器。第一个视图在列表中有兼容的Content-Type通过客户端来返回。如果一个兼容的视图不能通过ViewResolver链来提供,则视图的列表通过DefaultViews属性指定的视图将被处理。后面的选项适合于单例视图可以被当前的资源解析通过逻辑视图名。接受头可以包含通配符,例如text/*,代表Content-Typetext/xml也是匹配的。

 

To support custom resolution of a view based on a file extension, use a ContentNegotiationManager: see Section 22.16.6, Content Negotiation.

为了支持自定义的视图解析基于一个文件扩展,使用ContentNegotiationManager:见章节22.16.6,“内容协商”。

 

Here is an example configuration of a ContentNegotiatingViewResolver:

这是一个例子有关ContentNegotiatingViewResolver

 

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">

    <property name="viewResolvers">

        <list>

            <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>

            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

                <property name="prefix" value="/WEB-INF/jsp/"/>

                <property name="suffix" value=".jsp"/>

            </bean>

        </list>

    </property>

    <property name="defaultViews">

        <list>

            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

        </list>

    </property>

</bean>

 

<bean id="content" class="com.foo.samples.rest.SampleContentAtomView"/>

 

The InternalResourceViewResolver handles the translation of view names and JSP pages, while the BeanNameViewResolver returns a view based on the name of a bean. (See "Resolving views with the ViewResolver interface" for more details on how Spring looks up and instantiates a view.) In this example, the content bean is a class that inherits from AbstractAtomFeedView, which returns an Atom RSS feed. For more information on creating an Atom Feed representation, see the section Atom Views.

InternalResourceViewResolver处理视图名和jsp页面的翻译,BeanNameViewResolver返回一个视图基于bean的名字。(见“使用ViewResolver接口来解析视图”来了解更多的细节有关spring如何查找并实例化视图。)在这个例子中,上下文的bean是一个类继承自AbstractAtomFeedView,返回一个AtomRSSfeed。有关的更多的信息关于创建一个AtomFeed表现,见章节Atom视图。

 

In the above configuration, if a request is made with an .html extension, the view resolver looks for a view that matches the text/html media type. The InternalResourceViewResolver provides the matching view for text/html. If the request is made with the file extension .atom, the view resolver looks for a view that matches the application/atom+xml media type. This view is provided by the BeanNameViewResolver that maps to the SampleContentAtomView if the view name returned is content. If the request is made with the file extension .json, the MappingJackson2JsonView instance from the DefaultViews list will be selected regardless of the view name. Alternatively, client requests can be made without a file extension but with the Accept header set to the preferred media-type, and the same resolution of request to views would occur.

在上面的配置中,如果一个请求通过.html作为后缀,视图解析将寻找视图匹配text/html的媒体类型。InternalResourceViewResolver提供视图匹配对于text/html。如果请求使用了扩展名为.atom,视图解析器将查找媒体类型为application/atom+xml的视图来解析。视图通过BeanNameViewResolver来提供匹配SampleContentAtomView如果视图名返回是一个content。如果请求的是.json作为后缀,则MappingJackson2JsonView实例来自DefaultViews列表将选择相应的视图名。作为替代,客户端请求可以不需要通过扩展名来实现但是接受头设置为偏向的媒体类型并且对于请求相同的解析会发生。

 

[Note]

注意

 

If `ContentNegotiatingViewResolvers list of ViewResolvers is not configured explicitly, it automatically uses any ViewResolvers defined in the application context.

如果ContentNegotiatingViewResolverViewResolvers的列表没有被明确配置,自动使用任何ViewResolvers定义在应用上下文中。

 

The corresponding controller code that returns an Atom RSS feed for a URI of the form http://localhost/content.atom or http://localhost/content with an Accept header of application/atom+xml is shown below.

相应的控制器代码返回一个AtomRSSfeed对于一个URI来自http://localhost/content.atomhttp://localhost/content如果接受头是application/atom+xml被展示如下。

 

@Controller

public class ContentController {

 

    private List<SampleContent> contentList = new ArrayList<SampleContent>();

 

    @GetMapping("/content")

    public ModelAndView getContent() {

        ModelAndView mav = new ModelAndView();

        mav.setViewName("content");

        mav.addObject("sampleContentList", contentList);

        return mav;

    }

 

}

 

22.6 Using flash attributes

使用flash属性

 

Flash attributes provide a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting — for example, the Post/Redirect/Get pattern. Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and removed immediately.

Flash属性提供了一种方式对于请求来存储属性用于在另一个中使用。这通常需要打不过转发的时候————例如,Post/Redirect/Get的模式。Flash属性被临时保存在转发之前(通常在session中)使得对于请求可见在转发和直接删除之后。

 

Spring MVC has two main abstractions in support of flash attributes. FlashMap is used to hold flash attributes while FlashMapManager is used to store, retrieve, and manage FlashMap instances.

springmvc有两个主要的抽象来支持flash属性。FlashMap用于保存flash属性当使用FlashMapManager来存储、获取和关联FlashMap的实例时。

 

Flash attribute support is always "on" and does not need to enabled explicitly although if not used, it never causes HTTP session creation. On each request there is an "input" FlashMap with attributes passed from a previous request (if any) and an "output" FlashMap with attributes to save for a subsequent request. Both FlashMap instances are accessible from anywhere in Spring MVC through static methods in RequestContextUtils.

Flash属性支持是设置为on的不需要明确被允许尽管他没有被使用,他不会引起http会话的创建。对于每个请求有输入的FlashMap来传递属性来自之前的请求(如果有的话)和输出的FlashMap用于保存对于子请求。两个FlashMap实例可以从各个位置访问在springmvc中通过RequestContextUtils的静态方法。

 

Annotated controllers typically do not need to work with FlashMap directly. Instead an @RequestMapping method can accept an argument of type RedirectAttributes and use it to add flash attributes for a redirect scenario. Flash attributes added via RedirectAttributes are automatically propagated to the "output" FlashMap. Similarly, after the redirect, attributes from the "input" FlashMap are automatically added to the Model of the controller serving the target URL.

注解控制器通常不需要直接和FlashMap来工作。作为代替一个@RequestMapping方法可以接受一个RedirectAttributes类型的参数并且使用它来添加flash属性对于转发场景。flash属性通过RedirectAttributes来添加被自动传递给输出的FlashMap。相似的,在转发之后,来自输入FlashMap的属性自动添加到控制器的model中服务于目标的URL

 

Matching requests to flash attributes

匹配请求给flash的属性

 

The concept of flash attributes exists in many other Web frameworks and has proven to be exposed sometimes to concurrency issues. This is because by definition flash attributes are to be stored until the next request. However the very "next" request may not be the intended recipient but another asynchronous request (e.g. polling or resource requests) in which case the flash attributes are removed too early.

flash属性的内容在许多其他的web框架并且证明有时存在并发的问题。这是因为通过定义flash属性存储直到下一个请求。然而下一个请求可能不是那个正确的接收这但是另一个异步的请求(例如,查询或资源请求)由于flash属性被过早的删除了。

 

To reduce the possibility of such issues, RedirectView automatically "stamps" FlashMap instances with the path and query parameters of the target redirect URL. In turn the default FlashMapManager matches that information to incoming requests when looking up the "input" FlashMap.

为了减少这些问题的可能,RedirectView自动“粘贴”FlashMap实例和路径和请求参数对于目标转发的URL。为了返回默认的FlashMapManager匹配信息对于输入的请求当查找输入的FlashMap时。

 

This does not eliminate the possibility of a concurrency issue entirely but nevertheless reduces it greatly with information that is already available in the redirect URL. Therefore the use of flash attributes is recommended mainly for redirect scenarios .

这不能消除并发问题的可能性但是减少他的信息对于转发的URL可行。因此使用flash属性被推荐对于转发的场景中。

 

22.7 Building URIs

构建URI

 

Spring MVC provides a mechanism for building and encoding a URI using UriComponentsBuilder and UriComponents.

springmvc提供了一个策略用于构建和编码URI使用UriComponentsBuilderUriComponents

 

For example you can expand and encode a URI template string:

例如你可以扩展并编码一个URI模板字符串:

 

UriComponents uriComponents = UriComponentsBuilder.fromUriString(

        "http://example.com/hotels/{hotel}/bookings/{booking}").build();

 

URI uri = uriComponents.expand("42", "21").encode().toUri();

 

Note that UriComponents is immutable and the expand() and encode() operations return new instances if necessary.

注意UriComponents是不变的并且expandencode操作返回一个新的实例如果需要的话。

 

You can also expand and encode using individual URI components:

你也可以扩展和编码使用独立的URI组件:

 

UriComponents uriComponents = UriComponentsBuilder.newInstance()

        .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()

        .expand("42", "21")

        .encode();

 

In a Servlet environment the ServletUriComponentsBuilder sub-class provides static factory methods to copy available URL information from a Servlet requests:

在一个Servlet的环境中,ServletUriComponentsBuilder子类提供静态工厂方法来复制URL信息来自Servlet的请求:

 

HttpServletRequest request = ...

 

// Re-use host, scheme, port, path and query string

// Replace the "accountId" query param

 

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request)

        .replaceQueryParam("accountId", "{id}").build()

        .expand("123")

        .encode();

 

Alternatively, you may choose to copy a subset of the available information up to and including the context path:

作为代替,你可以选择复制一个子集对于可用的信息并包含上下文路径:

 

// Re-use host, port and context path

// Append "/accounts" to the path

 

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromContextPath(request)

        .path("/accounts").build()

 

Or in cases where the DispatcherServlet is mapped by name (e.g. /main/*), you can also have the literal part of the servlet mapping included:

或者由于DispatcherServlet通过名称匹配(例如,/main/*),你也可以有Servlet匹配包括文字的部分:

 

// Re-use host, port, context path

// Append the literal part of the servlet mapping to the path

// Append "/accounts" to the path

 

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromServletMapping(request)

        .path("/accounts").build()

 

22.7.1 Building URIs to Controllers and methods

对于控制器和方法构建URI

 

Spring MVC also provides a mechanism for building links to controller methods. For example, given:

springmvc提供了一个策略用于构建链接到控制器方法。例如,给定:

 

@Controller

@RequestMapping("/hotels/{hotel}")

public class BookingController {

 

    @GetMapping("/bookings/{booking}")

    public String getBooking(@PathVariable Long booking) {

 

    // ...

    }

}

 

You can prepare a link by referring to the method by name:

你可以准备一个链接通过名字来引用一个方法:

 

UriComponents uriComponents = MvcUriComponentsBuilder

    .fromMethodName(BookingController.class, "getBooking", 21).buildAndExpand(42);

 

URI uri = uriComponents.encode().toUri();

 

In the above example we provided actual method argument values, in this case the long value 21, to be used as a path variable and inserted into the URL. Furthermore, we provided the value 42 in order to fill in any remaining URI variables such as the "hotel" variable inherited from the type-level request mapping. If the method had more arguments you can supply null for arguments not needed for the URL. In general only @PathVariable and @RequestParam arguments are relevant for constructing the URL.

在上面的例子中我们提供了实际的方法参数值,在这个例子中长整型值21将被使用作为一个路径变量到URL中。此外,我们提供了值42用于填充任何剩余的URI变量例如“hotel”变量继承自类型级别的请求匹配。如果方法有多个参数你可以提供null对于参数不需要URL。通常只有@PathVariable@RequestParam参数和构建URL相关。

 

There are additional ways to use MvcUriComponentsBuilder. For example you can use a technique akin to mock testing through proxies to avoid referring to the controller method by name (the example assumes static import of MvcUriComponentsBuilder.on):

还有其他的方式来使用MvcUriComponentsBuilder。例如你可以使用一种技术akin来模拟测试通过代理来避免引用控制器方法通过名字(例子假设静态引入了MvcUriComponentsBuilder.on):

 

UriComponents uriComponents = MvcUriComponentsBuilder

    .fromMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

 

URI uri = uriComponents.encode().toUri();

 

The above examples use static methods in MvcUriComponentsBuilder. Internally they rely on ServletUriComponentsBuilder to prepare a base URL from the scheme, host, port, context path and servlet path of the current request. This works well in most cases, however sometimes it may be insufficient. For example you may be outside the context of a request (e.g. a batch process that prepares links) or perhaps you need to insert a path prefix (e.g. a locale prefix that was removed from the request path and needs to be re-inserted into links).

上面的例如使用了MvcUriComponentsBuilder中的静态方法。作为代替他们依赖于ServletUriComponentsBuilder来准备基础的URL来自scheme、主机、端口、上下文路径和当前请求的Servlet路径。在大部分情况下工作良好,然而有时他可能不够充足。例如你可以在上下文之外的请求(例如一个批量程序来准备链接)或者你需要插入一个路径前缀(例如一个位置前缀在请求路径中被取消并且需要重新插入到链接中)。

 

For such cases you can use the static "fromXxx" overloaded methods that accept a UriComponentsBuilder to use base URL. Or you can create an instance of MvcUriComponentsBuilder with a base URL and then use the instance-based "withXxx" methods. For example:

对于这样的请求你可以使用静态的"fromXxx"来覆盖方法接收一个UriComponentsBuilder用于使用基本的URL。或者你可以创建一个MvcUriComponentsBuilder的实例使用一个基本的URL并且使用基于实例的"withXxx"方法。例如:

 

UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath().path("/en");

MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);

builder.withMethodCall(on(BookingController.class).getBooking(21)).buildAndExpand(42);

 

URI uri = uriComponents.encode().toUri();

 

22.7.2 Building URIs to Controllers and methods from views

为来自视图的控制器和方法构建URI

 

You can also build links to annotated controllers from views such as JSP, Thymeleaf, FreeMarker. This can be done using the fromMappingName method in MvcUriComponentsBuilder which refers to mappings by name.

你也可以构建链接来注解控制器来自视图如JSPThymeleafFreeMarker。可以使用MvcUriComponentsBuilder中的fromMappingName方法来实现用名字来实现引用。

 

Every @RequestMapping is assigned a default name based on the capital letters of the class and the full method name. For example, the method getFoo in class FooController is assigned the name "FC#getFoo". This strategy can be replaced or customized by creating an instance of HandlerMethodMappingNamingStrategy and plugging it into your RequestMappingHandlerMapping. The default strategy implementation also looks at the name attribute on @RequestMapping and uses that if present. That means if the default mapping name assigned conflicts with another (e.g. overloaded methods) you can assign a name explicitly on the @RequestMapping.

每个@RequestMapping和默认名连接基于首字母大写的类和全部的方法名。例如,FooController中的getFoo方法表示为"FC#getFoo"。这个策略可以被替换或自定义通过创建一个HandlerMethodMappingNamingStrategy的实例和将其插件到你的RequestMappingHandlerMapping中。默认的策略实现也查找name属性在@RequestMapping上并且使用如果存在的话。这意味着如果默认匹配名和其他冲突(例如覆盖方法)你可以在@RequestMapping上明确指定一个名字。

 

[Note]

注意

 

The assigned request mapping names are logged at TRACE level on startup.

指定请求匹配名在启动时是在TRACE级别的。

 

The Spring JSP tag library provides a function called mvcUrl that can be used to prepare links to controller methods based on this mechanism.

springjsp标签库提供了一个功能名字为mvcUrl可以被使用用于准备连接到控制器方法基于这种策略。

 

For example given:

例如给定的例子:

 

@RequestMapping("/people/{id}/addresses")

public class PersonAddressController {

 

    @RequestMapping("/{country}")

    public HttpEntity getAddress(@PathVariable String country) { ... }

}

 

You can prepare a link from a JSP as follows:

你可以准备一个链接来自jsp如下:

 

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

...

<a href="${s:mvcUrl('PAC#getAddress').arg(0,'US').buildAndExpand('123')}">Get Address</a>

 

The above example relies on the mvcUrl JSP function declared in the Spring tag library (i.e. META-INF/spring.tld). For more advanced cases (e.g. a custom base URL as explained in the previous section), it is easy to define your own function, or use a custom tag file, in order to use a specific instance of MvcUriComponentsBuilder with a custom base URL.

上面的例子依赖于mvcUrlJSP功能定义在spring的标签库中(也就是,META-INF/spring.tld)。对于更高级的案例(例如,一个基于URL的自定义在之前的章节中解释过),在你自己的函数中定义是很简单的,或使用一个自定义标签文件,为了使用特定的MvcUriComponentsBuilder实例使用一个自定义的URL

 

22.8 Using locales

使用locales

 

Most parts of Springs architecture support internationalization, just as the Spring web MVC framework does. DispatcherServlet enables you to automatically resolve messages using the clients locale. This is done with LocaleResolver objects.

大部分spring的架构支持国际化,就像springwebmvc框架一样。DispatcherServlet允许你自动处理信息使用客户端的locale。这是通过LocaleResolver来实现的。

 

When a request comes in, the DispatcherServlet looks for a locale resolver, and if it finds one it tries to use it to set the locale. Using the RequestContext.getLocale() method, you can always retrieve the locale that was resolved by the locale resolver.

当收到一个请求,DispatcherServlet需找一个locale解析器并且如果定义了一个将试图使用它来设置locale。使用RequestContext.getLocale()方法,你可以获取本地解析器收到的locale

 

In addition to automatic locale resolution, you can also attach an interceptor to the handler mapping (see Section 22.4.1, Intercepting requests with a HandlerInterceptorfor more information on handler mapping interceptors) to change the locale under specific circumstances, for example, based on a parameter in the request.

此外为了自动完成locale解析,你可以添加一个拦截器对于处理器匹配(见章节22.4.1,“使用HandlerInterceptor”来拦截请求”了解更多信息有关处理器匹配拦截器)来改变locale通过特定的情况,例如,基于请求中的一个参数。

 

Locale resolvers and interceptors are defined in the org.springframework.web.servlet.i18n package and are configured in your application context in the normal way. Here is a selection of the locale resolvers included in Spring.

locale解析和拦截器被定义在org.springframework.web.servlet.i18n包中并且被配置在你的应用上下文中以正常的方式。下面是包含在spring中可供选择的locale解析器。

 

22.8.1 Obtaining Time Zone Information

获取时区信息

 

In addition to obtaining the clients locale, it is often useful to know their time zone. The LocaleContextResolver interface offers an extension to LocaleResolver that allows resolvers to provide a richer LocaleContext, which may include time zone information.

此外为了获得客户端的locale,比较有用的方式是了解他们的时区。LocaleContextResolver接口提供了一个LocaleResolver的扩展允许解析器提供一个较为丰富的LocaleContext,可以包括时区信息。

 

When available, the users TimeZone can be obtained using the RequestContext.getTimeZone() method. Time zone information will automatically be used by Date/Time Converter and Formatter objects registered with Springs ConversionService.

如果可以,用户的时区可以使用RequestContext.getTimeZone()方法来获取。时区信息将自动使用Date/Time的转换器和Formatter注册在springConversionService中。

 

22.8.2 AcceptHeaderLocaleResolver

 

This locale resolver inspects the accept-language header in the request that was sent by the client (e.g., a web browser). Usually this header field contains the locale of the clients operating system. Note that this resolver does not support time zone information.

locale解析查看accept-language头信息在客户端发送的请求中(例如,一个web浏览器)。通常头信息域包含客户端操作系统的locale。注意这个解析器不支持时区信息。

 

22.8.3 CookieLocaleResolver

 

This locale resolver inspects a Cookie that might exist on the client to see if a Locale or TimeZone is specified. If so, it uses the specified details. Using the properties of this locale resolver, you can specify the name of the cookie as well as the maximum age. Find below an example of defining a CookieLocaleResolver.

locale解析器查看cookie如果存在于客户端的话来检查其中是否定义了一个LocalTimeZone。如果有则使用指定的内容。使用locale解析器中的属性,你可以定义cookie使用的name来指定存活的最长时间。查看定义在CookieLocaleResolver中的下面的例子。

 

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

 

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

 

    <!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->

    <property name="cookieMaxAge" value="100000"/>

 

</bean>

 

Table 22.4. CookieLocaleResolver properties

CookieLocaleResolver属性

Property

属性

Default

默认值

Description

描述

cookieName

classname + LOCALE

The name of the cookie

cookie的名字

cookieMaxAge

Integer.MAX_INT

The maximum time a cookie will stay persistent on the client. If -1 is specified, the cookie will not be persisted; it will only be available until the client shuts down their browser.

cookie在客户端存活的最大时间。如果定义为-1cookie将不会持久化,在客户端关闭浏览器后失效

cookiePath

/

Limits the visibility of the cookie to a certain part of your site. When cookiePath is specified, the cookie will only be visible to that path and the paths below it.

限制cookie的可见性对于部分页面。当定义了cookiepathcookie将支持被某些路径看到。

 

22.8.4 SessionLocaleResolver

 

The SessionLocaleResolver allows you to retrieve Locale and TimeZone from the session that might be associated with the users request. In contrast to CookieLocaleResolver, this strategy stores locally chosen locale settings in the Servlet containers HttpSession. As a consequence, those settings are just temporary for each session and therefore lost when each session terminates.

SessionLocaleResolver允许你获得locale和失去来自session和客户的请求相关。与CookieLocaleResolver产生对于,策略在本地存储设置在Servlet容器的HttpSession中。因此,这些设置只是对于每个session来说是临时的并且在session关闭后失效。

 

Note that there is no direct relationship with external session management mechanisms such as the Spring Session project. This SessionLocaleResolver will simply evaluate and modify corresponding HttpSession attributes against the current HttpServletRequest.

注意没有直接的关系对于外部的session管理策略例如springsessionobjectSessionLocaleResolver只是简单的处理和修改其中的数据对于当前的HttpServletRequest

 

22.8.5 LocaleChangeInterceptor

 

You can enable changing of locales by adding the LocaleChangeInterceptor to one of the handler mappings (see Section 22.4, Handler mappings). It will detect a parameter in the request and change the locale. It calls setLocale() on the LocaleResolver that also exists in the context. The following example shows that calls to all *.view resources containing a parameter named siteLanguage will now change the locale. So, for example, a request for the following URL, http://www.sf.net/home.view?siteLanguage=nl will change the site language to Dutch.

你可以允许locale的改变通过添加LocaleChangeInterceptor对于其中一个处理请求(见章节22.4,“处理器设置”)。这将导致请求中的参数改变locale。他调用LocaleResolver中的setLocale方法存在于上下文中。下面的例子展示了所有对于*.view资源的调用包含一个名字siteLanguage将改变locale。例如,对于下面的URLhttp://www.sf.net/home.view?siteLanguage=nl将改变站点的语言为荷兰语。

 

<bean id="localeChangeInterceptor"

        class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">

    <property name="paramName" value="siteLanguage"/>

</bean>

 

<bean id="localeResolver"

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

 

<bean id="urlMapping"

        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

    <property name="interceptors">

        <list>

            <ref bean="localeChangeInterceptor"/>

        </list>

    </property>

    <property name="mappings">

        <value>/**/*.view=someController</value>

    </property>

</bean>

 

22.9 Using themes

使用主题

 

22.9.1 Overview of themes

主题概览

 

You can apply Spring Web MVC framework themes to set the overall look-and-feel of your application, thereby enhancing user experience. A theme is a collection of static resources, typically style sheets and images, that affect the visual style of the application.

你可以应用springwebmvc框架来设置你应用的外观,允许增强用户体验。一个主题是一些静态资源的集合,通常包括样式表和图片以及对于视觉效果有影响的部分。

 

22.9.2 Defining themes

定义主题

 

To use themes in your web application, you must set up an implementation of the org.springframework.ui.context.ThemeSource interface. The WebApplicationContext interface extends ThemeSource but delegates its responsibilities to a dedicated implementation. By default the delegate will be an org.springframework.ui.context.support.ResourceBundleThemeSource implementation that loads properties files from the root of the classpath. To use a custom ThemeSource implementation or to configure the base name prefix of the ResourceBundleThemeSource, you can register a bean in the application context with the reserved name themeSource. The web application context automatically detects a bean with that name and uses it.

为了在你的web应用中使用主题,你必须设置org.springframework.ui.context.ThemeSource接口的实现。WebApplicationContext接口扩展了ThemeSource但是作为代表实现。通过默认的委派将会是org.springframework.ui.context.support.ResourceBundleThemeSource实现加载属性文件来自类路径的根。为了使用自定义的ThemeSource实现或配置ResourceBundleThemeSource的基本的名称前缀,你可以注册一个bean在应用上下文中名字为themeSourceweb应用上下文自动探测bean使用的名字并进行使用。

 

When using the ResourceBundleThemeSource, a theme is defined in a simple properties file. The properties file lists the resources that make up the theme. Here is an example:

当使用ResourceBundleThemeSource,一个主题被定义在简单的属性文件中。属性文件列出了组合主题的资源。这是一个例子:

 

styleSheet=/themes/cool/style.css

background=/themes/cool/img/coolBg.jpg

 

The keys of the properties are the names that refer to the themed elements from view code. For a JSP, you typically do this using the spring:theme custom tag, which is very similar to the spring:message tag. The following JSP fragment uses the theme defined in the previous example to customize the look and feel:

属性的关键字引用了主题的元素根据视图代码。对于一个jsp,你通常使用spring:theme自定义标签,和spring:message标签很相近。下面的jsp片段使用了主题定义在之前的例子中用于自定义外观:

 

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>

<html>

    <head>

        <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>

    </head>

    <body style="background=<spring:theme code='background'/>">

        ...

    </body>

</html>

 

By default, the ResourceBundleThemeSource uses an empty base name prefix. As a result, the properties files are loaded from the root of the classpath. Thus you would put the cool.properties theme definition in a directory at the root of the classpath, for example, in /WEB-INF/classes. The ResourceBundleThemeSource uses the standard Java resource bundle loading mechanism, allowing for full internationalization of themes. For example, we could have a /WEB-INF/classes/cool_nl.properties that references a special background image with Dutch text on it.

默认的,ResourceBundleThemeSource使用一个空的名称前缀。因此,属性文件加载来自类路径的根。你希望放置cool.properties主题定义在类路径的根位置,例如在/WEB-INF/classes中。ResourceBundleThemeSource使用标准的java资源绑定加载策略,允许主题的全部国际化。例如,我们有一个/WEB-INF/classes/cool_nl.properties引用一个指定的背景且附带荷兰语。

 

22.9.3 Theme resolvers

主题解析

 

After you define themes, as in the preceding section, you decide which theme to use. The DispatcherServlet will look for a bean named themeResolver to find out which ThemeResolver implementation to use. A theme resolver works in much the same way as a LocaleResolver. It detects the theme to use for a particular request and can also alter the requests theme. The following theme resolvers are provided by Spring:

在你定义主题之后,在之前的章节,你决定了需要使用的主题。DispatcherServlet将查找themeResolver为名字的bean来找到使用哪一个ThemeResolver实现。一个主题解析器将作为LocaleResolver解析器来运行。他探测主题对于特定的请求并且也可以在请求主题之后。下面是spring提供的主题解析器:

 

Table 22.5. ThemeResolver implementations

ThemeResolver的实现

Class

Description

描述

FixedThemeResolver

Selects a fixed theme, set using the defaultThemeName property.

选择一个固定的主题,设置使用defaultThemeName属性

SessionThemeResolver

The theme is maintained in the users HTTP session. It only needs to be set once for each session, but is not persisted between sessions.

主题包含在用户的httpsession中。只需要对session设置异常,但是当session关闭时会消失

CookieThemeResolver

The selected theme is stored in a cookie on the client.

选择的主题以cookie的方式保存在客户端

Spring also provides a ThemeChangeInterceptor that allows theme changes on every request with a simple request parameter.

spring也提供了一个ThemeChangeInterceptor允许监听对于简单请求中主题的变化。

 

22.10 Springs multipart (file upload) support

spring的多部分(文件上传)支持

 

22.10.1 Introduction

介绍

 

Springs built-in multipart support handles file uploads in web applications. You enable this multipart support with pluggable MultipartResolver objects, defined in the org.springframework.web.multipart package. Spring provides one MultipartResolver implementation for use with Commons FileUpload and another for use with Servlet 3.0 multipart request parsing.

spring内置的多部分支持处理文件上传在web应用中。你允许这个多部分支持通过使用MultipartResolverobject,定义在org.springframework.web.multipart包中。spring提供了MultipartResolver实现对于使用普通的文件上传和其他的用于servlet3.0的多部分请求解析。

 

By default, Spring does no multipart handling, because some developers want to handle multiparts themselves. You enable Spring multipart handling by adding a multipart resolver to the web applications context. Each request is inspected to see if it contains a multipart. If no multipart is found, the request continues as expected. If a multipart is found in the request, the MultipartResolver that has been declared in your context is used. After that, the multipart attribute in your request is treated like any other attribute.

默认的,spring没有多部分的处理,应为一些开发者希望自行处理多部分。你允许spring的多部分处理通过添加一个多部分处理器对于web应用的上下文。每个请求来检查如果他包含多部分。如果没有多部分被找到,请求将被期望。如果在请求中找到了多部分,MultipartResolver将被定义在你使用的上下文中。之后,你请求中的多部分属性就像其他属性一样被处理。

 

22.10.2 Using a MultipartResolver with Commons FileUpload

使用MultipartResolver来处理普通的文件上传

 

The following example shows how to use the CommonsMultipartResolver:

下面的例子展示了如何使用CommonsMultipartResolver

 

<bean id="multipartResolver"

        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

 

    <!-- one of the properties available; the maximum file size in bytes -->

    <property name="maxUploadSize" value="100000"/>

 

</bean>

 

Of course you also need to put the appropriate jars in your classpath for the multipart resolver to work. In the case of the CommonsMultipartResolver, you need to use commons-fileupload.jar.

当然你也需要在你的classpath中放置合适的jar文件来解析相应的工作。对于CommonsMultipartResolver,你需要使用commons-fileupload.jar

 

When the Spring DispatcherServlet detects a multi-part request, it activates the resolver that has been declared in your context and hands over the request. The resolver then wraps the current HttpServletRequest into a MultipartHttpServletRequest that supports multipart file uploads. Using the MultipartHttpServletRequest, you can get information about the multiparts contained by this request and actually get access to the multipart files themselves in your controllers.

springDispatcherServlet探测到一个多部分的请求,他将激活处理定义在你的上下文中并且处理请求。解析器处理当前的HttpServletRequestMultipartHttpServletRequest中支持多部分的文件上传。使用MultipartHttpServletRequest,你可以获得信息对于多部分包括请求和实际获得访问多部分文件本身在你的控制器中。

 

22.10.3 Using a MultipartResolver with Servlet 3.0

使用Servlet3.0中的MultipartResolver

 

In order to use Servlet 3.0 based multipart parsing, you need to mark the DispatcherServlet with a "multipart-config" section in web.xml, or with a javax.servlet.MultipartConfigElement in programmatic Servlet registration, or in case of a custom Servlet class possibly with a javax.servlet.annotation.MultipartConfig annotation on your Servlet class. Configuration settings such as maximum sizes or storage locations need to be applied at that Servlet registration level as Servlet 3.0 does not allow for those settings to be done from the MultipartResolver.

为了使用Servlet3.0基于多部分的解析,你需要在web.xml中标记DispatcherServlet使用"multipart-config"节或在Servlet注册中使用javax.servlet.MultipartConfigElement或自定义Servlet类使用javax.servlet.annotation.MultipartConfig注解在你的Servlet类上。配置设置例如存储位置的最大值需要被应用于Servlet注册级别作为Servlet3.0不需要允许这些设置使用MultipartResolver来实现。

 

Once Servlet 3.0 multipart parsing has been enabled in one of the above mentioned ways you can add the StandardServletMultipartResolver to your Spring configuration:

一旦Servlet3.0多部分解析被激活根据上面提到的方法你可以添加StandardServletMultipartResolver到你的spring的配置中:

 

<bean id="multipartResolver"

        class="org.springframework.web.multipart.support.StandardServletMultipartResolver">

</bean>

 

22.10.4 Handling a file upload in a form

处理表单中的文件上传

 

After the MultipartResolver completes its job, the request is processed like any other. First, create a form with a file input that will allow the user to upload a form. The encoding attribute ( enctype="multipart/form-data") lets the browser know how to encode the form as multipart request:

MultipartResolver完成他的工作,请求就像其他的一样被处理。首先,创建一个表单带有文件输入将允许用户来上传一个表单。编码属性( enctype="multipart/form-data")使得浏览器知道如何编码表单作为多部分请求:

 

<html>

    <head>

        <title>Upload a file please</title>

    </head>

    <body>

        <h1>Please upload a file</h1>

        <form method="post" action="/form" enctype="multipart/form-data">

            <input type="text" name="name"/>

            <input type="file" name="file"/>

            <input type="submit"/>

        </form>

    </body>

</html>

 

The next step is to create a controller that handles the file upload. This controller is very similar to a normal annotated @Controller, except that we use MultipartHttpServletRequest or MultipartFile in the method parameters:

下一步是创建一个控制器处理文件上传。这个控制器是和普通的注解@Controller很相似的,除了我们使用MultipartHttpServletRequestMultipartFile在方法参数中:

 

@Controller

public class FileUploadController {

 

    @PostMapping("/form")

    public String handleFormUpload(@RequestParam("name") String name,

            @RequestParam("file") MultipartFile file) {

 

        if (!file.isEmpty()) {

            byte[] bytes = file.getBytes();

            // store the bytes somewhere

            return "redirect:uploadSuccess";

        }

 

        return "redirect:uploadFailure";

    }

 

}

 

Note how the @RequestParam method parameters map to the input elements declared in the form. In this example, nothing is done with the byte[], but in practice you can save it in a database, store it on the file system, and so on.

注意@RequestParam方法参数如何匹配输入元素定义在表单中。在这个例子中对于字节数组你可以将其保存在数据库中,存储在文件系统等等。

 

When using Servlet 3.0 multipart parsing you can also use javax.servlet.http.Part for the method parameter:

当使用Servlet3.0的多部分解析你也可以使用javax.servlet.http.Part用于方法参数:

 

@Controller

public class FileUploadController {

 

    @PostMapping("/form")

    public String handleFormUpload(@RequestParam("name") String name,

            @RequestParam("file") Part file) {

 

        InputStream inputStream = file.getInputStream();

        // store bytes from uploaded file somewhere

 

        return "redirect:uploadSuccess";

    }

 

}

 

22.10.5 Handling a file upload request from programmatic clients

处理来自编程客户端的文件上传请求

 

Multipart requests can also be submitted from non-browser clients in a RESTful service scenario. All of the above examples and configuration apply here as well. However, unlike browsers that typically submit files and simple form fields, a programmatic client can also send more complex data of a specific content type — for example a multipart request with a file and second part with JSON formatted data:

多部分请求也可以被提交来自非浏览器客户端在RESTful服务的场景中。所有上面的例子和配置也同样适用。然而不像浏览器一样通常提交文件和简单的表单域,一个编程客户端也可以发送复杂的数据对于特定的内容类型————例如一个多部分请求带有一个文件和另一部分的JSON的格式化数据:

 

POST /someUrl

Content-Type: multipart/mixed

 

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp

Content-Disposition: form-data; name="meta-data"

Content-Type: application/json; charset=UTF-8

Content-Transfer-Encoding: 8bit

 

{

"name": "value"

}

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp

Content-Disposition: form-data; name="file-data"; filename="file.properties"

Content-Type: text/xml

Content-Transfer-Encoding: 8bit

... File Data ...

 

You could access the part named "meta-data" with a @RequestParam("meta-data") String metadata controller method argument. However, you would probably prefer to accept a strongly typed object initialized from the JSON formatted data in the body of the request part, very similar to the way @RequestBody converts the body of a non-multipart request to a target object with the help of an HttpMessageConverter.

你可以使用@RequestParam("meta-data")的控制器方法参数来访问名字为"meta-data"的部分。然而,你可能需要接收一个强类型的object来自json的格式化数据在请求部分的体重,类似于@RequestBody转换non-multipart请求为目标object根据HttpMessageConverter的帮助。

 

You can use the @RequestPart annotation instead of the @RequestParam annotation for this purpose. It allows you to have the content of a specific multipart passed through an HttpMessageConverter taking into consideration the 'Content-Type' header of the multipart:

你可以使用@RequestPart注解代替@RequestParam来实现这个目的。他允许你有指定多部分传递通过HttpMessageConverter需要考虑多部分中的'Content-Type'头信息:

 

@PostMapping("/someUrl")

public String onSubmit(@RequestPart("meta-data") MetaData metadata,

        @RequestPart("file-data") MultipartFile file) {

 

    // ...

 

}

 

Notice how MultipartFile method arguments can be accessed with @RequestParam or with @RequestPart interchangeably. However, the @RequestPart("meta-data") MetaData method argument in this case is read as JSON content based on its 'Content-Type' header and converted with the help of the MappingJackson2HttpMessageConverter.

注意MultipartFile方法参数如何可以被访问通过@RequestParam@RequestPart。然而,@RequestPart("meta-data")元数据方法参数在这个例子中被解释为JSON内容基于他的'Content-Type'头和转换通过MappingJackson2HttpMessageConverter的帮助。

 

22.11 Handling exceptions

处理异常

 

22.11.1 HandlerExceptionResolver

 

Spring HandlerExceptionResolver implementations deal with unexpected exceptions that occur during controller execution. A HandlerExceptionResolver somewhat resembles the exception mappings you can define in the web application descriptor web.xml. However, they provide a more flexible way to do so. For example they provide information about which handler was executing when the exception was thrown. Furthermore, a programmatic way of handling exceptions gives you more options for responding appropriately before the request is forwarded to another URL (the same end result as when you use the Servlet specific exception mappings).

springHandlerExceptionResolver实现处理非期望异常发生于控制器的执行过程中。HandlerExceptionResolver有时解释异常匹配你可以定义在web应用描述文件web.xml中。然而他提供了更加简单的方式来实现。例如他们提供信息关于处理器如何执行当异常被抛出的时候。此外,编程处理异常给了你更多的选择对于响应的处理在请求转发为另一个URL之前(相同的记过当你使用Servlet特定的异常匹配)。

 

Besides implementing the HandlerExceptionResolver interface, which is only a matter of implementing the resolveException(Exception, Handler) method and returning a ModelAndView, you may also use the provided SimpleMappingExceptionResolver or create @ExceptionHandler methods. The SimpleMappingExceptionResolver enables you to take the class name of any exception that might be thrown and map it to a view name. This is functionally equivalent to the exception mapping feature from the Servlet API, but it is also possible to implement more finely grained mappings of exceptions from different handlers. The @ExceptionHandler annotation on the other hand can be used on methods that should be invoked to handle an exception. Such methods may be defined locally within an @Controller or may apply to many @Controller classes when defined within an @ControllerAdvice class. The following sections explain this in more detail.

此外实现HandlerExceptionResolver接口,只是resolveException实现的问题(异常,处理器)方法并且返回一个ModelAndView,你也可以提供SimpleMappingExceptionResolver或创建@ExceptionHandler方法。SimpleMappingExceptionResolver允许你定义异常的名可以被抛出并且匹配一个视图名。这个功能和异常匹配特性来自ServletAPI是相同的,但是他也可以更加简单的实现对于异常的匹配来自不同的处理器。@ExceptionHandler注解在另一方面可以用于方法上用于处理异常。例如方法可以被定义在本地的一个控制器中或应用于多个@Controller类当定义了@ControllerAdvice的类。下面的章节解释了更多的细节。

 

22.11.2 @ExceptionHandler

 

The HandlerExceptionResolver interface and the SimpleMappingExceptionResolver implementations allow you to map Exceptions to specific views declaratively along with some optional Java logic before forwarding to those views. However, in some cases, especially when relying on @ResponseBody methods rather than on view resolution, it may be more convenient to directly set the status of the response and optionally write error content to the body of the response.

HandlerExceptionResolver接口和SimpleMappingExceptionResolver实现允许你匹配异常对于特定的视图对于一些选项Java的逻辑对于这些视图。然而,在一些情况,尤其是当依赖于@ResponseBody方法而不是一个视图处理,他可以更加方便对于直接设置响应的状态和选择写入错误内容对于响应体。

 

You can do that with @ExceptionHandler methods. When declared within a controller such methods apply to exceptions raised by @RequestMapping methods of that controller (or any of its sub-classes). You can also declare an @ExceptionHandler method within an @ControllerAdvice class in which case it handles exceptions from @RequestMapping methods from many controllers. Below is an example of a controller-local @ExceptionHandler method:

你可以使用@ExceptionHandler方法。当定义一个控制器例如方法应用于异常来自控制器的@RequestMapping方法(或任何其子类)。你也可以定义一个@ExceptionHandler方法在@ControllerAdvice类用于处理来自@RequestMapping方法的异常对于多个控制器。下面是一个例子关于本地控制器的@ExceptionHandler方法:

 

@Controller

public class SimpleController {

 

    // @RequestMapping methods omitted ...

 

    @ExceptionHandler(IOException.class)

    public ResponseEntity<String> handleIOException(IOException ex) {

        // prepare responseEntity

        return responseEntity;

    }

 

}

 

The @ExceptionHandler value can be set to an array of Exception types. If an exception is thrown that matches one of the types in the list, then the method annotated with the matching @ExceptionHandler will be invoked. If the annotation value is not set then the exception types listed as method arguments are used.

@ExceptionHandler值可以被设置为一个异常类型的数组。如果一个异常被抛出匹配其中列表中其中一个异常类型,使用@ExceptionHandler注解的方法会被调用。如果注解值没有被设置则将作为方法属性的异常类型将被使用。

 

Much like standard controller methods annotated with a @RequestMapping annotation, the method arguments and return values of @ExceptionHandler methods can be flexible. For example, the HttpServletRequest can be accessed in Servlet environments and the PortletRequest in Portlet environments. The return type can be a String, which is interpreted as a view name, a ModelAndView object, a ResponseEntity, or you can also add the @ResponseBody to have the method return value converted with message converters and written to the response stream.

和标准的控制器方法相似使用了@RequestMapping注解,方法参数和@ExceptionHandler的返回值可以是灵活的。例如,HttpServletRequest可以处理在Servlet环境中并且在Portlet环境中的PortletRequest。返回值类型可以是字符串,拦截一个视图名,ModelAndViewobjectResponseEntity或你也可以添加@ResponseBody对于方法的返回值,转换消息转换器并且写入到响应流中。

 

22.11.3 Handling Standard Spring MVC Exceptions

处理标准的springmvc异常

 

Spring MVC may raise a number of exceptions while processing a request. The SimpleMappingExceptionResolver can easily map any exception to a default error view as needed. However, when working with clients that interpret responses in an automated way you will want to set specific status code on the response. Depending on the exception raised the status code may indicate a client error (4xx) or a server error (5xx).

springmvc可以抛出一系列异常对于处理一个请求。SimpleMappingExceptionResolver可以简单的匹配异常对于默认的错误视图。然而当和客户端工作拦截响应在自动化的方式你希望设置特定的状态码对于响应。依赖于异常状态码可以指出是客户端错误(4xx)或服务端错误(5xx)。

 

The DefaultHandlerExceptionResolver translates Spring MVC exceptions to specific error status codes. It is registered by default with the MVC namespace, the MVC Java config, and also by the DispatcherServlet (i.e. when not using the MVC namespace or Java config). Listed below are some of the exceptions handled by this resolver and the corresponding status codes:

DefaultHandlerExceptionResolver转换springmvc的异常为特定的错误状态码。他注册于默认的mvc的命名空间,mvcjava配置,并且依赖于DispatcherServlet(也就是说,当不使用mvc的命名空间或java配置)。下面的列表展示了一些异常的处理和响应的状态码:

Exception

HTTP Status Code

BindException

400 (Bad Request)

ConversionNotSupportedException

500 (Internal Server Error)

HttpMediaTypeNotAcceptableException

406 (Not Acceptable)

HttpMediaTypeNotSupportedException

415 (Unsupported Media Type)

HttpMessageNotReadableException

400 (Bad Request)

HttpMessageNotWritableException

500 (Internal Server Error)

HttpRequestMethodNotSupportedException

405 (Method Not Allowed)

MethodArgumentNotValidException

400 (Bad Request)

MissingPathVariableException

500 (Internal Server Error)

MissingServletRequestParameterException

400 (Bad Request)

MissingServletRequestPartException

400 (Bad Request)

NoHandlerFoundException

404 (Not Found)

NoSuchRequestHandlingMethodException

404 (Not Found)

TypeMismatchException

400 (Bad Request)

 

The DefaultHandlerExceptionResolver works transparently by setting the status of the response. However, it stops short of writing any error content to the body of the response while your application may need to add developer-friendly content to every error response for example when providing a REST API. You can prepare a ModelAndView and render error content through view resolution — i.e. by configuring a ContentNegotiatingViewResolver, MappingJackson2JsonView, and so on. However, you may prefer to use @ExceptionHandler methods instead.

DefaultHandlerExceptionResolver通过设置响应的状态来工作。然而,他停止简短的写入错误内容对于响应体当你的应用可以需要添加开发者友好的内容对于每个错误的响应例如提供一个RESTAPI。你可以准备一个ModelAndView并提出错误内容通过视图处理————例如,通过配置一个ContentNegotiatingViewResolverMappingJackson2JsonView等等。然而你可以使用@ExceptionHandler作为替代。

 

If you prefer to write error content via @ExceptionHandler methods you can extend ResponseEntityExceptionHandler instead. This is a convenient base for @ControllerAdvice classes providing an @ExceptionHandler method to handle standard Spring MVC exceptions and return ResponseEntity. That allows you to customize the response and write error content with message converters. See the ResponseEntityExceptionHandler javadocs for more details.

如果你倾向于写错误内容通过@ExceptionHandler方法你可以继承ResponseEntityExceptionHandler作为替代。这是方便的基于@ControllerAdvice类提供一个@ExceptionHandler方法来处理标准的springmvc的异常并返回ResponseEntity。他们允许你自定义响应并写错误内容通过消息转换器。见ResponseEntityExceptionHandlerjavadocs来了解更多。

 

22.11.4 Annotating Business Exceptions With @ResponseStatus

使用@ResponseStatus来注解业务异常

 

A business exception can be annotated with @ResponseStatus. When the exception is raised, the ResponseStatusExceptionResolver handles it by setting the status of the response accordingly. By default the DispatcherServlet registers the ResponseStatusExceptionResolver and it is available for use.

一个业务异常可以被注解使用@ResponseStatus。当异常被抛出,ResponseStatusExceptionResolver处理通过直接设置响应的状态。默认DispatcherServlet注册ResponseStatusExceptionResolver并且可以被使用。

 

22.11.5 Customizing the Default Servlet Container Error Page

自定义默认的Servlet容器错误页面

 

When the status of the response is set to an error status code and the body of the response is empty, Servlet containers commonly render an HTML formatted error page. To customize the default error page of the container, you can declare an <error-page> element in web.xml. Up until Servlet 3, that element had to be mapped to a specific status code or exception type. Starting with Servlet 3 an error page does not need to be mapped, which effectively means the specified location customizes the default Servlet container error page.

当响应的状态设置为错误响应吗并且响应体为空,Servlet容器通常返回一个html格式的错误页面。为了自定义容器的错误页面,你可以定义<error-page>元素在web.xml中。由于Servlet3,元素必须匹配指定的状态码或异常信息。对于Servlet3的错误页面不需要匹配,意味着指定位置自定义默认的Servlet容器错误页面。

 

<error-page>

    <location>/error</location>

</error-page>

 

Note that the actual location for the error page can be a JSP page or some other URL within the container including one handled through an @Controller method:

注意实际的错误页面的位置可以是一个jsp的页面或其他url在容器中包括通过@Controller方法处理的。

 

When writing error information, the status code and the error message set on the HttpServletResponse can be accessed through request attributes in a controller:

当写入错误信息,状态码和错误信息设置在HttpServletResponse可以访问通过控制器中的request属性:

 

@Controller

public class ErrorController {

 

    @RequestMapping(path = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

    @ResponseBody

    public Map<String, Object> handle(HttpServletRequest request) {

 

        Map<String, Object> map = new HashMap<String, Object>();

        map.put("status", request.getAttribute("javax.servlet.error.status_code"));

        map.put("reason", request.getAttribute("javax.servlet.error.message"));

 

        return map;

    }

 

}

 

or in a JSP:

或者在jsp中:

 

<%@ page contentType="application/json" pageEncoding="UTF-8"%>

{

    status:<%=request.getAttribute("javax.servlet.error.status_code") %>,

    reason:<%=request.getAttribute("javax.servlet.error.message") %>

}

 

22.12 Web Security

web安全

 

The Spring Security project provides features to protect web applications from malicious exploits. Check out the reference documentation in the sections on "CSRF protection", "Security Response Headers", and also "Spring MVC Integration". Note that using Spring Security to secure the application is not necessarily required for all features. For example CSRF protection can be added simply by adding the CsrfFilter and CsrfRequestDataValueProcessor to your configuration. See the Spring MVC Showcase for an example.

spring的安全项目提供了特性用于保护web应用对于恶意的攻击。检查引用文档在章节"CSRF protection""Security Response Headers""Spring MVC Integration"。注意使用spring的安全来保护应用不需要所有的特性。例如CSRF保护可以简单的添加CsrfFilterCsrfRequestDataValueProcessor到你的配置中。见springmvcShowcase中的一个例子。

 

Another option is to use a framework dedicated to Web Security. HDIV is one such framework and integrates with Spring MVC.

另一个选择对于使用框架对于web安全。HDIV是一个框架和springmvc可以集成。

 

22.13 Convention over configuration support

约定优于配置的支持

 

For a lot of projects, sticking to established conventions and having reasonable defaults is just what they (the projects) need, and Spring Web MVC now has explicit support for convention over configuration. What this means is that if you establish a set of naming conventions and suchlike, you can substantially cut down on the amount of configuration that is required to set up handler mappings, view resolvers, ModelAndView instances, etc. This is a great boon with regards to rapid prototyping, and can also lend a degree of (always good-to-have) consistency across a codebase should you choose to move forward with it into production.

对于许多的项目,需要建立约定和有理由的默认只是因为项目的需要,并且springwebmvc现在可以明确的支持约定优于配置。意味着如果你建立一系列的命名约定例如,你可以去掉也谢配置对于设置处理器匹配、视图解析、ModelAndView实例等。这是一个很好的福利对于快速原型,并且可以增加跨代码的一致性你应当选择将其加入到生产中。

 

Convention-over-configuration support addresses the three core areas of MVC: models, views, and controllers.

约定优于配置的支持有三个核心的部分对于mvc:模型、视图和控制器。

 

22.13.1 The Controller ControllerClassNameHandlerMapping

ControllerClassNameHandlerMapping控制器

 

The ControllerClassNameHandlerMapping class is a HandlerMapping implementation that uses a convention to determine the mapping between request URLs and the Controller instances that are to handle those requests.

ControllerClassNameHandlerMapping是一个HandlerMapping实现使用了规定决定了匹配对于请求的url和处理器实例来处理这些请求。

 

Consider the following simple Controller implementation. Take special notice of the name of the class.

考虑下面简单的控制器实现。对于特定的类的名字。

 

public class ViewShoppingCartController implements Controller {

 

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {

        // the implementation is not hugely important for this example...

    }

 

}

 

Here is a snippet from the corresponding Spring Web MVC configuration file:

这是一个片段来自相应的springwebmvc配置文件:

 

<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

 

<bean id="viewShoppingCart" class="x.y.z.ViewShoppingCartController">

    <!-- inject dependencies as required... -->

</bean>

 

The ControllerClassNameHandlerMapping finds all of the various handler (or Controller) beans defined in its application context and strips Controller off the name to define its handler mappings. Thus, ViewShoppingCartController maps to the /viewshoppingcart* request URL.

ControllerClassNameHandlerMapping查找所有的不同的处理器(或控制器)bean定义在应用上下文中并且匹配控制器名定义在他的处理器匹配中。因此ViewShoppingCartController匹配/viewshoppingcart*的请求路径。

 

Lets look at some more examples so that the central idea becomes immediately familiar. (Notice all lowercase in the URLs, in contrast to camel-cased Controller class names.)

让我们看一些例子中心的意思是相似的。(注意所有的url中的小写,对应驼峰是的控制器雷名。)

 

    WelcomeController maps to the /welcome* request URL

    HomeController maps to the /home* request URL

    IndexController maps to the /index* request URL

    RegisterController maps to the /register* request URL

 

In the case of MultiActionController handler classes, the mappings generated are slightly more complex. The Controller names in the following examples are assumed to be MultiActionController implementations:

MultiActionController处理器类的例子中,匹配生成是复杂的。控制器名在下面的例子中假设是MultiActionController的实现:

 

    AdminController maps to the /admin/* request URL

    CatalogController maps to the /catalog/* request URL

 

If you follow the convention of naming your Controller implementations as xxxController, the ControllerClassNameHandlerMapping saves you the tedium of defining and maintaining a potentially looooong SimpleUrlHandlerMapping (or suchlike).

如果你遵循命名的规范你的控制器实现作为xxxControllerControllerClassNameHandlerMapping保存你的定义并且维持一个潜在的SimpleUrlHandlerMapping(或者类似的)。

 

The ControllerClassNameHandlerMapping class extends the AbstractHandlerMapping base class so you can define HandlerInterceptor instances and everything else just as you would with many other HandlerMapping implementations.

ControllerClassNameHandlerMapping类继承了AbstractHandlerMapping的基类因此你可以定义HandlerInterceptor实例和所有其他你需要的HandlerMapping实现。

 

22.13.2 The Model ModelMap (ModelAndView)

 

The ModelMap class is essentially a glorified Map that can make adding objects that are to be displayed in (or on) a View adhere to a common naming convention. Consider the following Controller implementation; notice that objects are added to the ModelAndView without any associated name specified.

ModelMap是一个必要的map可以添加object将被展示在视图中对于普通的命名规范。考虑下面的控制器实现;注意object被添加到ModelAndView中没有匹配特定的名字。

 

public class DisplayShoppingCartController implements Controller {

 

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {

 

        List cartItems = // get a List of CartItem objects

        User user = // get the User doing the shopping

 

        ModelAndView mav = new ModelAndView("displayShoppingCart"); <-- the logical view name

 

        mav.addObject(cartItems); <-- look ma, no name, just the object

        mav.addObject(user); <-- and again ma!

 

        return mav;

    }

}

 

The ModelAndView class uses a ModelMap class that is a custom Map implementation that automatically generates a key for an object when an object is added to it. The strategy for determining the name for an added object is, in the case of a scalar object such as User, to use the short class name of the objects class. The following examples are names that are generated for scalar objects put into a ModelMap instance.

ModelAndView类使用一个ModelMap类是一个自定义Map实现自动生成一个key对于一个object当一个object被添加到其中时。决定名字的策略对于一个添加的object是,在一定范围的object例如User,使用了object类的简称。下面的例子是名字在ModelMap实例中放入了一定范围的object

 

    An x.y.User instance added will have the name user generated.

    An x.y.Registration instance added will have the name registration generated.

    An x.y.Foo instance added will have the name foo generated.

    A java.util.HashMap instance added will have the name hashMap generated. You probably want to be explicit about the name in this case because hashMap is less than intuitive.

一个java.util.HashMap实例添加将导致hashMap名字的生成。你可以希望明白名字因为hashMap不是直觉的。

    Adding null will result in an IllegalArgumentException being thrown. If the object (or objects) that you are adding could be null, then you will also want to be explicit about the name.

添加null将导致IllegalArgumentException异常被抛出。如果object(或object)你是添加可以是null,然后你也希望明白名字。

 

What, no automatic pluralization?

什么,没有自动的多元化?

 

Spring Web MVCs convention-over-configuration support does not support automatic pluralization. That is, you cannot add a List of Person objects to a ModelAndView and have the generated name be people.

springwebmvc的约定优于配置支持但是不支持自动多元化。你不能添加一个Personobject的列表对于ModelAndView并有一个生成的名字是people

 

This decision was made after some debate, with the "Principle of Least Surprise" winning out in the end.

在一些讨论之后我们做的决定,Principle of Least Surprise”最后胜出了。

 

The strategy for generating a name after adding a Set or a List is to peek into the collection, take the short class name of the first object in the collection, and use that with List appended to the name. The same applies to arrays although with arrays it is not necessary to peek into the array contents. A few examples will make the semantics of name generation for collections clearer:

生成名字的策略添加了一个集合或一个列表在集合中,对于简要的第一个object的类名在集合中,并且使用列表添加到名字中。相同的应用于数组机关数组不必要添加到数组的内容中。一些例子将对于集合清空使用相同的名称语义:

 

    An x.y.User[] array with zero or more x.y.User elements added will have the name userList generated.

    An x.y.Foo[] array with zero or more x.y.User elements added will have the name fooList generated.

    A java.util.ArrayList with one or more x.y.User elements added will have the name userList generated.

    A java.util.HashSet with one or more x.y.Foo elements added will have the name fooList generated.

    An empty java.util.ArrayList will not be added at all (in effect, the addObject(..) call will essentially be a no-op).

一个空的java.util.ArrayList将不会被添加(实际上addObject调用必须是非空参数)。

 

22.13.3 The View - RequestToViewNameTranslator

 

The RequestToViewNameTranslator interface determines a logical View name when no such logical view name is explicitly supplied. It has just one implementation, the DefaultRequestToViewNameTranslator class.

RequestToViewNameTranslator接口决定了逻辑视图名当没有这样的逻辑视图名被指定。他只有唯一的实现,就是DefaultRequestToViewNameTranslator类。

 

The DefaultRequestToViewNameTranslator maps request URLs to logical view names, as with this example:

DefaultRequestToViewNameTranslator匹配请求的url对于逻辑视图名,如下面的例子:

 

public class RegistrationController implements Controller {

 

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {

        // process the request...

        ModelAndView mav = new ModelAndView();

        // add data as necessary to the model...

        return mav;

        // notice that no View or logical view name has been set

    }

 

}

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    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">

 

    <!-- this bean with the well known name generates view names for us -->

    <bean id="viewNameTranslator"

            class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>

 

    <bean class="x.y.RegistrationController">

        <!-- inject dependencies as necessary -->

    </bean>

 

    <!-- maps request URLs to Controller names -->

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

 

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="prefix" value="/WEB-INF/jsp/"/>

        <property name="suffix" value=".jsp"/>

    </bean>

 

</beans>

 

Notice how in the implementation of the handleRequest(..) method no View or logical view name is ever set on the ModelAndView that is returned. The DefaultRequestToViewNameTranslator is tasked with generating a logical view name from the URL of the request. In the case of the above RegistrationController, which is used in conjunction with the ControllerClassNameHandlerMapping, a request URL of http://localhost/registration.html results in a logical view name of registration being generated by the DefaultRequestToViewNameTranslator. This logical view name is then resolved into the /WEB-INF/jsp/registration.jsp view by the InternalResourceViewResolver bean.

注意在handleRequest的实现中没有视图或逻辑视图名将设置在ModelAndView被返回。DefaultRequestToViewNameTranslator是工作对于生成逻辑视图名来自请求的URL。在上面RegistrationController的例子中,配合使用ControllerClassNameHandlerMapping,请求路径是http://localhost/registration.html将返回一个逻辑视图名对于DefaultRequestToViewNameTranslator的注册生成。逻辑视图名被解析为/WEB-INF/jsp/registration.jsp通过InternalResourceViewResolverbean

 

[Tip]

提示

 

You do not need to define a DefaultRequestToViewNameTranslator bean explicitly. If you like the default settings of the DefaultRequestToViewNameTranslator, you can rely on the Spring Web MVC DispatcherServlet to instantiate an instance of this class if one is not explicitly configured.

你不需要明确定义DefaultRequestToViewNameTranslator。如果你倾向于DefaultRequestToViewNameTranslator的默认设置,你可以依赖于springwebmvcDispatcherServlet用于实例化一个这个类的实例如果不需要明确的配置。

 

Of course, if you need to change the default settings, then you do need to configure your own DefaultRequestToViewNameTranslator bean explicitly. Consult the comprehensive DefaultRequestToViewNameTranslator javadocs for details on the various properties that can be configured.

当然,如果你不需要改变默认设置,你不需要配置你自己的DefaultRequestToViewNameTranslatorbean。参阅全面的DefaultRequestToViewNameTranslatorjavadocs来了解细节有关不同属性可以被配置。

 

22.14 HTTP caching support

http缓存支持

 

A good HTTP caching strategy can significantly improve the performance of a web application and the experience of its clients. The 'Cache-Control' HTTP response header is mostly responsible for this, along with conditional headers such as 'Last-Modified' and 'ETag'.

一个好的http缓存策略可以明显的提升web应用的性能和客户端的体验。'Cache-Control'http响应头是最能代表的,优于条件头例如'Last-Modified''ETag'

 

The 'Cache-Control' HTTP response header advises private caches (e.g. browsers) and public caches (e.g. proxies) on how they can cache HTTP responses for further reuse.

'Cache-Control'http响应头建议私有的缓存(例如,浏览器)和公共的缓存(例如,代理)对于他们如何缓存http响应对于未来的重用。

 

An ETag (entity tag) is an HTTP response header returned by an HTTP/1.1 compliant web server used to determine change in content at a given URL. It can be considered to be the more sophisticated successor to the Last-Modified header. When a server returns a representation with an ETag header, the client can use this header in subsequent GETs, in an If-None-Match header. If the content has not changed, the server returns 304: Not Modified.

一个空的tag是一个http响应头通过符合HTTP/1.1规范的web服务器来返回用于决定是否改变给定的url。他可以被考虑作为较复杂的继承对于Last-Modified的头信息。当一个服务器返回一个响应带有ETag头,客户端可以使用这个头在子的GET请求中,在If-None-Match头信息中。如果内容没有被改变,服务器返回304:未修改。

 

This section describes the different choices available to configure HTTP caching in a Spring Web MVC application.

这一节描述了不同的选择来配置http的缓存在springwebmvc应用中。

 

22.14.1 Cache-Control HTTP header

 

Spring Web MVC supports many use cases and ways to configure "Cache-Control" headers for an application. While RFC 7234 Section 5.2.2 completely describes that header and its possible directives, there are several ways to address the most common cases.

springwebmvc支持许多用力和方法来配置"Cache-Control"头对于一个应用。RFC72345.2.2完整描述了头和他的可用指令,有一些方式来描述大部分的情况。

 

Spring Web MVC uses a configuration convention in several of its APIs: setCachePeriod(int seconds):

springwebmvc使用一个配置规范在一些他的API中:setCachePeriod(int seconds)

 

    A -1 value wont generate a 'Cache-Control' response header.

-1值不会生成'Cache-Control'的响应头。

    A 0 value will prevent caching using the 'Cache-Control: no-store' directive.

0值将防止缓存使用'Cache-Control: no-store'指令。

    An n > 0 value will cache the given response for n seconds using the 'Cache-Control: max-age=n' directive.

一个大于0的值将缓存给定的响应在n秒使用'Cache-Control: max-age=n'指令。

 

The CacheControl builder class simply describes the available "Cache-Control" directives and makes it easier to build your own HTTP caching strategy. Once built, a CacheControl instance can then be accepted as an argument in several Spring Web MVC APIs.

CacheControl的构建类描述了可用的"Cache-Control"指令并且使得更加简单的构建你自己的http缓存策略。一旦构建,CacheControl实例可以被接受一个参数在一些springwebmvcapi中。

 

// Cache for an hour - "Cache-Control: max-age=3600"

CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);

 

// Prevent caching - "Cache-Control: no-store"

CacheControl ccNoStore = CacheControl.noStore();

 

// Cache for ten days in public and private caches,

// public caches should not transform the response

// "Cache-Control: max-age=864000, public, no-transform"

CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS)

                                    .noTransform().cachePublic();

 

22.14.2 HTTP caching support for static resources

http缓存支持静态的资源

 

Static resources should be served with appropriate 'Cache-Control' and conditional headers for optimal performance. Configuring a ResourceHttpRequestHandler for serving static resources not only natively writes 'Last-Modified' headers by reading a files metadata, but also 'Cache-Control' headers if properly configured.

静态资源应当服务于适当的'Cache-Control'并且条件头对于可选的表现。配置一个ResourceHttpRequestHandler用于服务静态资源而不需要本地的使用'Last-Modified'头通过读取文件的元数据但是'Cache-Control'如果被适当的配置的话。

 

You can set the cachePeriod attribute on a ResourceHttpRequestHandler or use a CacheControl instance, which supports more specific directives:

你可以设置ResourceHttpRequestHandler中的cachePeriod属性或使用一个CacheControl实例,支持更多特殊的指令:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**")

                .addResourceLocations("/public-resources/")

                .setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());

    }

 

}

 

And in XML:

xml中:

 

<mvc:resources mapping="/resources/**" location="/public-resources/">

    <mvc:cache-control max-age="3600" cache-public="true"/>

</mvc:resources>

 

22.14.3 Support for the Cache-Control, ETag and Last-Modified response headers in Controllers

支持Cache-ControlETagLast-Modified响应头在控制器中

 

Controllers can support 'Cache-Control', 'ETag', and/or 'If-Modified-Since' HTTP requests; this is indeed recommended if a 'Cache-Control' header is to be set on the response. This involves calculating a lastModified long and/or an Etag value for a given request, comparing it against the 'If-Modified-Since' request header value, and potentially returning a response with status code 304 (Not Modified).

控制器可以支持'Cache-Control''ETag''If-Modified-Since'http请求;这是被建议的如果'Cache-Control'头被设置到响应中。这将调用计算lastModifiedEtag值对于给定的请求,比较他和'If-Modified-Since'的请求头值并且返回响应吗是304

 

As described in the section called Using HttpEntity, controllers can interact with the request/response using HttpEntity types. Controllers returning ResponseEntity can include HTTP caching information in responses like this:

在这个章节中名为“使用HttpEntity”,控制器可以作用于请求或响应使用HttpEntity的类型。控制器返回ResponseEntity可以包括http缓存信息在响应中类似于:

 

@GetMapping("/book/{id}")

public ResponseEntity<Book> showBook(@PathVariable Long id) {

 

    Book book = findBook(id);

    String version = book.getVersion();

 

    return ResponseEntity

                .ok()

                .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))

                .eTag(version) // lastModified is also available

                .body(book);

}

 

Doing this will not only include 'ETag' and 'Cache-Control' headers in the response, it will also convert the response to an HTTP 304 Not Modified response with an empty body if the conditional headers sent by the client match the caching information set by the Controller.

这样做不仅仅包括'ETag''Cache-Control'头信息在响应中,他也将导致转换响应到http304未修改而没有响应内容如果条件头被客户端发送符合缓存的信息根据控制器的设置。

 

An @RequestMapping method may also wish to support the same behavior. This can be achieved as follows:

一个@RequestMapping方法可以支持相同的行为。他们可以被打包如下:

 

@RequestMapping

public String myHandleMethod(WebRequest webRequest, Model model) {

 

    long lastModified = // 1. application-specific calculation

 

    if (request.checkNotModified(lastModified)) {

        // 2. shortcut exit - no further processing necessary

        return null;

    }

 

    // 3. or otherwise further request processing, actually preparing content

    model.addAttribute(...);

    return "myViewName";

}

 

There are two key elements here: calling request.checkNotModified(lastModified) and returning null. The former sets the appropriate response status and headers before it returns true. The latter, in combination with the former, causes Spring MVC to do no further processing of the request.

有两个关键的元素在这里:调用request.checkNotModified和返回null。前者设置适当的响应状态和响应头在他返回true之前。后者和前者相比,引起springmvc来做但是不会进一步处理请求。

 

Note that there are 3 variants for this:

注意有3个不同点:

 

    request.checkNotModified(lastModified) compares lastModified with the 'If-Modified-Since' or 'If-Unmodified-Since' request header

request.checkNotModified比较lastModified通过'If-Modified-Since''If-Unmodified-Since'的头信息。

    request.checkNotModified(eTag) compares eTag with the 'If-None-Match' request header

request.checkNotModified比较eTag使用'If-None-Match'的请求头。

    request.checkNotModified(eTag, lastModified) does both, meaning that both conditions should be valid

request.checkNotModified也是这么做的,要求条件全部合适。

 

When receiving conditional 'GET'/'HEAD' requests, checkNotModified will check that the resource has not been modified and if so, it will result in a HTTP 304 Not Modified response. In case of conditional 'POST'/'PUT'/'DELETE' requests, checkNotModified will check that the resource has not been modified and if it has been, it will result in a HTTP 409 Precondition Failed response to prevent concurrent modifications.

当收到GETHEAD的请求,checkNotModified将会检查资源有没有被修改并且如果没有则返回http304状态码。对于POSTPUTDELETE请求,checkNotModified将检查资源是否被修改,如果没有则返回409防止避免并发的修改。

 

22.14.4 Shallow ETag support

简单的ETag支持

 

Support for ETags is provided by the Servlet filter ShallowEtagHeaderFilter. It is a plain Servlet Filter, and thus can be used in combination with any web framework. The ShallowEtagHeaderFilter filter creates so-called shallow ETags (as opposed to deep ETags, more about that later).The filter caches the content of the rendered JSP (or other content), generates an MD5 hash over that, and returns that as an ETag header in the response. The next time a client sends a request for the same resource, it uses that hash as the If-None-Match value. The filter detects this, renders the view again, and compares the two hashes. If they are equal, a 304 is returned.

对于ETag的支持被提供通过Servlet的过滤器ShallowEtagHeaderFilter。他是普通的Servlet过滤器并且可以被使用配合任意的web框架。ShallowEtagHeaderFilter过滤器创建这样的shallowETag(和deep ETag不一样)。过滤器捕获解析JSP的内容(或其他内容),生成MD5哈希并且返回一个ETag头在响应中。下一次客户端发送一个请求对于相同的资源,使用hash作为If-None-Match的值。过滤器探测这些,再次解析视图并且比较两个哈希。如果他们相同将返回304

 

Note that this strategy saves network bandwidth but not CPU, as the full response must be computed for each request. Other strategies at the controller level (described above) can save network bandwidth and avoid computation.

注意这个策略保存网络的带宽但是不是cpu,作为全部的响应必须在每个请求中被计算。其他的策略在控制器级别(描述如上)可以保存网络带宽避免计算。

 

This filter has a writeWeakETag parameter that configures the filter to write Weak ETags, like this: W/"02a2d595e6ed9a0b24f027f2b63b134d6", as defined in RFC 7232 Section 2.3.

这个过滤器有writeWeakETag参数配置过滤器来写Weak ETags,类似于W/"02a2d595e6ed9a0b24f027f2b63b134d6",描述在RFC72322.3节中。

 

You configure the ShallowEtagHeaderFilter in web.xml:

你需要在web.xml中配置ShallowEtagHeaderFilter

 

<filter>

    <filter-name>etagFilter</filter-name>

    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>

    <!-- Optional parameter that configures the filter to write weak ETags

    <init-param>

        <param-name>writeWeakETag</param-name>

        <param-value>true</param-value>

    </init-param>

    -->

</filter>

 

<filter-mapping>

    <filter-name>etagFilter</filter-name>

    <servlet-name>petclinic</servlet-name>

</filter-mapping>

 

Or in Servlet 3.0+ environments,

或者在Servlet3.0以上的环境,

 

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

 

    // ...

 

    @Override

    protected Filter[] getServletFilters() {

        return new Filter[] { new ShallowEtagHeaderFilter() };

    }

 

}

 

See Section 22.15, Code-based Servlet container initializationfor more details.

见章节22.15,“基于代码的Servlet容器初始化”来了解更多信息。

 

22.15 Code-based Servlet container initialization

基于代码的Servlet容器初始化

 

In a Servlet 3.0+ environment, you have the option of configuring the Servlet container programmatically as an alternative or in combination with a web.xml file. Below is an example of registering a DispatcherServlet:

Servlet3.0以上的环境,你有选择编程配置Servlet容器作为替代或配合使用web.xml文件。下面是一个注册DispatcherServlet的例子:

 

import org.springframework.web.WebApplicationInitializer;

 

public class MyWebApplicationInitializer implements WebApplicationInitializer {

 

    @Override

    public void onStartup(ServletContext container) {

        XmlWebApplicationContext appContext = new XmlWebApplicationContext();

        appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

 

        ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(appContext));

        registration.setLoadOnStartup(1);

        registration.addMapping("/");

    }

 

}

 

WebApplicationInitializer is an interface provided by Spring MVC that ensures your implementation is detected and automatically used to initialize any Servlet 3 container. An abstract base class implementation of WebApplicationInitializer named AbstractDispatcherServletInitializer makes it even easier to register the DispatcherServlet by simply overriding methods to specify the servlet mapping and the location of the DispatcherServlet configuration.

WebApplicationInitializer是一个接口由springmvc提供保证你的实现被探测并自动使用来初始化Servlet3容器。一个抽象类实现了WebApplicationInitializer名字为AbstractDispatcherServletInitializer使得他更加容易注册DispatcherServlet通过简单的覆盖方法来指定Servlet匹配和DispatcherServlet配置的位置。

 

This is recommended for applications that use Java-based Spring configuration:

建议对于应用使用基于javaspring的配置:

 

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

 

    @Override

    protected Class<?>[] getRootConfigClasses() {

        return null;

    }

 

    @Override

    protected Class<?>[] getServletConfigClasses() {

        return new Class[] { MyWebConfig.class };

    }

 

    @Override

    protected String[] getServletMappings() {

        return new String[] { "/" };

    }

 

}

 

If using XML-based Spring configuration, you should extend directly from AbstractDispatcherServletInitializer:

如果使用基于xmlspring的配置,你应当直接扩展AbstractDispatcherServletInitializer

 

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

 

    @Override

    protected WebApplicationContext createRootApplicationContext() {

        return null;

    }

 

    @Override

    protected WebApplicationContext createServletApplicationContext() {

        XmlWebApplicationContext cxt = new XmlWebApplicationContext();

        cxt.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");

        return cxt;

    }

 

    @Override

    protected String[] getServletMappings() {

        return new String[] { "/" };

    }

 

}

 

AbstractDispatcherServletInitializer also provides a convenient way to add Filter instances and have them automatically mapped to the DispatcherServlet:

AbstractDispatcherServletInitializer也提供了方便的方式来添加过滤器实例并使得他们自动匹配DispatcherServlet

 

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

 

    // ...

 

    @Override

    protected Filter[] getServletFilters() {

        return new Filter[] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };

    }

 

}

 

Each filter is added with a default name based on its concrete type and automatically mapped to the DispatcherServlet.

每个过滤器被添加通过默认的名字基于他具体的类型和自动匹配DispatcherServlet

 

The isAsyncSupported protected method of AbstractDispatcherServletInitializer provides a single place to enable async support on the DispatcherServlet and all filters mapped to it. By default this flag is set to true.

AbstractDispatcherServletInitializer中的isAsyncSupported的保护方法提供了一个简单的位置来允许异步的支持对于DispatcherServlet并且所有的过滤器来匹配他。默认这个标志被设置为true

 

Finally, if you need to further customize the DispatcherServlet itself, you can override the createDispatcherServlet method.

最后,如果你需要更多自定义DispatcherServlet本身,你可以覆盖createDispatcherServlet方法。

 

22.16 Configuring Spring MVC

配置springmvc

 

Section 22.2.1, Special Bean Types In the WebApplicationContextand Section 22.2.2, Default DispatcherServlet Configurationexplained about Spring MVCs special beans and the default implementations used by the DispatcherServlet. In this section youll learn about two additional ways of configuring Spring MVC. Namely the MVC Java config and the MVC XML namespace.

章节22.2.1,“特定的bean类型在WebApplicationContext”和章节22.2.2,“默认的DispatcherServlet的配置”解释了springmvc的特定的bean和默认的实现使用通过DispatcherServlet。在这一节中你将学会两个额外的方法来配置springmvc。命名为mvcjava配置和mvcxml命名空间。

 

The MVC Java config and the MVC namespace provide similar default configuration that overrides the DispatcherServlet defaults. The goal is to spare most applications from having to create the same configuration and also to provide higher-level constructs for configuring Spring MVC that serve as a simple starting point and require little or no prior knowledge of the underlying configuration.

mvcjava配置和mvc的命名空间提供了相似的默认配置覆盖了DispatcherServlet的默认信息。目标是分开大部分应用来创建相同的配置并且提供高级别的构造器对于配置springmvc来服务于简单的开始点和要求较少或没有内部配置的知识。

 

You can choose either the MVC Java config or the MVC namespace depending on your preference. Also as you will see further below, with the MVC Java config it is easier to see the underlying configuration as well as to make fine-grained customizations directly to the created Spring MVC beans. But lets start from the beginning.

你可以选择mvcjava配置或mvc命名空间依据你的性能。并且你将看到,根据mvcjava配置可以简单的看到内部的配置并且有很好直接自定义对于创建springmvcbean。但是让我们从起点开始。

 

22.16.1 Enabling the MVC Java Config or the MVC XML Namespace

启用mvcjava配置或mvcxml命名空间

 

To enable MVC Java config add the annotation @EnableWebMvc to one of your @Configuration classes:

为了启用mvcjava配置添加注解@EnableWebMvc对于@Configuration类之一:

 

@Configuration

@EnableWebMvc

public class WebConfig {

 

}

 

To achieve the same in XML use the mvc:annotation-driven element in your DispatcherServlet context (or in your root context if you have no DispatcherServlet context defined):

为了获得相同的在xml使用mvc:annotation-driven元素在你的DispatcherServlet的上下文中(或在你根上下文中如果你没有DispatcherServlet的上下文定义):

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    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">

 

    <mvc:annotation-driven/>

 

</beans>

 

The above registers a RequestMappingHandlerMapping, a RequestMappingHandlerAdapter, and an ExceptionHandlerExceptionResolver (among others) in support of processing requests with annotated controller methods using annotations such as @RequestMapping, @ExceptionHandler, and others.

上面注册了RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver(包括其他)来支持处理请求对于注解的控制器使用类似于@RequestMapping@ExceptionHandler或其他的注解。

 

It also enables the following:

他也允许开启如下:

 

    Spring 3 style type conversion through a ConversionService instance in addition to the JavaBeans PropertyEditors used for Data Binding.

spring3风格的类型通过ConversionService实例对于JavaBeansPropertyEditors用于数据绑定。

    Support for formatting Number fields using the @NumberFormat annotation through the ConversionService.

支持格式化Number域使用@NumberFormat注解通过ConversionService

    Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation.

支持格式化DateCalendarLongJoda Time域通过使用@DateTimeFormat注解。

    Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath.

支持验证@Controller输入通过@Valid,如果JSR303提供了在classpath中。

 

    HttpMessageConverter support for @RequestBody method parameters and @ResponseBody method return values from @RequestMapping or @ExceptionHandler methods.

HttpMessageConverter支持@RequestBody方法参数和@ResponseBody方法返回来自@RequestMapping@ExceptionHandler方法。

 

    This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:

这是一个完整的清单对于HttpMessageConverters通过mvc:annotation-driven来设置:

        ByteArrayHttpMessageConverter converts byte arrays.

ByteArrayHttpMessageConverter转换字节数组

        StringHttpMessageConverter converts strings.

StringHttpMessageConverter转换字符串

        ResourceHttpMessageConverter converts to/from org.springframework.core.io.Resource for all media types.

ResourceHttpMessageConverter转换org.springframework.core.io.Resource对于所有的媒体类型

        SourceHttpMessageConverter converts to/from a javax.xml.transform.Source.

SourceHttpMessageConverter转换javax.xml.transform.Source

        FormHttpMessageConverter converts form data to/from a MultiValueMap<String, String>.

FormHttpMessageConverter转换数据为MultiValueMap<String, String>

        Jaxb2RootElementHttpMessageConverter converts Java objects to/from XML — added if JAXB2 is present and Jackson 2 XML extension is not present on the classpath.

Jaxb2RootElementHttpMessageConverter转换javaobjectxml————添加如果JAXB2比较和Jackson2xml扩展没有在classpath

        MappingJackson2HttpMessageConverter converts to/from JSON — added if Jackson 2 is present on the classpath.

MappingJackson2HttpMessageConverter转换JSON————添加如果Jackson2被避免在classpath

        MappingJackson2XmlHttpMessageConverter converts to/from XML — added if Jackson 2 XML extension is present on the classpath.

MappingJackson2XmlHttpMessageConverter转换xml————添加如果Jackson2xml扩展在classpath

        AtomFeedHttpMessageConverter converts Atom feeds — added if Rome is present on the classpath.

AtomFeedHttpMessageConverter转换Atomfeed————添加如果Romeclasspath

        RssChannelHttpMessageConverter converts RSS feeds — added if Rome is present on the classpath.

RssChannelHttpMessageConverter转换Rssfeed————添加如果在classpath

 

See Section 22.16.12, Message Convertersfor more information about how to customize these default converters.

见章节22.16.12,“消息转换器”来了解更多信息关于如果自定义这些默认的转换器。

 

[Note]

注意

 

Jackson JSON and XML converters are created using ObjectMapper instances created by Jackson2ObjectMapperBuilder in order to provide a better default configuration.

JacksonJSONxml转换器被创建使用ObjectMapper实例创建通过Jackson2ObjectMapperBuilder用于避免默认的配置。

 

This builder customizes Jacksons default properties with the following ones:

这个构建器自定义Jackson的默认属性根据如下:

 

    DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES is disabled.

DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES被关闭

    MapperFeature.DEFAULT_VIEW_INCLUSION is disabled.

MapperFeature.DEFAULT_VIEW_INCLUSION是关闭的

 

It also automatically registers the following well-known modules if they are detected on the classpath:

他也能自动注册下面的模块如果他们被探测在classpath中:

 

    jackson-datatype-jdk7: support for Java 7 types like java.nio.file.Path.

    jackson-datatype-joda: support for Joda-Time types.

    jackson-datatype-jsr310: support for Java 8 Date & Time API types.

    jackson-datatype-jdk8: support for other Java 8 types like Optional.

 

22.16.2 Customizing the Provided Configuration

自定义提供的配置

 

To customize the default configuration in Java you simply implement the WebMvcConfigurer interface or more likely extend the class WebMvcConfigurerAdapter and override the methods you need:

为了自定义默认的配置在java中你简单的实现WebMvcConfigurer接口或扩展类WebMvcConfigurerAdapter和覆盖你需要的方法:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    // Override configuration methods...

 

}

 

To customize the default configuration of <mvc:annotation-driven/> check what attributes and sub-elements it supports. You can view the Spring MVC XML schema or use the code completion feature of your IDE to discover what attributes and sub-elements are available.

为了自定义默认的配置关于<mvc:annotation-driven/>检查属性和支持的子元素。你可以视图springmvcschema或使用代码完成对于你的IDE的特性来发现什么属性或什么子元素是允许的。

 

22.16.3 Conversion and Formatting

转换和格式化

 

By default formatters for Number and Date types are installed, including support for the @NumberFormat and @DateTimeFormat annotations. Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath. To register custom formatters and converters, override the addFormatters method:

默认的转换器对于数字和日期类型是已经安装的支持,包括支持@NumberFormat@DateTimeFormat注解。全面支持Joda Time格式化库也是被安装的如果Joda Time是持久化在classpath中的。为了注册自定义格式化器和转换器,覆盖addFormatters方法。

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addFormatters(FormatterRegistry registry) {

        // Add formatters and/or converters

    }

 

}

 

In the MVC namespace the same defaults apply when <mvc:annotation-driven> is added. To register custom formatters and converters simply supply a ConversionService:

mvc命名空间内相同的默认应用当<mvc:annotation-driven>被添加的时候。为了注册自定义格式化器和转换器简单的支持转换服务:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    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">

 

    <mvc:annotation-driven conversion-service="conversionService"/>

 

    <bean id="conversionService"

            class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

        <property name="converters">

            <set>

                <bean class="org.example.MyConverter"/>

            </set>

        </property>

        <property name="formatters">

            <set>

                <bean class="org.example.MyFormatter"/>

                <bean class="org.example.MyAnnotationFormatterFactory"/>

            </set>

        </property>

        <property name="formatterRegistrars">

            <set>

                <bean class="org.example.MyFormatterRegistrar"/>

            </set>

        </property>

    </bean>

 

</beans>

 

[Note]

注意

 

See Section 9.6.4, FormatterRegistrar SPIand the FormattingConversionServiceFactoryBean for more information on when to use FormatterRegistrars.

见章节9.6.4,“FormatterRegistrar SPI”和FormattingConversionServiceFactoryBean来了解更多信息当你使用FormatterRegistrars的时候。

 

22.16.4 Validation

验证

 

Spring provides a Validator interface that can be used for validation in all layers of an application. In Spring MVC you can configure it for use as a global Validator instance, to be used whenever an @Valid or @Validated controller method argument is encountered, and/or as a local Validator within a controller through an @InitBinder method. Global and local validator instances can be combined to provide composite validation.

spring提供了Validator接口可以使用用于验证应用中所有的层。在springmvc中你可以配置用于全局的Validator接口实例,为了被使用当@Valid@Validated控制器方法参数要到的,或者本地的Validator使用一个控制器通过@InitBinder方法。全局和本地的验证实例可以组合通过提供符合的验证。

 

Spring also supports JSR-303/JSR-349 Bean Validation via LocalValidatorFactoryBean which adapts the Spring org.springframework.validation.Validator interface to the Bean Validation javax.validation.Validator contract. This class can be plugged into Spring MVC as a global validator as described next.

spring也智慧城JSR303/JSR349bean验证通过LocalValidatorFactoryBean适用于springorg.springframework.validation.Validator接口对于bean的验证javax.validation.Validator合约。这个类可以被插件到springmvc中作为一个全局的验证如描述在后面。

 

By default use of @EnableWebMvc or <mvc:annotation-driven> automatically registers Bean Validation support in Spring MVC through the LocalValidatorFactoryBean when a Bean Validation provider such as Hibernate Validator is detected on the classpath.

通过默认使用@EnableWebMvc<mvc:annotation-driven>自动注册bean的验证支持在springmvc通过LocalValidatorFactoryBean当一个beanValidation提供了例如HibernateValidator来自classpath中。

 

[Note]

注意

 

Sometimes its convenient to have a LocalValidatorFactoryBean injected into a controller or another class. The easiest way to do that is to declare your own @Bean and also mark it with @Primary in order to avoid a conflict with the one provided with the MVC Java config.

有时可以方便的使用LocalValidatorFactoryBean的注入到一个控制器或另一个类。简单的方式来这么做是定义你自己的@Bean并且标记他通过@Primary用于避免冲突对于给定的mvcjava配置。

 

If you prefer to use the one from the MVC Java config, youll need to override the mvcValidator method from WebMvcConfigurationSupport and declare the method to explicitly return LocalValidatorFactory rather than Validator. See Section 22.16.13, Advanced Customizations with MVC Java Configfor information on how to switch to extend the provided configuration.

如果你倾向于使用来自mvcjava配置,你将需要覆盖mvcValidator方法来做WebMvcConfigurationSupport并且定义方法来明确返回LocalValidatorFactory而不是Validator。见章节22.16.13,“高级自定义mvcjava配置”来了解有关如何扩展提供的配置。

 

Alternatively you can configure your own global Validator instance:

作为替代你可以配置你自己的全局Validator实例:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public Validator getValidator(); {

        // return "global" validator

    }

 

}

 

and in XML:

和在xml中:

 

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    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">

 

    <mvc:annotation-driven validator="globalValidator"/>

 

</beans>

 

To combine global with local validation, simply add one or more local validator(s):

为了合并本地的验证,简单的添加一个或多个本地的验证器:

 

@Controller

public class MyController {

 

    @InitBinder

    protected void initBinder(WebDataBinder binder) {

        binder.addValidators(new FooValidator());

    }

 

}

 

With this minimal configuration any time an @Valid or @Validated method argument is encountered, it will be validated by the configured validators. Any validation violations will automatically be exposed as errors in the BindingResult accessible as a method argument and also renderable in Spring MVC HTML views.

对于最小的配置,任何时候一个@Valid@Validated方法参数被使用,将验证通过配置的验证器。任何验证妨碍将自动被暴露作为一个错误在BindingResult中访问作为一个方法参数并且可以在springmvchtml视图中进行渲染。

 

22.16.5 Interceptors

拦截器

 

You can configure HandlerInterceptors or WebRequestInterceptors to be applied to all incoming requests or restricted to specific URL path patterns.

你可以配置HandlerInterceptorsWebRequestInterceptors用于应用于所有的输入请求或严格于特定的URL的路径模式。

 

An example of registering interceptors in Java:

一个在java中注册拦截器的例子:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new LocaleInterceptor());

        registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");

        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");

    }

 

}

 

And in XML use the <mvc:interceptors> element:

xml中使用<mvc:interceptors>元素:

 

<mvc:interceptors>

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

    <mvc:interceptor>

        <mvc:mapping path="/**"/>

        <mvc:exclude-mapping path="/admin/**"/>

        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>

    </mvc:interceptor>

    <mvc:interceptor>

        <mvc:mapping path="/secure/*"/>

        <bean class="org.example.SecurityInterceptor"/>

    </mvc:interceptor>

</mvc:interceptors>

 

22.16.6 Content Negotiation

内容协商

 

You can configure how Spring MVC determines the requested media types from the request. The available options are to check the URL path for a file extension, check the "Accept" header, a specific query parameter, or to fall back on a default content type when nothing is requested. By default the path extension in the request URI is checked first and the "Accept" header is checked second.

你可以配置如何让springmvc决定请求的媒体类型来自请求。可选的选项用于检查URL路径对于文件的扩展名,检查Accept头信息,一个特定查询参数或退回到一个默认的内容类型当注册为空时。默认的路径扩展名在请求的URI被首先检查并且Accept的头信息其次被检查。

 

The MVC Java config and the MVC namespace register json, xml, rss, atom by default if corresponding dependencies are on the classpath. Additional path extension-to-media type mappings may also be registered explicitly and that also has the effect of whitelisting them as safe extensions for the purpose of RFD attack detection (see the section called Suffix Pattern Matching and RFDfor more detail).

mvcjava配置和mvc的命名空间注册jsonxmlrssatom在默认情况下如果相应的依赖在classpath中。额外的路径扩展对于媒体类型匹配也明确被注册并且影响白名单作为安全的扩展名目的是RFD攻击的探测(见章节名字为“后缀匹配和RFD”来了解更多内容)。

 

Below is an example of customizing content negotiation options through the MVC Java config:

下面是一个例子关于自定义内容协商选项通过mvcjava配置:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

        configurer.mediaType("json", MediaType.APPLICATION_JSON);

    }

}

 

In the MVC namespace, the <mvc:annotation-driven> element has a content-negotiation-manager attribute, which expects a ContentNegotiationManager that in turn can be created with a ContentNegotiationManagerFactoryBean:

mvc的命名空间,<mvc:annotation-driven>元素有一个content-negotiation-manager属性,期望ContentNegotiationManager返回被创建通过ContentNegotiationManagerFactoryBean

 

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

 

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">

    <property name="mediaTypes">

        <value>

            json=application/json

            xml=application/xml

        </value>

    </property>

</bean>

 

If not using the MVC Java config or the MVC namespace, youll need to create an instance of ContentNegotiationManager and use it to configure RequestMappingHandlerMapping for request mapping purposes, and RequestMappingHandlerAdapter and ExceptionHandlerExceptionResolver for content negotiation purposes.

如果没有使用mvcjava配置或mvc命名空间,你将需要创建一个ContentNegotiationManager的实例并且使用它来配置RequestMappingHandlerMapping对于请求的匹配目的并且RequestMappingHandlerAdapterExceptionHandlerExceptionResolver用于内容协商的目的。

 

Note that ContentNegotiatingViewResolver now can also be configured with a ContentNegotiationManager, so you can use one shared instance throughout Spring MVC.

注意ContentNegotiatingViewResolver也可以配置通过ContentNegotiationManager,因此你可以使用一个共享的实例通过springmvc

 

In more advanced cases, it may be useful to configure multiple ContentNegotiationManager instances that in turn may contain custom ContentNegotiationStrategy implementations. For example you could configure ExceptionHandlerExceptionResolver with a ContentNegotiationManager that always resolves the requested media type to "application/json". Or you may want to plug a custom strategy that has some logic to select a default content type (e.g. either XML or JSON) if no content types were requested.

在更多高级的例子中,他是有用的来配置多个ContentNegotiationManager实例用于包含自定义的ContentNegotiationStrategy实现。例如你可以配置ExceptionHandlerExceptionResolver使用ContentNegotiationManager将被解析请求媒体类型对于"application/json"。或你可以插件一个自定义的策略有相同的逻辑来选择默认的内容类型(例如XMLJSON)如果没有指定内容类型被注册的话。

 

22.16.7 View Controllers

视图控制器

 

This is a shortcut for defining a ParameterizableViewController that immediately forwards to a view when invoked. Use it in static cases when there is no Java controller logic to execute before the view generates the response.

这是一个简明的定义ParameterizableViewController直接对于视图当被调用的时候。使用它在静态的例子中当没有Java控制器逻辑来执行在视图生成响应之前。

 

An example of forwarding a request for "/" to a view called "home" in Java:

一个例子有关请求中对于/对于视图而言相当于java中的home

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addViewControllers(ViewControllerRegistry registry) {

        registry.addViewController("/").setViewName("home");

    }

 

}

 

And the same in XML use the <mvc:view-controller> element:

并且在xml中也可以相同的使用<mvc:view-controller>元素:

 

<mvc:view-controller path="/" view-name="home"/>

 

22.16.8 View Resolvers

视图解析器

 

The MVC config simplifies the registration of view resolvers.

mvc的配置简单的注册了视图解析器。

 

The following is a Java config example that configures content negotiation view resolution using FreeMarker HTML templates and Jackson as a default View for JSON rendering:

java配置例子的下面配置内容协商视图解析使用FreeMarkerhtml模板和Jackson作为默认的视图对于JSON的处理:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureViewResolvers(ViewResolverRegistry registry) {

        registry.enableContentNegotiation(new MappingJackson2JsonView());

        registry.jsp();

    }

 

}

 

And the same in XML:

xml中也是相同的:

 

<mvc:view-resolvers>

    <mvc:content-negotiation>

        <mvc:default-views>

            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

        </mvc:default-views>

    </mvc:content-negotiation>

    <mvc:jsp/>

</mvc:view-resolvers>

 

Note however that FreeMarker, Velocity, Tiles, Groovy Markup and script templates also require configuration of the underlying view technology.

注意对于FreeMarkerVelocityTilesGroovy标记和脚本模板也要求配置下面的视图技术。

 

The MVC namespace provides dedicated elements. For example with FreeMarker:

mvc的命名空间提供了专用的元素。例如对于FreeMarker

 

<mvc:view-resolvers>

    <mvc:content-negotiation>

        <mvc:default-views>

            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>

        </mvc:default-views>

    </mvc:content-negotiation>

    <mvc:freemarker cache="false"/>

</mvc:view-resolvers>

 

<mvc:freemarker-configurer>

    <mvc:template-loader-path location="/freemarker"/>

</mvc:freemarker-configurer>

 

In Java config simply add the respective "Configurer" bean:

java配置中添加各自的Configurerbean

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureViewResolvers(ViewResolverRegistry registry) {

        registry.enableContentNegotiation(new MappingJackson2JsonView());

        registry.freeMarker().cache(false);

    }

 

    @Bean

    public FreeMarkerConfigurer freeMarkerConfigurer() {

        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();

        configurer.setTemplateLoaderPath("/WEB-INF/");

        return configurer;

    }

 

}

 

22.16.9 Serving of Resources

资源的服务

 

This option allows static resource requests following a particular URL pattern to be served by a ResourceHttpRequestHandler from any of a list of Resource locations. This provides a convenient way to serve static resources from locations other than the web application root, including locations on the classpath. The cache-period property may be used to set far future expiration headers (1 year is the recommendation of optimization tools such as Page Speed and YSlow) so that they will be more efficiently utilized by the client. The handler also properly evaluates the Last-Modified header (if present) so that a 304 status code will be returned as appropriate, avoiding unnecessary overhead for resources that are already cached by the client. For example, to serve resource requests with a URL pattern of /resources/** from a public-resources directory within the web application root you would use:

选项允许静态的资源请求符合特定URL模式来服务通过ResourceHttpRequestHandler来自任何资源位置的列表。这提供了一个方便的方式来服务静态资源来自location而不是web应用的根,包括classpath的根。cache-period属性可以被使用用于设置复杂的过期头信息(讲义设置为一年对于Page SpeedYSlow)一次他们可以更有效的被客户端使用。处理器也计算Last-Modified头信息(如果存在的话)因此304的状态会被在适当的情况下返回,避免不必要的覆盖资源已经缓存在客户端中。例如,为了服务资源请求对于含有/resources/**URL来自公共的资源路径对于一个web应用你可以看到:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");

    }

 

}

 

And the same in XML:

对于xml则是类似的:

 

<mvc:resources mapping="/resources/**" location="/public-resources/"/>

 

To serve these resources with a 1-year future expiration to ensure maximum use of the browser cache and a reduction in HTTP requests made by the browser:

为了服务这些资源对于未来一年可扩展的确保最大程度的使用浏览器缓存和减少HTTP请求对于浏览器:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);

    }

 

}

 

And in XML:

并且在xml中:

 

<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>

 

For more details, see HTTP caching support for static resources.

关于更多的细节,见HTTP缓存对于静态资源的支持。

 

The mapping attribute must be an Ant pattern that can be used by SimpleUrlHandlerMapping, and the location attribute must specify one or more valid resource directory locations. Multiple resource locations may be specified using a comma-separated list of values. The locations specified will be checked in the specified order for the presence of the resource for any given request. For example, to enable the serving of resources from both the web application root and from a known path of /META-INF/public-web-resources/ in any jar on the classpath use:

匹配属性必须是一个Ant模式的可以被使用通过SimpleUrlHandlerMapping,并且location属性必须定义一个或多个合法的资源路径位置。多个资源位置可以被定义使用一个逗号分隔的列表的值。位置定义将以一定的顺序被检查对于给定请求的资源的表现。例如,为了允许服务于资源来自web应用和已知的路径如/META-INF/public-web-resources/classpath中的任何一个jar中使用:

 

@EnableWebMvc

@Configuration

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**")

                .addResourceLocations("/", "classpath:/META-INF/public-web-resources/");

    }

 

}

 

And in XML:

并且在xml中:

 

<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>

 

When serving resources that may change when a new version of the application is deployed it is recommended that you incorporate a version string into the mapping pattern used to request the resources so that you may force clients to request the newly deployed version of your applications resources. Support for versioned URLs is built into the framework and can be enabled by configuring a resource chain on the resource handler. The chain consists of one more ResourceResolver instances followed by one or more ResourceTransformer instances. Together they can provide arbitrary resolution and transformation of resources.

当服务资源可以改变当一个新版本的应用被部署建议你合并一个版本字符串到匹配模式中使用请求资源以便你可以强制客户端请求新的部署版本对于你的应用资源。支持版本的URL被构建进入了框架并且可以允许被配置一个资源链对于资源的处理。资源链中包括多个ResourceResolver实例以及一个或多个ResourceTransformer实例。他们一同提供了资源的解决方案。

 

The built-in VersionResourceResolver can be configured with different strategies. For example a FixedVersionStrategy can use a property, a date, or other as the version. A ContentVersionStrategy uses an MD5 hash computed from the content of the resource (known as "fingerprinting" URLs). Note that the VersionResourceResolver will automatically use the resolved version strings as HTTP ETag header values when serving resources.

内置的VersionResourceResolver可以被配置对于不同的策略。例如FixedVersionStrategy可以使用一个代理、一个日志或其他如版本。ContentVersionStrategy使用一个MD5的哈希计算来自资源的内容(作为“签名”的URL而被大家熟悉)。注意VersionResourceResolver将自动使用版本字符串作为HTTP的标签头数据对于服务的资源。

 

ContentVersionStrategy is a good default choice to use except in cases where it cannot be used (e.g. with JavaScript module loaders). You can configure different version strategies against different patterns as shown below. Keep in mind also that computing content-based versions is expensive and therefore resource chain caching should be enabled in production.

ContentVersionStrategy是一个好的默认选择对于使用于他不能被使用的地方(例如,在JavaScript的模块加载中)。你可以配置不同版本的策略对于不同的模式展示如下。记住计算基于内容的版本是耗时的并且在生产中要保证资源链应当被允许缓存。

 

Java config example;

Java配置的例子:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**")

                .addResourceLocations("/public-resources/")

                .resourceChain(true).addResolver(

                    new VersionResourceResolver().addContentVersionStrategy("/**"));

    }

 

}

 

XML example:

XML的例子:

 

<mvc:resources mapping="/resources/**" location="/public-resources/">

<mvc:resource-chain>

<mvc:resource-cache/>

<mvc:resolvers>

<mvc:version-resolver>

<mvc:content-version-strategy patterns="/**"/>

</mvc:version-resolver>

</mvc:resolvers>

</mvc:resource-chain>

</mvc:resources>

 

In order for the above to work the application must also render URLs with versions. The easiest way to do that is to configure the ResourceUrlEncodingFilter which wraps the response and overrides its encodeURL method. This will work in JSPs, FreeMarker, Velocity, and any other view technology that calls the response encodeURL method. Alternatively, an application can also inject and use directly the ResourceUrlProvider bean, which is automatically declared with the MVC Java config and the MVC namespace.

对于上面的和应用配合使用必须解析带有版本的URL。最简单的方式来配置ResourceUrlEncodingFilter就是包裹响应和覆盖他的encodeURL方法。这在JSPFreeMarkerVelocity和其他视图技术中可用就是调用encodeURL方法。作为代替,一个应用也可以注入和直接使用ResourceUrlProviderbean,自动定义通过mvcjava配置和mvc的命名空间。

 

Webjars are also supported with WebJarsResourceResolver, which is automatically registered when the "org.webjars:webjars-locator" library is on classpath. This resolver allows the resource chain to resolve version agnostic libraries from HTTP GET requests "GET /jquery/jquery.min.js" will return resource "/jquery/1.2.0/jquery.min.js". It also works by rewriting resource URLs in templates <script src="/jquery/jquery.min.js"/> <script src="/jquery/1.2.0/jquery.min.js"/>.

Webjars也支持WebJarsResourceResolver,可以自动注册当classpath中存在"org.webjars:webjars-locator"时。解析允许资源链解析版本库来自httpget请求中"GET /jquery/jquery.min.js"将返回资源"/jquery/1.2.0/jquery.min.js"。也可以用于重写URL在模板<script src="/jquery/jquery.min.js"/> <script src="/jquery/1.2.0/jquery.min.js"/>

 

22.16.10 Falling Back On the "Default" Servlet To Serve Resources

对于服务资源回调"Default"Servlet

 

This allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the containers default Servlet), while still allowing static resource requests to be handled by the containers default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping of "/**" and the lowest priority relative to other URL mappings.

这个允许DispatcherServlet匹配"/"(覆盖容器默认的Servlet匹配),将允许静态资源请求处理通过容器默认的Servlet。他配置一个DefaultServletHttpRequestHandler使用URL匹配"/**"并且是最低优先对于其他的URL匹配来说。

 

This handler will forward all requests to the default Servlet. Therefore it is important that it remains last in the order of all other URL HandlerMappings. That will be the case if you use <mvc:annotation-driven> or alternatively if you are setting up your own customized HandlerMapping instance be sure to set its order property to a value lower than that of the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE.

处理将转发所有的请求到默认的Servlet。这是重要的对于保留按照一定顺序对于其他的URL的匹配。这是一个例子如果你使用<mvc:annotation-driven>或作为替代如果你设置了你自定义的HandlerMapping实例保证设置了他的顺序对于值低于DefaultServletHttpRequestHandler,其值是Integer的最大值。

 

To enable the feature using the default setup use:

为了保证特性使用默认的设置:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

        configurer.enable();

    }

 

}

 

Or in XML:

或在xml中:

 

<mvc:default-servlet-handler/>

 

The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher for the default Servlet must be retrieved by name rather than by path. The DefaultServletHttpRequestHandler will attempt to auto-detect the default Servlet for the container at startup time, using a list of known names for most of the major Servlet containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere). If the default Servlet has been custom configured with a different name, or if a different Servlet container is being used where the default Servlet name is unknown, then the default Servlets name must be explicitly provided as in the following example:

对于覆盖"/"Servlet匹配的警告是RequestDispatcher对于默认的Servlet必须通过name而不是路径。DefaultServletHttpRequestHandler将试图自动探测默认的Servlet对于容器在启动时通过使用已知的列表名对于主要的Servlet容器(包括TomcatJettyGlassFishJBossResinWebLogicWebSphere)。如果默认的Servlet有自定义的配置对于不同的名称或如果一个不同的Servlet容器被使用当默认的Servlet名未知的时候,默认的Servlet名必须明确被指定如下面的例子一样:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

        configurer.enable("myCustomDefaultServlet");

    }

 

}

 

Or in XML:

或在xml中:

 

<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>

 

22.16.11 Path Matching

路径匹配

 

This allows customizing various settings related to URL mapping and path matching. For details on the individual options check out the PathMatchConfigurer API.

允许自定义不同的设置基于URL匹配和路径匹配。关于每种选项的细节检查来自PathMatchConfigurerAPI

 

Below is an example in Java config:

下面是一个有关Java配置的例子:

 

@Configuration

@EnableWebMvc

public class WebConfig extends WebMvcConfigurerAdapter {

 

    @Override

    public void configurePathMatch(PathMatchConfigurer configurer) {

        configurer

            .setUseSuffixPatternMatch(true)

            .setUseTrailingSlashMatch(false)

            .setUseRegisteredSuffixPatternMatch(true)

            .setPathMatcher(antPathMatcher())

            .setUrlPathHelper(urlPathHelper());

    }

 

    @Bean

    public UrlPathHelper urlPathHelper() {

        //...

    }

 

    @Bean

    public PathMatcher antPathMatcher() {

        //...

    }

 

}

 

And the same in XML, use the <mvc:path-matching> element:

并且在相同的xml中,使用<mvc:path-matching>元素:

 

<mvc:annotation-driven>

    <mvc:path-matching

        suffix-pattern="true"

        trailing-slash="false"

        registered-suffixes-only="true"

        path-helper="pathHelper"

        path-matcher="pathMatcher"/>

</mvc:annotation-driven>

 

<bean id="pathHelper" class="org.example.app.MyPathHelper"/>

<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>

 

22.16.12 Message Converters

消息转换器

 

Customization of HttpMessageConverter can be achieved in Java config by overriding configureMessageConverters() if you want to replace the default converters created by Spring MVC, or by overriding extendMessageConverters() if you just want to customize them or add additional converters to the default ones.

对于HttpMessageConverterCustomization可以通过java配置覆盖configureMessageConverters方法如果你希望替代默认的由springmvc创建的转换器或覆盖extendMessageConverters如果你希望自定义他们并且对于默认实现添加额外的转换器。

 

Below is an example that adds Jackson JSON and XML converters with a customized ObjectMapper instead of default ones:

下面是一个例子添加JacksonJSONxml的转换器对于自定义的ObjectMapper代替默认的转换器:

 

@Configuration

@EnableWebMvc

public class WebConfiguration extends WebMvcConfigurerAdapter {

 

    @Override

    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()

                .indentOutput(true)

                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))

                .modulesToInstall(new ParameterNamesModule());

        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));

        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));

    }

 

}

 

In this example, Jackson2ObjectMapperBuilder is used to create a common configuration for both MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter with indentation enabled, a customized date format and the registration of jackson-module-parameter-names that adds support for accessing parameter names (feature added in Java 8).

在这个例子中,Jackson2ObjectMapperBuilder使用使用来创建一个通用的配置对于MappingJackson2HttpMessageConverterMappingJackson2XmlHttpMessageConverter来允许压缩,一个自定义的日期格式和注册jackson-module-parameter-names添加支持对于访问参数名(在java8中添加的特性)。

 

[Note]

注意

 

Enabling indentation with Jackson XML support requires woodstox-core-asl dependency in addition to jackson-dataformat-xml one.

允许Jackson XML的压缩支持请求woodstox-core-asl依赖此外对于jackson-dataformat-xml

 

Other interesting Jackson modules are available:

其他有趣的Jackson模块是可用的:

 

    jackson-datatype-money: support for javax.money types (unofficial module)

jackson-datatype-money:支持javax.money类型(非官方模块)

    jackson-datatype-hibernate: support for Hibernate specific types and properties (including lazy-loading aspects)

jackson-datatype-hibernate:支持特定的Hibernate类型和属性(包括延迟加载方面)

 

It is also possible to do the same in XML:

也可以在xml中进行实现:

 

<mvc:annotation-driven>

    <mvc:message-converters>

        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">

            <property name="objectMapper" ref="objectMapper"/>

        </bean>

        <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">

            <property name="objectMapper" ref="xmlMapper"/>

        </bean>

    </mvc:message-converters>

</mvc:annotation-driven>

 

<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"

      p:indentOutput="true"

      p:simpleDateFormat="yyyy-MM-dd"

      p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>

 

<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

 

22.16.13 Advanced Customizations with MVC Java Config

使用mvcjava配置的高级自定义设置

 

As you can see from the above examples, MVC Java config and the MVC namespace provide higher level constructs that do not require deep knowledge of the underlying beans created for you. Instead it helps you to focus on your application needs. However, at some point you may need more fine-grained control or you may simply wish to understand the underlying configuration.

你也看到来自上面的例子,mvcjava配置和和mvc的命名空间提供了高等级的设计不需要更深层次的知识对于底层为你创建的bean。作为替代他帮助你关注于你的应用需求。然而,在一些情况,你可能需要更多的细粒度的控制或你可以简单的希望理解底层的配置。

 

The first step towards more fine-grained control is to see the underlying beans created for you. In MVC Java config you can see the javadocs and the @Bean methods in WebMvcConfigurationSupport. The configuration in this class is automatically imported through the @EnableWebMvc annotation. In fact if you open @EnableWebMvc you can see the @Import statement.

第一步对于细粒度的控制是发现底层为你创建的bean。在mvcjava配置在中你可以看到javadocs@Bean方法在WebMvcConfigurationSupport中。在这个类中的配置自动被导入@EnableWebMvc注解。实际上如果你打开的@EnableWebMvc你可以看到@Import的声明。

 

The next step towards more fine-grained control is to customize a property on one of the beans created in WebMvcConfigurationSupport or perhaps to provide your own instance. This requires two things — remove the @EnableWebMvc annotation in order to prevent the import and then extend from DelegatingWebMvcConfiguration, a subclass of WebMvcConfigurationSupport. Here is an example:

下一步更细粒度的控制是自定义一个属性对于一个bean创建通过WebMvcConfigurationSupport或者提供你自己的实例。这要求两点————取消@EnableWebMvc注解用于避免导入和扩展DelegatingWebMvcConfiguration。是WebMvcConfigurationSupport的一个子类。例子如下:

 

@Configuration

public class WebConfig extends DelegatingWebMvcConfiguration {

 

    @Override

    public void addInterceptors(InterceptorRegistry registry){

        // ...

    }

 

    @Override

    @Bean

    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {

        // Create or let "super" create the adapter

        // Then customize one of its properties

    }

 

}

 

[Note]

注意

 

An application should have only one configuration extending DelegatingWebMvcConfiguration or a single @EnableWebMvc annotated class, since they both register the same underlying beans.

一个应用应当有唯一的配置扩展自DelegatingWebMvcConfiguration或一个单独的@EnableWebMvc注解类当他们注册了相同的底层bean

 

Modifying beans in this way does not prevent you from using any of the higher-level constructs shown earlier in this section. WebMvcConfigurerAdapter subclasses and WebMvcConfigurer implementations are still being used.

修改bean以这样的方式不能避免你使用任何高级的设计展示这个章节的前面。WebMvcConfigurerAdapter的子类和WebMvcConfigurer的实现依然可以被使用。

 

22.16.14 Advanced Customizations with the MVC Namespace

高级的自定义对于mvc的命名空间

 

Fine-grained control over the configuration created for you is a bit harder with the MVC namespace.

细粒度的控制对于配置为你来创建是比较困难的对于mvc的命名空间来说。

 

If you do need to do that, rather than replicating the configuration it provides, consider configuring a BeanPostProcessor that detects the bean you want to customize by type and then modifying its properties as necessary. For example:

如果你需要这么做,而不是复制提供的配置,考虑配置一个BeanPostProcessor来探测你希望自定义的bean通过类型然后根据需要修改他们的属性。例如:

 

@Component

public class MyPostProcessor implements BeanPostProcessor {

 

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {

        if (bean instanceof RequestMappingHandlerAdapter) {

            // Modify properties of the adapter

        }

    }

 

}

 

Note that MyPostProcessor needs to be included in an <component scan/> in order for it to be detected or if you prefer you can declare it explicitly with an XML bean declaration.

注意MyPostProcessor需要被包括在<component scan/>中为了他可以被探测或如果你倾向于明确定义使用xmlbean定义。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值