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被初始化好了以後才會被呼叫的)