【跟着官网学SpringMVC】1.1. DispatcherServlet

1. Spring Web MVC
     Spring Web MVC 是建立在Servlet API和spring framework基础之上的一套web 框架。
 1.1. DispatcherServlet
     在学习servlet时知道,要处理浏览器发送的请求,就需要通过写对应的servlet,然后通过对应的url映射,将请求交给对应的servlet来处理请求。使用spring mvc框架后,就由DispatcherServlet来处理我们的请求。使用它就必须先声明他,只要在web.xml中声明这一个DispatcherServlet即可,声明如下:

web.xml
	<servlet>
		<servlet-name>spring-mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring-mvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping> 

我们知道,现在spring framework都提倡我们使用代码来配置,而不推荐使用配置文件的方式。那么通过代码该如何做呢?下面的方式等同于上面xml中的配置:

public class MyWebApplicationInitializer implements WebApplicationInitializer {
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		XmlWebApplicationContext appContext = new XmlWebApplicationContext();【1】
		appContext.setConfigLocation("classpath:spring-mvc.xml");
		ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher",new DispatcherServlet(appContext));
		dispatcher.setLoadOnStartup(1);
		dispatcher.addMapping("/");
	}
}

通过实现WebApplicationInitializer 接口,当容器启动时,便会调用这个onStartup方法,通过代码来注册一个DispatcherServlet。
这个接口就是为了用来通过程序方式配置ServletContext的,从而代替web.xml。

实现WebApplicationInitializer接口的类,会自动被SpringServletContainerInitializer检测到。SpringServletContainerInitializer是有Servlet3.0自动引导启动的。也就是Servlet3.0容器启动时,便会通过SpringServletContainerInitializer去检测所有实现了WebApplicationInitializer接口的类,并调用其onStartup方法。
Servlet容器怎么知道启动时要实例化SpringServletContainerInitializer这个类呢,这是因为Servlet3.0的新特性,工作机制是这样的:

Servlet3.0新特性:
1、Servlet容器启动会扫描,当前应用里面每一个jar包的ServletContainerInitializer的实现
2、提供ServletContainerInitializer的实现类;
    必须绑定在,META-INF/services/javax.servlet.ServletContainerInitializer
    文件的内容就是ServletContainerInitializer实现类的全类名;

关于ServletContainerInitializer这里有一些相关的介绍,开源中国都有一些相关的介绍。当然最好可以去JCP官网寻找官方文档说明

容器启动时,会通过JAR Services API ServiceLoader.load(Class) 通过反射,读取这个文件中的类,如下图:

经过上面流程,便可以调用到WebApplicationInitializer实现类中的onStartup方法了。

 

1.1.1. Context Hierarchy(上下文的层次关系)

官网上说,DispatcherServlet期望要有一个WebApplicationContext ,原文如下:

 这个WebAppliactionContext是什么,乍一看很抽象。启示它就是用来加载spring的xml文件的一个类,看上面MyWebApplicationInitializer 中的的【1】,他就是一个WebAppliactionContext,因为是他的子类。
下面看看WebAppliactionContext api中的说法:

org.springframework.web.context.WebApplicationContext implementation which takes its configuration from XML documents, understood by an org.springframework.beans.factory.xml.XmlBeanDefinitionReader
WebApplicationContext 从XML中获取配置,是通过XmlBeanDefinitionReader来解析XML的。

By default, the configuration will be taken from "/WEB-INF/applicationContext.xml" for the root context, and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" (like for a DispatcherServlet instance with the servlet-name "test").
默认是读取的是/WEB-INF/applicationContext.xml或者/WEB-INF/test-servlet.xml。

The config location defaults can be overridden via the "contextConfigLocation" context-param of org.springframework.web.context.ContextLoader and servlet init-param of org.springframework.web.servlet.FrameworkServlet. Config locations can either denote concrete files like "/WEB-INF/context.xml" or Ant-style patterns like "/WEB-INF/*-context.xml" (see org.springframework.util.PathMatcher javadoc for pattern details).

也可以通过contextConfigLocation自定义xml文件的位置和名字,如下图

