請求處理方法執行完成后,最終返回一個 ModelAndView 對象。對於那些返回 String、View 或 ModelMap 等類型的處理方法,Spring MVC 也會在內部將它們裝配成一個 ModelAndView 對象,該對象包含了視圖邏輯名和模型對象的信息。
Spring MVC 借助視圖解析器(ViewResolver)得到最終的視圖對象(View),這可能是我們常見的 JSP 視圖,也可能是一個基於 FreeMarker、Velocity 模板技術的視圖,還可能是 PDF、Excel、XML、JSON 等各種形式的視圖。
對於最終究竟采取何種視圖對象對模型數據進行渲染,處理器並不關心,處理器的工作重點聚焦在生產模型數據的工作上,從而實現 MVC 的充分解耦。
1.認識視圖
視圖的作用是渲染模型數據,將模型里的數據以某種形式呈現給客戶。視圖對象可以是常見的 JSP,還可以是 Excel 或 PDF 等形式不一的媒體形式。為了實現視圖模型和具體實現技術的解耦,Spring 在 org.springframework.web.servlet 包中定義了一個高度抽象的 View 接口,該接口中定義了兩個方法。
1)String getContentType():視圖對應的 MIME 類型,如 text/html、Image/jpeg 等。
2)void render(Map model,HttpServletRequest request,HttpServletResponse response):將模型數據以某種 MIME 類型渲染出來。
視圖對象是一個 Bean,通常情況下,視圖對象由視圖解析器負責實例化。由於視圖 Bean 是無狀態的,所以它們不會有線程安全的問題。
不同類型的視圖實現技術對應不同的 View 實現類,這些視圖實現類都位於 org.springframework.web.servlet.view 包中。
2.認識視圖解析器
Spring MVC 為邏輯視圖名的解析提供了不同的策略,可以在 Spring Web 上下文中配置一種或多種解析策略,並指定它們之間的先后順序。每種解析策略對應一個具體的視圖解析器實現類。視圖解析器的工作比較單一,即將邏輯視圖名解析為一個具體的視圖對象。所有視圖解析器都實現了 ViewResolver 接口,該接口僅有一個方法。
View resolveViewName(String viewName,Locale locale)
resolveViewName() 方法的簽名清楚地向我們傳達了視圖解析器工作的內涵:根據邏輯視圖名和本地化對象得到一個視圖對象。Spring 擁有眾多的視圖解析器實現類,通過下圖進行概括性說明。
用戶可以選擇一種視圖解析器或混用多種視圖解析器,每個視圖解析器都實現了Ordered 接口並開放出一個 orderNo 屬性,可以通過該屬性指定解析器的優先順序,值越小優先級越高。有些視圖解析器默認為最高優先級(如 ContentNegotiatingViewResolver),而有些視圖解析器默認為最低優先級(如 InternalResourceViewResoIver、XsltViewResolver 等),具體請參考 API 文檔。
Spring MVC 會按照視圖解析器的優先級順序對邏輯視圖名進行解析,直到解析成功並返回視圖對象,否則將拋出 ServletException 異常。