spring-framework-reference 3.1.4(十七章)

17.Web MVC framework

17.1 Spring Web MVC 簡介

Spring Web MVC framework圍繞一個可以分派請求到相應處理者的DispatcherServlet設計,它支持可配置的處理映射、視圖解析、區域和主題解析並且同時支持文件上傳。默認的處理者是基於@Controller和@RequestMapping註解,提供十分靈活的處理方法。根據Spring3.0的介紹,@Controller機制也允許你創建RESTful Web站點和應用程序,通過利用@PathVariable註解以及其他功能。使用Spring Web MVC 你可以把任何一個對象用來做命令對象或者表單回填對象;而不用必須實現一個特定的框架接口或者基類。Spring 的數據綁定也是很靈活的:比如,Spring框架把類型不匹配錯誤作爲可以被應用程序解決的驗證錯誤處理,而不是當作系統錯誤。因此你不必複製業務對象屬性爲簡單的,無類型的字符串到表單對象中去,僅僅是爲了驗證提交或者適當的轉化字符串。取而代之的是直接綁定到業務對象。

Spring 的視圖解析也是相當的靈活。通常一個Controller主要負責準備一個包含有數據的模型Map並且選擇一個視圖名稱,但是它也可以直接向響應流中寫入內容並完成請求。視圖名稱解析也是高度可配置的。可以通過文件擴展名或者接收頭內容類型協議,實體名稱,屬性文件,甚至是一個定製的ViewResolver的實現來配置。Model(MVC 中的 M)是一個Map接口,完全與視圖技術剝離,也就是說跟使用何種視圖技術沒有關係。你可以將Model直接與那些基於JSP、Velocity和Freemarker這些呈現技術的模板集成,或者直接生成XML,JSON,以及許多其他類型的內容。模型Map只需要轉換爲合適的格式,比如JSP請求屬性,Velocity模板模型。

Spring Web MVC的特色

Spring的web模塊包含有很多獨一無二的web支持功能:

  • 分工明確。每一個角色-控制器、驗證器、命令對象、表單對象、域模型、DispatcherServlet、處理器映射表、視圖解析器、等角色可以分別被一個特定的對象履行。
  • 強大並且直觀的配置框架和應用像配置javaBeans一樣。配置能力包括在不同的上下文環境中交叉引用,比如從控制器到業務模型和驗證器。
  • 可變、無侵入、靈活。定義你需要的控制器方法簽名,儘可能的使用參數註解(如:@RequestParam,@RequestHeader,@PathVariable等等)針對給定的應用場景。
  • 可重用的業務代碼,無需重複。利用存在的業務對象作爲命令對象或者表單對象而不需要反射他們去擴展一個特定的框架基類。
  • 可定製的綁定和驗證。類型不匹配作爲應用級的驗證錯誤,保存有違規的數據、本地化的日期和數字綁定等等而不是作爲一個只包含有字符串屬性的表單對象,需要人工解析並轉換爲業務對象。
  • 可定製的處理器映射和視圖解析。Spring提供從最簡單的基於URL的配置到複雜的,特定用途的處理器映射和視圖解析策略。Spring比起那些強制使用一種特定的技術進行請求映射的框架要更具有靈活性。
  • 靈活的模型傳遞。模型傳遞有了一個鍵值對Map的支持很容易的跟任何類型的視圖技術結合。
  • 可定製的語言環境和主題解析,支持JSPs不論有沒有Spring標籤庫,支持JSTL,支持Velocity不需要其他的紐帶。
  • 一個簡單卻有力的JSP標籤庫,也就是所說的Spring標籤庫,他提供對數據綁定和主題定製功能的支持。定製標籤考慮到儘可能大的靈活性就標記代碼來講。想要知道關於標籤庫描述的信息,請看題名爲: Appendix G.spring.tld的附錄。
  • 擁有一個JSP表單標籤庫,在Spring2.0版本時引入的,使得編寫JSP頁面的表單變得更容易。關於JSP表單標籤庫的描述見附錄:Appendix H, spring-form.tld。
  • 所有beans的生命週期被侷限到當前的HTTP請求或者HTTP Session。這不是Sprign MVC自身特有的功能,而是Spring MVC所使用的WebApplicationContext 容器所具有的。Bean的範圍描述在Request, session, andglobalsession scopes部分。

其他類型MVC框架可插入性