1.1.2. Special Bean Types
所谓Special Bean,指的是DispatcherServlet中用来处理请求和和响应的,这些Bean都被spring容器管理,是所以特殊,因为这些Bean都不需要我们自己手动实例化。但是我们可以重写里面的属性。那么DispatcherServlet中的这些Special Bean有哪些呢,如下:

Bean typeExplanation

HandlerMapping

通过它可以绑定某个类来处理请求

HandlerAdapter

由adapter用来调用处理请求的方法。

HandlerExceptionResolver

用来处理处理请求时的异常

ViewResolver

用来展示结果的解析器,比如最常见的JSP就是一个viewResolver

LocaleResolverLocaleContextResolver

本地化处理器

ThemeResolver

比如给页面统一换颜色,就是ThemeResolver

MultipartResolver

就是用来处理shangcu

FlashMapManager

用于处理重定向中reqeust参数丢失的解决方案

上面这些类的具体分析和讲解,可以参考我的相应文章。

1.1.3. Web MVC Config

Applications can declare the infrastructure beans listed in Special Bean Types that are required to process requests. The DispatcherServlet checks the WebApplicationContext for each special bean. If there are no matching bean types, it falls back on the default types listed in DispatcherServlet.properties.

意思就是:DispatcherServlet 在执行的的时候会检查上面说的Special Bean,如果找不到对应的类,就会声明DispatcherServlet.properties中指定的默认类。

1.1.4. Servlet Config
这一节还是说从Servlet3.0开始可以通过java 代码的形式来注册DispatcherServlet来代替web.xml声明DispatcherServlet。
1.1.1中介绍的直接实现接口WebApplicationInitializer,这一节在介绍一个通过继承AbstractDispatcherServletInitializer的方式(AbstractDispatcherServletInitializer也是实现了WebApplicationInitializer接口),注册一个DispatcherServlet。如下:

public class MyWebAppInitializer extends AbstractDispatcherServletInitializer {
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        XmlWebApplicationContext cxt = new XmlWebApplicationContext();
        cxt.setConfigLocation("classpath:spring-mvc.xml");
        return cxt;
    }
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
   /**
     * 也可以添加Filter
     */
    @Override
    protected Filter[] getServletFilters() {
        return new Filter[] {
            new HiddenHttpMethodFilter(), new CharacterEncodingFilter() };
    }
}

AbstractDispatcherServletInitializer这个类的运作机制与实现WebApplicationInitializer 接口是相同的,当自定义的类继承这个抽象类后,容器启动时,便会调用这个抽象类的onStartup方法来注册一个DispatcherServlet。与1.1.1通过实现WebApplicationInitializer 来注册DispatcherServlet不同的是,继承这个抽象类,我们就不需要在手动创建DispatcherServlet进行注册了。抽象类里面帮我们创建然后注册了。
 

1.1.5. Processing
DispatcherServlet按照的步骤来处理request:

  • 先查找WebApplicationContext(什么是WebApplicationContext,上面说过,简单来书就是springmvc的xml中配置的那些类的集合) 然后把它保存到reqeust的attribute中,默认attribute的key为  DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE。
    具体代码中的体现就是如下:
    DispatcherServlet.java extends FrameworkServlet
    
    public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());【1】
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);【2】
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);【3】
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());【4】
    }
    FrameworkServlet.java
    public final WebApplicationContext getWebApplicationContext() {
        // this.webAppliactionContext是什么时候怎么赋值的?是在实例化DispatcherServlet时,通过构造方法赋值的,如下图
        return this.webApplicationContext;
    }

    什么时候实例化的呢?可以从1.1.1节和1.1.2节中找到答案,那里在注册DispatcherServlet的时候,会将webApplicationXml放到构造参数中。
  • 将 locale resolver 绑定到request的attribute中,代码【2】所示
  • 将 theme resolver绑定到request的attribute中,代码【3】所示
  • 如果检测到multipart file resolver(也就是我们在xml中配置multpart类),那么request将被包装为MultipartHttpServletRequest 
  • 会去查找适合的handler,如果找到了handler,就会执行一个 chain (preprocessors, postprocessors, and controllers) 
  • 如果上面那一步返回的是一个model,那么便会通过以view来渲染model中的数据。

