- 請求處理方法執行完成后,最終返回一個 ModelAndView對象。對於那些返回 String,View 或 ModeMap 等類型的處理方法,Spring MVC 也會在內部將它們裝配成一個ModelAndView 對象,它包含了邏輯名和模型對象的視圖
- Spring MVC 借助視圖解析器(ViewResolver)得到最終的視圖對象(View),最終的視圖可以是 JSP ,也可能是Excel、JFreeChart 等各種表現形式的視圖
- 對於最終究竟采取何種視圖對象對模型數據進行渲染,處理器並不關心,處理器工作重點聚焦在生產模型數據的工作上,從而實現 MVC 的充分解耦
一、視圖
- 視圖的作用是渲染模型數據,將模型里的數據以某種形式呈現給客 戶。
- 為了實現視圖模型和具體實現技術的解耦,Spring 在 org.springframework.web.servlet 包中定義了一個高度抽象的 View 接口:
- 視圖對象由視圖解析器負責實例化。由於視圖是無狀態的,所以他們 不會有線程安全的問題
常用的視圖實現類
視圖實現類 | 說明 |
---|---|
InternalResourceView | 將jsp或其他資源封裝成一個視圖,這是InternalResourceViewResolver解析成的視圖 |
JstlView | 如果jsp文件中需要用到JSTL國際化標簽功能,則需要使用該視圖類,而非InternalResourceView視圖類 |
XsltView | XSTL驅動的視圖 |
TilesView | 基於Tiles頁面布局的視圖 |
TilesJstlView | 如果Tiles模版的jsp組成文件使用到了JSTL了,則需要用該視圖替換TilesView |
AbstractExcelView | Excel視圖抽象類,開發者需要繼承AbstractExcelView,獲取視圖模型進行填充,實現自己的文檔視圖,需要依賴POI |
AbstractJExcelView | 和AbstractExcelView只不過他是依賴JExcelAPI |
AbstractPdfStamperView | PDF文檔視圖抽象類,通過AcroForm對PDF文檔進行操作 |
AbstractPdfView | PDF文檔視圖抽象類,可以通過該抽象類實現自己的PDF文檔視圖,依賴iText |
FreeMarkView | 使用FreeMark模版引擎的視圖 |
VelocityLayoutView | 使用Velocity模版引擎的視圖 |
VelocityView | 使用Velocity模版引擎的視圖 |
ConfigurableJasperReportsView | 使用java JasperReports報表技術的視圖 |
JasperReportsCsvView | 使用java JasperReports報表技術的視圖 |
JasperReportsHtmlView | 使用java JasperReports報表技術的視圖 |
JasperReportsMultiFormatView | 使用java JasperReports報表技術的視圖 |
JasperReportsPdgView | 使用java JasperReports報表技術的視圖 |
JasperReportsXlsView | 使用java JasperReports報表技術的視圖 |
MarshallingView | 通過oxm和Marshaller技術將模型數據以xml方式輸出 |
MappingJackson2JsonView | 將模型數據通過Jackson開發框架的ObjectMapper已JSON方式輸出 |
MappingJackson2XmlView | 將模型數據通過Jackson開發框架的ObjectMapper已XML方式輸出 |
redirectView | 通過redirect:和forword:前綴進行重定向的視圖 |
二、視圖解析器
- SpringMVC 為邏輯視圖名的解析提供了不同的策略,可 以在 Spring WEB 上下文中配置一種或多種解析策略,並 指定他們之間的先后順序。每一種映射策略對應一個具體 的視圖解析器實現類。
- 視圖解析器的作用比較單一:將邏輯視圖解析為一個具體 的視圖對象。
- 所有的視圖解析器都必須實現 ViewResolver 接口
常用的視圖解析器
視圖解析器實現類 | 說明 |
---|---|
beanNameViewResolver | 常用,將視圖名解析為一個bean,視圖名是bean的id |
XmlViewResolver | 和beanNameViewResolver類似,它和beanNameViewResolver的區別是bean的定義是放在xml文件中,而不是DispatchServert的配置文件中 |
ResourceBundleViewResolver | 可以利用該類為不同本地化類型提供不同的解析結果 |
InternalResourceViewResolver | 常用,一般通過該類配置前綴和后綴,然后解析為一個URL文件,例如jsp頁面,解析優先級最低 |
XsltViewResolver | 將視圖名解析為一個指定的XSLT樣式表的URL文件 |
JasperReportsViewResolver | JasperReports是一個基於java的開源報表工具,該解析器將視圖名解析為報表文件對應的路徑 |
FreeMarkerViewResolver | 解析基於FreeMarker模版技術的模版文件 |
VelocityViewResovler, VelocityLayoutViewResovler | 解析為基於Velocity模版技術的模版文件 |
ContentNegotiatingViewResovler | 常用,內容協商視圖解析器,它不負責具體的視圖解析,而且根據請求的媒體類型,從注冊的視圖解析器中選擇一個合適的解析器來將視圖解析,解析優先級最高 |
程序員可以選擇一種視圖解析器或混用多種視圖解析器
- 每個視圖解析器都實現了 Ordered 接口並開放出一個 order 屬性,可以通過 order 屬性指定解析器的優先順序,order 越小優先級越高。
- SpringMVC 會按視圖解析器順序的優先順序對邏輯視圖名進行解 析,直到解析成功並返回視圖對象,否則將拋出 ServletException 異常
InternalResourceViewResolver
JSP 是最常見的視圖技術,可以使用 InternalResourceViewResolver 作為視圖解析器:
<!-- 配置視圖解析器: 如何把 handler 方法返回值解析為實際的物理視圖 --> <!--該視圖的優先級為Integer的最大值--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
Excel 視圖
若希望使用 Excel 展示數據列表,僅需要擴展 SpringMVC 提供的 AbstractExcelView 或 AbstractJExcel View 即可。實現 buildExcelDocument() 方法,在方法中使用模型數據對象構建 Excel 文檔就可以 了。
- AbstractExcelView 基於 POI API,而 AbstractJExcelView 是基於 JExcelAPI 的。
- 視圖對象需要配置 IOC 容器中的一個 Bean,使用 BeanNameViewResolver 作為視圖解析器即可
- 若希望直接在瀏覽器中直接下載 Excel 文檔,則可以設置 響應頭 Content-Disposition 的值為 attachment;filename=xxx.xls
<!-- 配置視圖 BeanNameViewResolver 解析器: 使用視圖的名字來解析視圖 --> <!-- 通過 order 屬性來定義視圖解析器的優先級, order 值越小優先級越高 --> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"> <property name="order" value="100"></property> </bean>
三、重定向和轉發
①、一般情況下,控制器方法返回字符串類型的值會被當成邏 輯視圖名處理
②、如果返回的字符串中帶 forward: 或 redirect: 前綴 時,SpringMVC 會對他們進行特殊處理:
將 forward: 和 redirect: 當成指示符,其后的字符串作為 URL 來處理
- redirect:success.jsp:會完成一個到 success.jsp 的重定向的操作
- forward:success.jsp:會完成一個到 success.jsp 的轉發操作
org.springframework.web.servlet.view.UrlBasedViewResolver.class
protected View createView(String viewName, Locale locale) throws Exception { if(!this.canHandle(viewName, locale)) { return null; } else { String forwardUrl; if(viewName.startsWith("redirect:")) { forwardUrl = viewName.substring("redirect:".length()); RedirectView view = new RedirectView(forwardUrl,
this.isRedirectContextRelative(),
this.isRedirectHttp10Compatible()); return this.applyLifecycleMethods(viewName, view); } else if(viewName.startsWith("forward:")) { forwardUrl = viewName.substring("forward:".length()); return new InternalResourceView(forwardUrl); } else { return super.createView(viewName, locale); } } }