Spring Web MVC 视图解析
Spring web MVC 框架同其它web MVC 框架一样,是请求驱动的(request driven),围绕中心Servlet设计的。中心Servlet会分配请求到各个Controllers,以及提供其它功能。Spring的DispatcherServlet就是这种中心Servlet,但做的更多。所有MVC框架都提供定位视图(address views)的机制,Spring提供view resolvers,让你能够在浏览器上渲染models,而不会把你束缚在某一特定的视图技术上。有2个接口(Interface)对于Spring处理视图来说是很重要的,一个是ViewResolver,另一个是View。 ViewResolver提供视图名称与实际视图的映射关系,View接口定位请求准备和请求处理到视图技术上。Spring规定,Controller中的所有handler方法,必须解析到一个逻辑视图,可以是显式的(通过返回String、View或ModelView)或者是隐式的(基于协商 based on conventions)。在Spring中,视图由逻辑视图名称定位,然后由一个view resolver解析。
Spring自带的视图解析器
Spring自身带有若干种view resolver,比如:AbstractCachingViewResolver、XmlViewResolver、ResourceBundleViewResolver、UrlBasedViewResolver、InternalResourceViewResolver、VelocityViewResolver、FreeMarkerViewResolver
、ContentNegotiatingViewResolver,你可以使用1种,或链式使用多种。使用方法就是在你的*-Servlet.xml配置文件种加入相关的bean。举例如下:
<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>
J2EE环境下视图解析器的加载
那么,问题是,Spring是如何从容器中感知到我们想要使用哪些ViewResoler的呢? 答案就在于DispatcherServlet类中的initViewResolvers方法。
DispatcherServlet.java中有一个私有方法,名为initViewResolvers,代码片段如下,就是用来初始化所有ViewResolvers的。
/**
* Initialize the ViewResolvers used by this class.
* <p>If no ViewResolver beans are defined in the BeanFactory for this
* namespace, we default to InternalResourceViewResolver.
*/
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
OrderComparator.sort(this.viewResolvers);
}
}
else {
try {
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
// Ensure we have at least one ViewResolver, by registering
// a default ViewResolver if no other resolvers are found.
if (this.viewResolvers == null) {
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
如果detectAllViewResolvers属性被设置为true的话,就会触发DispatcherServlet从ApplicationContext中加载所有基类为ViewResolver的Beans,然后存入viewResolvers列表。
(initViewResolvers会被确保在WebApplicationContext被初始化好了以后才会被调用的)