以上的这个过程可以参考的其他文章,里面详细介绍了DispatcherServlet中的执行过程。

The HandlerExceptionResolver beans declared in the WebApplicationContext are used to resolve exceptions thrown during request processing. Those exception resolvers allow customizing the logic to address exceptions. See Exceptions for more details.
意思:当在WebAppliacationContext(可以理解为xml中)中声明了一个HandlerExceptionResolver的bean时,那么当处理request发生异常时,便会调用我们这个bean中自定义的逻辑。一句话就是,在spring配置文件中定义这个类,然后通过这个类可以扑捉到处理request是发生的异常,然后进行处理。我有相关文章进行介绍过,可以参考。

 

You can customize individual DispatcherServlet instances by adding Servlet initialization parameters (init-param elements) to the Servlet declaration in the web.xml file. The following table lists the supported parameters:
意思:你可以通过在web.xml中使用init-param的参数自定义自己的DispatcherServlet,相关的一些参数如下:
Table 1. DispatcherServlet initialization parameters
ParameterExplanation

contextClass

contextClass这个参数对应的值应该是一个实现了ConfigurableWebApplicationContext接口的类。默认如果不用contextClass这个参数,那么会默认使用XmlWebApplicationContext 这个类。具体解释,看一下下面的【1】

contextConfigLocation

这个参数的值是一个字符串,这个字符串表示我们springmvc配置文件的路径名字。这个名字将会被传给上面的contextClass指定的类中。然后让这个类来将配置文件中的bean注入到容器中。如果不指定,就会使用默认的文件名。具体说明参考下面的【2】

namespace

WebApplicationContext的实现类也就是contextClass指定的类设置一个名字。默认 [servlet-name]-servlet.,具体参考下面的【3】

throwExceptionIfNoHandlerFound

当一个request找不到处理它的handler(controller)时,便会抛出NoHandlerFoundException 异常。这个异常可以被使用了@ExceptionHandler的controller中的方法进行处理。
默认情况下throwExceptionIfNoHandlerFound的值false,也就是不抛出NoHandlerFoundException
 异常。而是让DispatcherServlet返回一个404.

上面表格中说的这几个参数,是在web.xml中的DispatcherServlet中配置的,例子如下:

<servlet>
		<servlet-name>spring-mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<init-param>
		  	<param-name>contextClass</param-name>
            <!--这里只是将默认的又在这写了一次而已,只是为了展示如何使用,如果使用默认的,这里就没必要写了。如果想使用其他的类,可以在这指定-->
			<param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
		</init-param>
		<init-param>
		  	<param-name>namespace</param-name>
			<param-value>my-servlet</param-value>
		</init-param>
		<init-param>
		  	<param-name>throwExceptionIfNoHandlerFound</param-name>
			<param-value>false</param-value>
		</init-param>
</servlet>

contextConfigLocation、contextClass、namespace的值将被set到FrameworkServlet.java中

throwExceptionIfNoHandlerFound的值将被set到子类DispatcherServlet中。源码如下:

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
    public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
	private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
	private String namespace;
	private String contextConfigLocation;

    get\set方法省略
}

下面分别详细介绍一下这几个参数:
【1】contextClass

上面表格说过,这个参数的值是一个实现了ConfigurableWebApplicationContext接口的类的全限定名。设置这个参数的作用是什么呢?举个例子,比如,要让我们在spring的配置文件中声明的bean添加到容器中,就需要有个类专门读取这个配置文件,这个类就是通过这个参数设置的。当我们不适用这个参数时,这个参数的值将默认使用XmlWebApplicationContext(什么是XmlWebApplicationContext还记得吧?他就是专门用来读取xml文件,然后就会把xml中的bean实例化放到容器中,不懂的看开头部分)。
为什么说这个参数的值必须是一个类的全限定名呢?看下面:



可以看出,必须使用全限定名,这里才能通过BeanUtils进行实例化了。
也就是说,要想指定一个类来通过一种形式将一些bean放到容器中(也就是上下文context中),就必须设置这个参数。
只不过,如果我们不设置,默认使用

