SpringMVC重要接口ViewResolver
SpringMVC用于处理视图最重要的两个接口是ViewResolver
和View
。ViewResolver
的主要作用是把一个逻辑上的视图名称解析为一个真
正的视图,SpringMVC中用于把View
对象呈现给客户端的是View
对象本身,而ViewResolver
只是把逻辑视图名称解析为对象的View
对
象。View
接口的主要作用是用于处理视图,然后返回给客户端
这是一个抽象类,这种视图解析器会把它曾经解析过的视图保存起来,然后每次要解析视图的时候先从缓存里面找,如果找到了对
应的视图就直接返回,如果没有就创建一个新的视图对象,然后把它放到一个用于缓存的map
中,接着再把新建的视图返回。使用这
种视图缓存的方式可以把解析视图的性能问题降到最低
它是对ViewResolver
的一种简单实现,而且继承了 AbstractCachingViewResolver
,主要就是提供的一种拼接URL的方式来解析视图,它可以让我们通过prefix属性
指定一个指定的前缀,通过suffix属性
指定一个指定的后缀,然后把返回的逻辑视图名称加上指定的前缀和后缀就是指定的视图URL了。如prefix=/WEB-INF/jsps/
,suffix=.jsp
,返回的视图名称viewName=test/indx
, 则UrlBasedViewResolver
解析出来的视图URL就是/WEB-INF/jsps/test/index.jsp
。
默认的prefix和suffix都是空串。URLBasedViewResolver
支持返回的视图名称中包含redirect:前缀
,这样就可以支持URL在客户端的跳转,如当返回的视图名称是”redirect:test.do”
的时候,URLBasedViewResolver
发现返回的视图名称包含”redirect:”前缀
,于是把返回的视图名称前缀”redirect:”
去掉,取后面的test.do
组成一个RedirectView
,RedirectView
中将把请求返回的模型属性组合成查询参数的形式组合到redirect的URL后面,然后调用HttpServletResponse
对象的sendRedirect
方法进行重定向
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
</bean>
它是URLBasedViewResolver
的子类,所以URLBasedViewResolver
支持的特性它都支持。在实际应用中 InternalResourceViewResolver
也是使用的最广泛的一个视图解析器。
比如 在InternalResourceViewResolver
中定义了prefix=/WEB-INF/,suffix=.jsp
,然后请求的Controller处理器方法返回的视图名称为test
,那么这个时 候InternalResourceViewResolver
就会把test解析为一个InternalResourceView
对象,先把返回的模型属性都存放到对应的HttpServletRequest
属性中,然后利用RequestDispatcher
在服务器端把请求forword到/WEB-INF/test.jsp
。
这就 是InternalResourceViewResolver
一个非常重要的特性,我们都知道存放在/WEB-INF/
下面的内容是不能直接通过request请求的方式请求到的,为了安全性考虑,我们通常会把jsp文件放在WEB-INF
目录下,而InternalResourceView
在服务器端跳转的方式可以很好的解决这个问题。
它继承自AbstractCachingViewResolver
抽象类,所以它也是支持视图缓存的。XmlViewResolver
需要给定一个xml配置文件,该文件将使用和Spring的bean工厂配置文件一样的DTD定义,所以其实该文件就是用来定义视图的bean对象的
在该文件中定义的每一个视图的bean对象都给定一个名字,然后XmlViewResolver
将根据Controller处理器方法返回的逻辑视图名称到XmlViewResolver
指定的配置文件中寻找对应名称的视图bean用于处理视图。
该配置文件默认是/WEB-INF/views.xml
文件,如果不使用默认值的时候可以在XmlViewResolver
的location
属性中指定它的位 置。XmlViewResolver
还实现了Ordered
接口,因此我们可以通过其order
属性来指定在ViewResolver链
中它所处的位置,order
的值越小优先级越高。
这个视图解析器跟XmlViewResolver
有点类似,也是通过把返回的逻辑视图名称去匹配定义好的视图bean对象。
不同点有二,
一 是BeanNameViewResolver
要求视图bean对象都定义在Spring的application context中,而XmlViewResolver
是在指定的配置文件中寻找视图bean对象.
二 是BeanNameViewResolver
不会进行视图缓存。看一个例子,在SpringMVC的配置文件中定义了个BeanNameViewResolver
视图解析器和一个id为test的InternalResourceviewbean
对象.
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="1"/>
</bean>
<bean id="test" class="org.springframework.web.servlet.view.InternalResourceView">
<property name="url" value="/index.jsp"/>
</bean>
这样当返回的逻辑视图名称是 test的时候,就会解析为上面定义好id为test的InternalResourceView
它和XmlViewResolver
一样,也是继承自 AbstractCachingViewResolver
,但是它缓存的不是视图,这个会在后面有说到。和XmlViewResolver
一样它也需要有一个配置文件来定义逻辑视图名称和真正的View对象的对应关系,不同的是ResourceBundleViewResolver
的配置文件是一个属性文件,而且必须是放在classpath
路径下面的,默认情况下这个配置文件是在classpath根目录下的views.properties
文件,如果不使用默认值的话,则可以通过属性baseName
或baseNames
来指定。
baseName
只是指定一个基名称,Spring会在指定的classpath根目录
下寻找以指定的baseName
开始的属性文件进行View解析,如指定的baseName
是base,那 么base.properties
、baseabc.properties
等等以base开始的属性文件都会被Spring当做ResourceBundleViewResolver
解析视图的资源文件。ResourceBundleViewResolver
使用的属性配置文件的内容类似于这样:
resourceBundle.(class)=org.springframework.web.servlet.view.InternalResourceView
resourceBundle.url=/index.jsp
test.(class)=org.springframework.web.servlet.view.InternalResourceView
test.url=/test.jsp
这两个视图解析器都 是UrlBasedViewResolver
的子类。FreeMarkerViewResolver
会把Controller处理方法返回的逻辑视图解析为FreeMarkerView
,而VolocityViewResolver
会把返回的逻辑视图解析为VolocityView
。这两个视图解析器类似
FreeMarkerViewResolver
和VilocityViewResolver
都继承了UrlBasedViewResolver
。 对于FreeMarkerViewResolver
而言,它会按照UrlBasedViewResolver
拼接URL的方式进行视图路径的解析。
视图解析器链
在SpringMVC中可以同时定义多个ViewResolver
视图解析器,然后它们会组成一个ViewResolver
链。
当Controller处理器方法返回一个逻辑视图名称后,ViewResolver链将根据其中ViewResolver
的优先级来进行处理。所有的ViewResolver
都实现了Ordered
接口,在Spring中实现了这个接口的类都是可以排序的。
在ViewResolver
中是通过order
属性来指定顺序的,默认都是最大值。所以我们可以通过指定ViewResolver
的order
属性来实现ViewResolver
的优先级,order
属性是Integer
类型,order
越小,对应的 ViewResolver
将有越高的解析视图的权利,所以第一个进行解析的将是ViewResolver
链中order
值最小的那个。
当一个ViewResolver
在进行视图解析后返回的View
对象是null的话就表示该ViewResolver
不能解析该视图,这个时候如果还存在其他order
值比它大的ViewResolver
就会调用剩余的ViewResolver
中的order
值最小的那个来解析该视图,依此类推。
当ViewResolver
在进行视图解析后返回的是一个非空的View对象的时候,就表示该ViewResolver
能够解析该视图,那么视图解析这一步就完成了,后续的ViewResolver
将不会再用来解析该视图。当定义的所有ViewResolver
都不能解析该视图的时候,Spring就会抛出一个异常。
基于Spring支持的这种ViewResolver
链模式,我们就可以在SpringMVC应用中同时定义多个ViewResolver
,给定不同的order
值,这样我们就可以对特定的视图特定处理,以此来支持同一应用中有多种视图类型。
注意:像InternalResourceViewResolver
这种能解析所有的视图,即永远能返回一个非空View对象的ViewResolver
一定要把它放在ViewResolver
链的最后面。