在有些項目中Non-Spring MVC的實現是更受人喜歡的。許多團隊希望利用他們在技術和工具上的既有的投資。大量的Struts框架的知識和經驗。如果你能夠忍受Struts設計上的瑕疵,Struts也是web層一個不錯的選擇;也同樣適用於WebWork以及其他的web MVC框架。

如果你不想使用Spring的Web MVC,但是又想要利用Spring提供的其他方面的解決方案,你可以輕鬆的將你選擇的MVC框架跟Spring集成在一起。只需要利用ContextLoaderListener啓動一個Spring跟應用上下文,通過來自Struts或者WebWork  action內部的ServletContext屬性(或者利用Spring的幫助方法)來訪問它。不涉及任何插件,因此沒有專用的集成是必須的。站在web層的觀點來看,你只是使用把Spring當做一個庫來使用,把根應用上下文實體作爲一個入口。

儘管沒有用Spring 的 Web MVC是註冊 的實體和Spring服務也是唾手可得的。在這方面Spring跟Struts或者WebWork不是競爭關係。Spring致力於很多方面然而那些純粹的web MVC框架做不到這些,從實體配置到數據訪問以及事務管理。因此你可以充實你的應用程序利用Spring的中間層和/或數據訪問層,甚至你可以只使用抽象於JDBC或者Hibernate的事務。

17.2  TheDispatcherServlet

Spring Web MVC 跟許多其他的Web MVC框架類似,請求驅動,圍繞一箇中心Servlet設計,這個中央Servlet分配請求到對應的Controller並且提供其他的功能以促進web應用的開發。但是Spring Web MVC 的DispatcherServlet能做的遠遠不止這些。它完全跟Spring IoC 容器集成在一起正因爲如此你可以使用Spring 具有的任何其他功能。

Spring Web MVC 的DispatcherServlet處理請求的工作流在下圖中闡述.深諳設計模式的讀者會意識到DispatcherServlet是“前端控制器”(一種設計模式 Spring Web MVC與其他主流的web框架所公用的)設計模式的一種表現形式。


Spring Web MVC 處理請求流程圖(頂級)

DiapatcherServlet其實就是一個Servlet(它繼承自HttpServlet這個基類),因此需要在你的web項目的web.xml中被聲明。你需要映射那些你想要DispatcherServlet處理的請求,通過使用URL映射在同一個web.xml文件中。這是一個標準的Java EE Servlet 配置;下面的例子向你展示了一個DispatcherServlet的聲明以及映射:

<web-app>
<servlet>
    <servlet-name>example</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>example</servlet-name>
    <url-pattern>/example/*</url-pattern>
</servlet-mapping>
</web-app>


在前面的例子中,所有的以/example 開頭的請求將會被命名爲example的DispatcherServlet實體處理。在一個Servlet3.0以上的環境中,你也可以選擇以編程的方式配置Servlet容器。下面是的代碼基本等效於上面的web.xml例子:

public classMyWebApplicationInitializer implements WebApplicationInitializer{
    @Override
    public void onStartup(ServletContext container){
            ServletRegistration.Dynamic registration=container.addServlet("dispatcher",newDispatcherServlet());
            registration.setLoadOnStartup(1);
            registration.addMapping("/example/*");
        }
}

WebApplicationInitializer是一個Spring MVC提供的接口用來確保你的基於代碼的配置能夠被檢測到並自動被用來初始化任何類型的Servlet 3容器。一個實現了該接口的抽象基類AbstractDispatcherServletInitializer使註冊DisapatcherServlet變得更加容易,只需要簡單的制定的servlet 的映射。在Code-based Servlet containerinitialization瞭解更多信息。

以上只是設置Spring Web MVC 框架的第一步。接下來你需要配置多種多樣的Spring Web MVC框架需要使用的實體(除了DispatcherServlet以外的)。

正如在5.14節詳細說明的一樣“ApplicationContext的附加功能”,Spring中的Application -Context實體是有範圍的。在Web MVC框架中,每一個DispatcherServlet有它自己的Web Appli -cationContext,這個WebApplicationContext繼承所有已經在根Web ApplicationContext中定義的實體。這些被繼承的實體可以在特定的Servelt範圍內被重寫,你也可以爲一個給定的Ser -vlet實體定義新的特定範圍的實體。

在初始化一個DispatcherServlet 的時候,SpringMVC 會在你的web項目的WEB-INF目錄下去尋找一個以[servlet-name]-servlet.xml命名規範命名的配置文件並會創建在這個配置文件中聲明的實體,也會重寫在全局範圍內以相同名稱被定義的實體。

思考下面的DispatcherServlet配置(在 web.xml中):

<web-app>
<servlet>
    <servlet-name>golfing</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>golfing</servlet-name>
    <url-pattern>/golfing/*</url-pattern>
</servlet-mapping>
</web-app>


如果你的項目中用到了上面這中配置,那麼在你項目中需要有這樣一個配置文件:WEB-INF/golfi -ng -servlet.xml;這個文件中包含有跟你的Spring MVC框架相關的組件。你可以使用Servelt初始化參數來改變這個這個配置文件的確切位置(將在下文中做詳細介紹)。

WebApplicationContext是對原始的ApplicationContext的擴展,增加了一些web應用需要的功能。WebApplicationContext跟一般的ApplicationContext的不同之處在於它具有解析主題的能力並且它知道自己跟哪個Servlet相關聯(WebApplicationContext引用了ServletContext)。WebApplicationContext被綁定到ServletContext上,當你需要訪問WebApplicationContext的時候你可以使用RequestContextUtils提供的靜態方法來獲取WebApplicationContext。

WebApplicationContext中的特殊實體

Spring 的DispatcherServlet利用特殊的實體來處理來之頁面的請求並且渲染合適的視圖。這些實體是Spring MVC的一部分。你可以根據自己的需要在配置這些實體。Spring MVC 維護有一組默認的實體,當你沒做任何的配置的時候,那些默認的實體將會被使用,因此你不一定必須配置實體。更多信息將在下一節中講述。先看看下面的表格,列出了DispatcherServlet所依賴的一些特殊的實體。
表 17.1. WebApplicationContext中的特殊類型的實體

實體類型

說明

HandlerMapping

將請求映射到對應的處理器以及以系列的前置或後置處理(處理者攔截器)根據一些標準,這些標準的細節可以被HandlerMapping 的實現多樣化。最受歡迎的實現支持帶有註解的控制器但是也有其他類型實現。

HandlerAdapter

幫助DispatcherServlet調用映射到請求的處理器,而不用管實際調用的是那個處理者。比如,調用一個有註解的控制器需要解析多個註解。因此HandlerAdapter 的作用就是對DispatcherServlet隱藏這些細節。

HandlerExceptionResolver

將異常映射到視圖或者更復雜的一場處理代碼

ViewResolver

解析字符串類型的邏輯視圖名稱到實際的視圖類型

LocaleResolver

解析用戶的使用的地域,爲了提供國際化視圖

ThemeResolver

解析你的web應用可以使用的主題,比如想要提供個性化的佈局

MultipartResolver

解析多部請求例如支持來自HTML表單的文件上傳

FlashMapHandler

存儲、檢索輸入和輸出的FlashMap用來在請求之間傳遞屬性,通常用在重定向的時候。

默認的DispatcherServlet配置

前面提到的每一個特定的實體DispatcherServlet都默認維護有一系列他們的實現。關於這些實體的信息保存在org.springframework.web.servlet包下面的DispatcherServlet.properties文件中。

所有的特定實體都有自己合理的默認值。儘管遲早你會你會定製這些實體的屬性。比如,你會經常配置一個InternalResourceViewResolver並設置它的prefix屬性爲視圖文件的父文件夾。

不用關注細節,理解這個地方的重要理論是一旦你配置了一個特殊的實體比如一個InternalReso –urceViewResolver在你的WebApplicationContext中,你實際上重寫了默認的,本該被使用的實現列表。例如如果你配置了一個InternalResourcesViewResolver,默認的ViewResolver實現列表將會被忽略。

在17.15部分“配置Spring MVC”你將瞭解配置Spring MVC的其他可選項,包括 用java文件配置MVC以及MVC XML的命名空間,那些知識僅僅向你提供了一個簡單的切入點。假設你已經對Spring MVC如何工作有了一定的瞭解。不管你是以何種方式配置你的應用程序,在該部分講解的基本概念都將對你有所幫助。

DispatcherServlet處理順序

在你設置好一個DispatcherServlet以後,並且這個DispatcherServlet對應的請求到來,接着DispatcherServlet按照下面的步驟處理該請求:

1.   相應WebApplicationContext將會被尋找並且作爲一個屬性被綁定到請求上爲了方便處理過程中用到的處理器和其他元素使用。默認情況下會被綁定到DispatcherServlet.WEB_APPLICATION_CO -NTEXT_ATTRIBUTE鍵下。

2.   地域解析器也會被綁定到請求上便於處理過程中的其他元素在處理請求(渲染視圖、準備數據等)的時候可以確定使用區域。如果你不需要解析地域,那麼你將不需要用它。

3.   主題解析器被綁定到請求上爲了讓視圖這類處理元素知道使用哪種主題。如果你不適用主題,你可以忽略。

4.   如果你指定了多部件文件解析器,則會在請求中檢查多部分;如果多部分被找到了,那麼請求將會被封裝爲MultipartHttpServletRequest便於處理流程中接下來的元素來處理改請求。請看17.10,“Spring 的多部(文件上傳)支持”獲取跟多部處理有關的更多信息。

5.   一個合適的處理器被搜索。如果一個處理者被找到了,爲了準備model或者渲染,跟該處理者(前置處理器,後置處理器,控制器)關聯的執行鏈將會被執行。

6.   如果一個模型被返回,視圖將會被渲染。如果沒有模型返回,(可能是以爲一個前置處理器或者後置處理器攔截了請求,也有可能因爲安全原因),不會有視圖被渲染,因爲請求到此已經完成了。

聲明在WebApplicationContext中的處理異常解析器收集處理請求過程中被拋出的異常。利用這些異常解析器你可以定製異常的處理行爲。

Spring的DispatcherServlet也支持返回last-modification-date,像Servlet API規定的一樣。決定某一請求的最後修改時間的處理流程是比較直觀的:DispatcherServlet尋找一個合適的處理者映射並且檢查這些處理者是否實現了LastModified接口。如果實現了,LastModified接口的Long getLastModified(request)方法的返回值將會被返回到客戶端。

你可以在web.xml中聲明Servlet的時候爲DispatcherServlet設置初始化參數來定製個人的DispatcherServlet。下面的表中顯示了支持的參數。

表17.2 DispatcherServlet初始化參數

參數

說明

contextClass

一個類實現了WebApplicationContext接口,實例化Servlet使用的上下文。默認情況下XmlWebapplicationContext被使用。

contextConfigLocation

一個被傳遞給上下文實例(contextClass指定的)的字符串用來指明上下文可以在哪裏被找到。這個字符串可以包含多個子串(子串之間用逗號分隔)來初始化多個上下文。同一個實體的位置被定義兩次的話靠後的位置將會起作用。

namespace

WebApplicationContext的命名空間。默認的是[servlet-name]-servlet

17.3控制器的實現

控制器可以訪問應用程序行爲通常你通過一個服務接口定義的。控制器翻譯用戶輸入成爲一個模型,對視圖來說代表用戶。Spring用很抽象的方法實現一個控制器,因此你可以創建多種多樣的控制器。

Spring2.5爲MVC控制器引入了基於註解的編程模型,可以使用@RequestMapping,@RequestPara -m,@ModelAttribute等。Servlet MVC 和Portlet都可以使用這些註解。以此種方式實現的控制器無需擴展特定的基類或者實現特定的接口。此外他們不會經常直接依賴Servlet或者Portle -t APIs,但是你可以輕鬆的配置對Servlet或Portlet的訪問。

@Controller
public class HelloWorldController {
   @RequestMapping("/helloWorld")
   public String helloWorld(Model model){
      model.addAttribute("message","Hello World!");
      return "helloWorld";
   }
}


正如你看到一樣,@Controller和@RequestMapping註解允許靈活的方法名和簽名。在這個特定例子中這個方法接收一個Model並且以字符串的形式返回一個視圖的邏輯名稱,但是其他類型的接收參數和返回參數也是可以被使用的,將在這一章節的後面講述。@Controller和@RequestMa -ppding以及許多其他的註解構成了Spring MVC實現的基石。該部分記載那些在Servl -et環境中最常使用的註解。

用@Controller定義一個控制器

@Controller註解表明一個特定的類起着控制器的作用。Spring 不要求你擴展任何的控制器基類或者引用Servelet API。如果需要你也可以引用特定的Servlet的功能。

@Controller註解扮演着一個原型對被註解的類來說,聲明瞭類的扮演的角色。分配器掃描帶有@Controller註解的類尋找被影射的方法並且找出@RequestMapping註解(請看下節)。

你可以用標準的Spring實體定義方法,明確的定義註解的控制器在分配器上下文中。@Controller原型也支持自動檢測,與Spring通常支持在類路徑上檢測組件類並自動註冊爲他們定義的實體一致。

爲了能夠使用自動檢測被註解的控制器,你需要在你的配置文件添加組件掃描。利用spring-context模式像下面列出的XML片段一樣:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="org.springframework.samples.petclinic.web"/>
</beans>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章