XmlWebApplicationContext这个类,然后通过一种xml方式来将bean加载到容器中而已。

【2】contextConfigLocation

上面表格说过,这个参数用来指定一个springmvc配置文件的路径名,然后contextClass指定的类(默认是XmlWebApplicationContext)将会通过这个参数指定的路径去找对应的配置文件,然后去实例化里面的bean,放到容器中。
其依据如下:
当tomcat启动时,便会通过FrameworkServlet的createWebApplicationContext方法,从下图会发现,会使用contextClass来实例化wac对象,然后将我们通过contextConfigLocation设置的配置文件的路径传给wac(wac就是contextClass的实例化对象)


下面看一下createWebApplicationContext官方doc解释

Instantiate the WebApplicationContext for this servlet, either a default org.springframework.web.context.support.XmlWebApplicationContext or a custom context class, if set.
意思:给当前的serlvet实例化一个WebApplicationContext ,这个当前的servlet就是DispatcherServlet。如果设置了contextClass那么实例化的就是WebApplicationContext 指定的,否则就使用默认的XmlWebApplicationContext

通过上面的解释可以看出所谓WebApplicationContext就是我们处理spring配置文件,对文件中bean进行实例化的类。因为实例化后的bean,都在这个WebApplicationContext中,所以也成为了bean都放到了容器中,其实容器就是这个context。

【3】namespace
这个参数暂时来看只是给我们通过contextClass指定的类设置一个名字而已。FrameworkServlet这个类中设置,如下图:

当我们在web.xml中设置这个参数时,就用这个参数的值,如果没有这个参数,则使用默认的值---就是在web.xml中设置的servlet-name的值连上-servlet(也就是表格中的[servlet-name]-servlet),如下图:

 

1.1.6. Interception

All HandlerMapping implementations support handler interceptors that are useful when you want to apply specific functionality to certain requests — for example, checking for a principal. Interceptors must implement HandlerInterceptor from the org.springframework.web.servlet package with three methods that should provide enough flexibility to do all kinds of pre-processing and post-processing:

  • preHandle(..): Before the actual handler is executed

  • postHandle(..): After the handler is executed

  • afterCompletion(..): After the complete request has finished

上面官网的这段话的大体意思就是:
 

Interception就是在handler处理request之前之后和完成时,如果你想对request做一些其他的操作,比如进行权限检查。就可以使用Interception。Interceptors 必须实现org.springframework.web.servlet.HandlerInterceptor ,然后重写里面的几个方法,如下:

  • preHandle(..): 在handler调用之前执行

  • postHandle(..): 在handler调用之后执行

  • afterCompletion(..): request完成之后执行

英文中的All HandlerMapping的意思就是指下面的【1】,在【1】中我们详细解释这段话的意思

【1】
上面表格的英文部分,从代码中是如何表示出来的呢,下面我们来看一下:
All HandlerMapping implementations support handler interceptors其实指的就是当浏览发送一个reqeust的时候,如果DispatcherServlet想要找到handler处理这个reqeust,就必须先从所用handlerMappings中找到这个reqeust对应的handler,
  图1

在getHandler方法中,就体现出了All HandlerMapping了,如下(如果你不懂handlerMapping的意思,可看我专门的文章)
图2

这里根据handlermapping就可以通过request中获取到对应的handler了。这里看到handler实际上是一个HandlerExecutionChain。这时候在返回去看官方解释All HandlerMapping implementations support handler interceptors,All HandlerMapping implementations就是指这个方法中通过for获取到的hm,support handler interceptors就是指hm.getHandler(reqeust)获取到的HandlerExecutionChain,这个类里面便会遍历所有的interceptiors,如下图:
图3
看到了preHandler方法了吧。这就是上面表格中说的interceptor的三个方法之一了,剩下两个这里就不截图了。
有了HandlerExecutionChain(也就是图1中getHandler得到的用于处理request的handler),那么在DispatcherServlet中在调用handler的方法处理请求之前,之后,完成时这三个时间点,调用handler的interceptor的方法即可,如下:

图中代码是经过精简的,主要为了突出说明红框的调用interceptor的三个方法的时间点(handler处理request之前,之后,完成时)。红框三个方法便会调用图3中的方法,在这个方法中就会调用相对应的interceptor中的preHandle,postHandle,afterCompletion三个方法。
关于如何配置Interception的例子,请参考文章【稀里糊涂学springmvc】自定义Interception

Note that postHandle is less useful with @ResponseBody and ResponseEntity methods for which the response is written and committed within the HandlerAdapter and before postHandle. That means it is too late to make any changes to the response, such as adding an extra header. For such scenarios, you can implement ResponseBodyAdvice and either declare it as an Controller Advice bean or configure it directly on RequestMappingHandlerAdapter.
意思就是说:当使用了@ResponseBody and ResponseEntity 的时候postHandle方法就没太有用处了,因为这时候对response进行任何更改(例如添加额外的header信息)已经太晚了。其替代方式为使用Controller Advice或者在RequestMappingHandlerAdapter中进行设置。

 

1.1.7. Exceptions

If an exception occurs during request mapping or is thrown from a request handler (such as a @Controller), the DispatcherServlet delegates to a chain of HandlerExceptionResolver beans to resolve the exception and provide alternative handling, which is typically an error response.
大体意思就是说:当处理handler中的方法在处理request出现异常时,DispatcherServlet会遍历所有的HandlerExceptionResolver(也就是所谓的 chain of HandlerExceptionResolver) 然后找出可以处理这个异常的HandlerExceptionResolver 来处理异常。

下面表格列出了springmvc中自带的可用的一些HandlerExceptionResolver 
 

Table 2. HandlerExceptionResolver implementations
HandlerExceptionResolverDescription

SimpleMappingExceptionResolver

A mapping between exception class names and error view names. Useful for rendering error pages in a browser application.
意思就是说:将抛出的异常类的名称与跳转到的页面进行一个映射。这样当抛出这个异常时就会跳转到这个页面

DefaultHandlerExceptionResolver

Resolves exceptions raised by Spring MVC and maps them to HTTP status codes. See also alternative ResponseEntityExceptionHandler and REST API exceptions.
意思就是:根据http返回的状态码,在页面显示对应的异常信息

ResponseStatusExceptionResolver

Resolves exceptions with the @ResponseStatus annotation and maps them to HTTP status codes based on the value in the annotation.
意思就是:我们用来处理异常的自定义的类上用@ResponseStatus注解,来设置显示在异常页面上的信息和状态码

ExceptionHandlerExceptionResolver

Resolves exceptions by invoking an @ExceptionHandler method in a @Controller or a @ControllerAdvice class. See @ExceptionHandler methods.
意思就是:当抛出异常的controller中找含有@ExceptionHandler注解的方法时(注解中的参数必须跟抛出异常的类型相同),便会通过这个方法来处理异常。

上面表格中内容全部都在文章springmvc篇:【HandlerExceptionResolver】中有详细的说明和例子
 

Chain of Resolvers

You can form an exception resolver chain by declaring multiple HandlerExceptionResolver beans in your Spring configuration and setting their order properties as needed. The higher the order property, the later the exception resolver is positioned.

The contract of HandlerExceptionResolver specifies that it can return:

  • ModelAndView that points to an error view.

  • An empty ModelAndView if the exception was handled within the resolver.

  • null if the exception remains unresolved, for subsequent resolvers to try, and, if the exception remains at the end, it is allowed to bubble up to the Servlet container.

这里的chain说白了就是当声明了多个HandlerExceptionResolver ,会遍历所有的,然后找到合适的可以处理的那个进行调用。
HandlerExceptionResolver 中主要有这么几个关键点:

  • ModelAndView 显示异常的view(暂时理解为页面就行)
  • 找不到view就返回null
  • 如果springmvc的resolvers都处理不了这个异常,就会使用servlet container中设置的(web.xml中设置的error-page)

Container Error Page

If an exception remains unresolved by any HandlerExceptionResolver and is, therefore, left to propagate or if the response status is set to an error status (that is, 4xx, 5xx), Servlet containers can render a default error page in HTML. To customize the default error page of the container, you can declare an error page mapping in web.xml. The following example shows how to do so:
意思为:如果抛出的异常找不到合适的HandlerExceptionResolver 来处理,那么便会通过servlet container设置的页面来作为异常跳转的页面(也就是web.xml中配置的error-page),如下:
web.xml
<error-page> 
    <location>/error</location>
</error-page>

1.1.8. View Resolution

Spring MVC defines the ViewResolver and View interfaces that let you render models in a browser without tying you to a specific view technology. ViewResolver provides a mapping between view names and actual views. View addresses the preparation of data before handing over to a specific view technology.
大体意思就是:springmvc提供了ViewResolver and View interfaces接口,有这个这个以后你就可以将models(什么是model不做解释)的内容显示在浏览器上,而不用关注使用哪种技术来显示页面,比如是在jsp上显示model的内容,还是在freemark上显示model中的内容。
ViewResolver 用来对view 名与实际view的实际映射,View就是在在具体用某种view technology显示之前进行的数据准备。

下面表格中列出列springmvc中带的一些ViewResolver

table 3. ViewResolver implementations
ViewResolverDescription

AbstractCachingViewResolver

这是个父类,就是用来缓存已经有过的view,每次要显示时,都会先从这个缓存中查找一次

XmlViewResolver

Implementation of ViewResolver that accepts a configuration file written in XML with the same DTD as Spring’s XML bean factories. The default configuration file is /WEB-INF/views.xml.
当controller中的方法返回一个model时,会拿着这个名字到制定的xml中去找对应的显示的页面。
默认这个xml的名字为/WEB-INF/views.xml.

ResourceBundleViewResolver

Implementation of ViewResolver that uses bean definitions in a ResourceBundle, specified by the bundle base name. For each view it is supposed to resolve,view URL. 
it uses the value of the property [viewname].(class) as the view class and the value of the property [viewname].url as the
简单来说这个resolver就是通过与properties文件一起使用,然后通过properteis文件配置不同请求使用什么技术在页面显示(比如jsp还是freemark)之所以说使用properties,是因为这个类中用到了ResourceBundle这个类(一看这个类,就要先想到properties文件。)
properties文件中使用 [viewname].(class)来指定要显示的view的实现了的全限定名
 [viewname].url指定用哪个页面来显示
[viewname]这个东东要注意一下,他就是controller中方法返回的view的字符串(比如modelAndView的名字,或者直接返回的字符串的值),看下面图例:




注意红框中两个hello1就是[viewname],一定要对应起来。这样当controller方法返回这个hello1时,就会使用hello1.url对应的页面来显示

UrlBasedViewResolver

Simple implementation of the ViewResolver interface that affects 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.
意思就是说:不需要进行viewname与页面的显式映射配置(不需要向上面一样配置),只要我们controller中的方法返回的viewname(方法中return 的值)在存放页面的文件夹中能找到对应的名字,就可以自动显式这个页面(这里为了理解简单,所以直接说成页面,其实应该是view resources)

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 javadoc for details.

FreeMarkerViewResolver

Convenient subclass of UrlBasedViewResolver that supports FreeMarkerView and custom subclasses of them.

ContentNegotiatingViewResolver

Implementation of the ViewResolver interface that resolves a view based on the request file name or Accept header. See Content Negotiation.

上面表格中的内容可以参考我的文章spring篇【ViewResolver】,里面有详细的解释。
Handling

You can chain view resolvers by declaring more than one resolver bean 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.

The contract of a ViewResolver specifies that it can return null to indicate that the view could not be found. However, in the case of JSPs and InternalResourceViewResolver, the only way to figure out if a JSP exists is to perform a dispatch through RequestDispatcher. Therefore, you must always configure an InternalResourceViewResolver to be last in the overall order of view resolvers.
翻译:大体意思就是说你可以设置多个view resolvers,然后通过order这个属性值来制定优先使用那个resolver。如果resolver返回的是null则表示找不到对应的view。但是,如果使用jsp和InternalResourceViewResolver配合使用的话,那么这个resolver必须放在最后一个来执行。

Redirecting

The special redirect: prefix in a view name lets you perform a redirect. The UrlBasedViewResolver (and its subclasses) recognize this as an instruction that a redirect is needed. The rest of the view name is the redirect URL.

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

Note that, if a controller method is annotated with the @ResponseStatus, the annotation value takes precedence over the response status set by RedirectView.
翻译:当使用redirect:时(也就是controller方法中return的字符串以redirect:开头时),则表明要执行一个重定向操作,UrlBasedViewResolver 能够识别出这个前缀字符串。
使用这个redirect:前缀,既可以重定向到其他的view(页面)也可以重定向到controller中的方法
注意:如果控制器方法用@ResponseStatus注释,则注释值优先于RedirectView设置的响应状态

Forwarding

You can also use a special forward: prefix for view names that are ultimately resolved by UrlBasedViewResolver and subclasses. This creates an InternalResourceView, which does a RequestDispatcher.forward(). Therefore, this prefix is not useful with InternalResourceViewResolver and InternalResourceView (for JSPs), but it can be helpful if you use 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.
翻译:在controller的方法中的return 字符串中也可以使用forward:前缀(return “forward: **”),如果当前你用的是UrlBasedViewResolver 或者子类,则都可以被识别。这个前缀的作用就等同于RequestDispatcher.forward()。因此这个前缀在使用InternalResourceViewResolver 时,没什么作用。

Content Negotiation

ContentNegotiatingViewResolver does not resolve views itself but rather delegates to other view resolvers and selects the view that resembles the representation requested by the client. The representation can be determined from the Accept header or from a query parameter (for example, "/path?format=pdf").

the ContentNegotiatingViewResolver selects an appropriate View to handle the request by comparing the request media types 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, the list of views specified through the DefaultViews property is 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 can include wildcards (for example text/*), in which case a View whose Content-Type is text/xml is a compatible match.
翻译:ContentNegotiatingViewResolver本身不能决定使用什么view,而是委托给其他的resolver。这表示它可以通过header或者url请求中的参数("/path?format=pdf")来决定使用哪个resolver来解析。
ContentNegotiatingViewResolver
 通过比较request中的media type来决定一个合适的view来处理request。如果我们的resolver chain中找不到合适的resolver,则会使用DefaultViews来处理。Accept头可以包含通配符(例如text/*),在这种情况下,内容类型为text/xml的视图是兼容的匹配项。

1.1.9. Locale

Most parts of Spring’s architecture support internationalization, as the Spring web MVC framework does. DispatcherServlet lets you automatically resolve messages by using the client’s locale. This is done with LocaleResolver objects.
spring架构中大所属都支持国际化,springmvc同样也是的。DispatcherServlet 会根据client的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. By using the RequestContext.getLocale() method, you can always retrieve the locale that was resolved by the locale resolver.
当接收到一个request时,DispatcherServlet 会查找locale resolver ,如果找到了,就会使用这个locale。

In addition to automatic locale resolution, you can also attach an interceptor to the handler mapping (see Interception for more information on handler mapping interceptors) to change the locale under specific circumstances (for example, based on a parameter in the request).
除了自动指定外,还可以通过拦截,然后手动改变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. The following selection of locale resolvers is included in Spring.
Locale resolvers and interceptors 都在org.springframework.web.servlet.i18n这个包中。

Locale resolver有以下几种,可参考【稀里糊涂学springmvc】 LocalResolver

1.1.10. Themes
这个Themes,举个例子来说,就是比如你做的网站想可以随便切换网站基调颜色,比如点击切换为蓝色,那么网站的基调就变为蓝色,点击切换为红色,网站的基调就变为了红色。这就是Themes。通过配置这个Themes,便可以来回切换不同的颜色。
关于如何定义这个Themes和Themes的详细介绍,可参考 【稀里糊涂学springmvc】 Themes

1.1.11. Multipart Resolver

multipart Resolver就是专门用来处理multipart requests,什么是multipart request,举个例子,也就是我们熟知的multipart/form-data  ,比如你要上传一个文件,就需要和请求设置为multipart/form-data  。在springmvc中如果想接受这个multipart/form-data  ,就需要使用multipart Resolver。
具体关于multipart Resolver的详细说明和例子,可参考【稀里糊涂学springmvc】 Multipart Resolver

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值