隨筆-295  評(píng)論-26  文章-1  trackbacks-0

          13.3.?控制器

          控制器的概念是MVC設(shè)計(jì)模式的一部分(確切地說(shuō),是MVC中的C)。應(yīng)用程序的行為通常被定義為服務(wù)接口,而控制器使得用戶(hù)可以訪(fǎng)問(wèn)應(yīng)用所提供的服務(wù)。控制器解析用戶(hù)輸入,并將其轉(zhuǎn)換成合理的模型數(shù)據(jù),從而可以進(jìn)一步由視圖展示給用戶(hù)。Spring以一種抽象的方式實(shí)現(xiàn)了控制器概念,這樣使得不同類(lèi)型的控制器可以被創(chuàng)建。Spring本身包含表單控制器、命令控制器、向?qū)涂刂破鞯榷喾N多樣的控制器。

          Spring控制器架構(gòu)的基礎(chǔ)是org.springframework.mvc.Controller接口,其代碼如下:

          public interface Controller {
          
              /**
               * Process the request and return a ModelAndView object which the DispatcherServlet
               * will render.
               */
              ModelAndView handleRequest(
                  HttpServletRequest request,
                  HttpServletResponse response) throws Exception;
          
          }

          你可以發(fā)現(xiàn)Controller接口僅僅聲明了一個(gè)方法,它負(fù)責(zé)處理請(qǐng)求并返回合適的模型和視圖。Spring MVC實(shí)現(xiàn)的基礎(chǔ)就是這三個(gè)概念:Mdel、View(ModelAndView)以及 Controller。雖然Controller接口是完全抽象的,但Spring也提供了許多你可能會(huì)用到的控制器。Controller接口僅僅定義了每個(gè)控制器都必須提供的基本功能:處理請(qǐng)求并返回一個(gè)模型和一個(gè)視圖。

          13.3.1.?AbstractControllerWebContentGenerator

          為了提供一套基礎(chǔ)設(shè)施,所有的Spring控制器都繼承了 AbstractControllerAbstractController 提供了諸如緩存支持和mimetype設(shè)置這樣的功能。

          表?13.3.?AbstractController提供的功能

          功能 描述
          supportedMethods 指定這個(gè)控制器應(yīng)該接受什么樣的請(qǐng)求方法。通常它被設(shè)置成同時(shí)支持GET和POST,但是你可以選擇你想支持的方法。如果控制器不支持請(qǐng)求發(fā)送的方法,客戶(hù)端會(huì)得到通知(通常是拋出一個(gè)ServletException)。
          requiresSession 指定這個(gè)控制器是否需要HTTP session才能正常工作。如果控制器在沒(méi)有session的情況下接收到請(qǐng)求,客戶(hù)端會(huì)因?yàn)閽伋?code class="classname">ServletException而得到通知。
          synchronizeSession 指定controller是否同步用戶(hù)的HTTP session。
          cacheSeconds 指定controller通知客戶(hù)端對(duì)數(shù)據(jù)內(nèi)容緩存的秒數(shù),一般為大于零的整數(shù)。默認(rèn)值為-1,即不緩存。
          useExpiresHeader 指定Controller在響應(yīng)請(qǐng)求時(shí)是否兼容HTTP 1.0 Expires header。缺省值為true
          useCacheHeader 指定Controller在相應(yīng)請(qǐng)求時(shí)是否兼容HTTP 1.1 Cache-Control header。默認(rèn)值為true

          當(dāng)從AbstractController繼承時(shí),需要實(shí)現(xiàn)handleRequestInternal(HttpServletRequest, HttpServletResponse)抽象方法,該方法將用來(lái)實(shí)現(xiàn)自己的邏輯,并返回一個(gè)ModelAndView對(duì)象。下面這個(gè)簡(jiǎn)單的例子演示了如何從AbstractController繼承以及如何在applicationContext.xml中進(jìn)行配置

          package samples;
          
          public class SampleController extends AbstractController {
          
              public ModelAndView handleRequestInternal(
                  HttpServletRequest request,
                  HttpServletResponse response) throws Exception {
          
                  ModelAndView mav = new ModelAndView("hello");
                  mav.addObject("message", "Hello World!");
                  return mav;        
              }
          }
          <bean id="sampleController" class="samples.SampleController">
              <property name="cacheSeconds" value="120"/>
          </bean>

          該controller返回的ModelAndView使用了硬編碼的視圖名(盡管這樣做不好),并通知客戶(hù)端將響應(yīng)數(shù)據(jù)緩存2分鐘。除了通過(guò)以上方式創(chuàng)建和配置controller之外,還需要配置handler mapping(請(qǐng)參考第?13.4?節(jié) “處理器映射(handler mapping)”),這樣該controller就可以工作了。

          13.3.2.?其它的簡(jiǎn)單控制器

          盡管可以繼承AbstractController來(lái)實(shí)現(xiàn)自己的控制器,不過(guò)Spring提供的眾多控制器減輕了我們開(kāi)發(fā)簡(jiǎn)單MVC應(yīng)用時(shí)的負(fù)擔(dān)。ParameterizableViewController基本上和上面例子中的一樣,不同的是,你可以在applicationContext.xml配置中指定返回視圖名從而避免了在Java代碼中的硬編碼。

          UrlFilenameViewController會(huì)檢查URL,獲取文件請(qǐng)求的文件名,并把它作為視圖名加以使用。。例如,http://www.springframework.org/index.html對(duì)應(yīng)的視圖文件名是index

          13.3.3.?MultiActionController

          MultiActionController將多個(gè)行為(action)合并在一個(gè)控制器里,這樣可以把相關(guān)功能組合在一起。MultiActionController位于org.springframework.web.mvc.multiaction包中,它通過(guò)將請(qǐng)求映射到正確的方法名來(lái)調(diào)用方法。當(dāng)在一個(gè)控制器存在大量公共的行為,但是有多個(gè)調(diào)用入口時(shí),使用MultiActionController就特別方便。

          表?13.4.?MultiActionController提供的功能

          功能 描述
          delegate MultiActionController有兩種使用方式。第一種是你繼承MultiActionController,并在子類(lèi)中指定由MethodNameResolver解析的方法(這種情況下不需要這個(gè)delegate參數(shù))。第二種是你定義一個(gè)代理對(duì)象,由它提供MethodNameResolver解析出來(lái)的方法(這種情況下,你必須使用這個(gè)配置參數(shù)定義代理對(duì)象)。
          methodNameResolver MultiActionController需要一種策略,使其可以通過(guò)解析請(qǐng)求信息來(lái)獲得要調(diào)用的方法。這個(gè)解析策略由MethodNameResolver這個(gè)接口定義的。這個(gè)參數(shù)允許你實(shí)現(xiàn)MethodNameResolver接口,然后在控制器中使用你的策略。

          MultiActionController所支持的方法需要符合下列格式:

          								
          										// anyMeaningfulName can be replaced by any methodname
          								
          public [ModelAndView | Map | void] anyMeaningfulName(HttpServletRequest, HttpServletResponse [, Exception | AnyObject]);

          注意:在此不允許方法重載,因?yàn)?code class="classname">MultiActionController無(wú)法分辨出重載(overloading)了的方法。此外,你可以定義exception handler來(lái)處理方法中拋出的異常。

          Exception 參數(shù)是可選的,它可以是任何異常,只要它是java.lang.Exceptionjava.lang.RuntimeException的子類(lèi)。AnyObject參數(shù)也是可選的,它可以是任何對(duì)象。HTTP Request中的參數(shù)會(huì)存在這個(gè)對(duì)象中,以便使用。

          下面幾個(gè)例子示范了MultiActionController正確的方法定義。

          標(biāo)準(zhǔn)格式(跟Controller接口定義的一樣)。

          public ModelAndView doRequest(HttpServletRequest, HttpServletResponse)

          下面這個(gè)方法支持Login參數(shù), 這個(gè)參數(shù)中包含從請(qǐng)求中抽取出來(lái)的信息。

          public ModelAndView doLogin(HttpServletRequest, HttpServletResponse, Login)

          下面這個(gè)方法可以處理Exception

          public ModelAndView processException(HttpServletRequest, HttpServletResponse, IllegalArgumentException)

          下面這個(gè)方法不返回任何數(shù)值。 (請(qǐng)參考后面的章節(jié) 第?13.11?節(jié) “慣例優(yōu)先原則(convention over configuration)”)

          public void goHome(HttpServletRequest, HttpServletResponse)

          This signature has a Map return type (see the section entitled 第?13.11?節(jié) “慣例優(yōu)先原則(convention over configuration)” below).

          下面這個(gè)方法返回一個(gè)Map。 (請(qǐng)參考后面的章節(jié)第?13.11?節(jié) “慣例優(yōu)先原則(convention over configuration)”)

          public Map doRequest(HttpServletRequest, HttpServletResponse)

          MethodNameResolver負(fù)責(zé)從請(qǐng)求中解析出需要調(diào)用的方法名稱(chēng)。下面是Spring中內(nèi)置的三個(gè)MethodNameResolver 實(shí)現(xiàn)。

          • ParameterMethodNameResolver - 解析請(qǐng)求參數(shù),并將它作為方法名。(對(duì)應(yīng)http://www.sf.net/index.view?testParam=testIt的請(qǐng)求,會(huì)調(diào)用 testIt(HttpServletRequest,HttpServletResponse)方法)。使用paramName配置參數(shù),可以設(shè)定要檢查的參數(shù)。

          • InternalPathMethodNameResolver -從路徑中獲取文件名作為方法名 (http://www.sf.net/testing.view的請(qǐng)求會(huì)調(diào)用testing(HttpServletRequest,HttpServletResponse)方法。

          • PropertiesMethodNameResolver - 使用用戶(hù)自定義的屬性對(duì)象,將請(qǐng)求的URL映射到方法名。當(dāng)屬性中包含/index/welcome.html=doIt時(shí),發(fā)到/index/welcome.html 的請(qǐng)求會(huì)調(diào)用doIt(HttpServletRequest, HttpServletResponse)這個(gè)方法。 這個(gè)方法名解析器可以和PathMatcher一起工作,比如上邊那個(gè)URL寫(xiě)成/**/welcom?.html也是可以的。

          我們來(lái)看一組例子。首先是一個(gè)使用ParameterMethodNameResolver和代理(delegate)屬性的例子,它接受包含參數(shù)名"method"的請(qǐng)求,調(diào)用方法retrieveIndex

          <bean id="paramResolver" class="org....mvc.multiaction.ParameterMethodNameResolver">
            <property name="paramName" value="method"/>
          </bean>
          
          <bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
            <property name="methodNameResolver" ref="paramResolver"/>
            <property name="delegate" ref="sampleDelegate"/>
          </bean>
          
          <bean id="sampleDelegate" class="samples.SampleDelegate"/>
          
          ## together with
          
          public class SampleDelegate {
          
              public ModelAndView retrieveIndex(HttpServletRequest req, HttpServletResponse resp) {
          
                  return new ModelAndView("index", "date", new Long(System.currentTimeMillis()));
              }
          }

          當(dāng)使用上面的代理對(duì)象時(shí),我們也可以使用PropertiesMethodNameRseolver來(lái)匹配一組URL,將它們映射到我們定義的方法上:

          <bean id="propsResolver" class="org....mvc.multiaction.PropertiesMethodNameResolver">
            <property name="mappings">
              <value>
                  /index/welcome.html=retrieveIndex
                  /**/notwelcome.html=retrieveIndex
                  /*/user?.html=retrieveIndex
              </value>
            </property>
          </bean>
          
          <bean id="paramMultiController" class="org....mvc.multiaction.MultiActionController">
              <property name="methodNameResolver" ref="propsResolver"/>
              <property name="delegate" ref="sampleDelegate"/>
          </bean>

          13.3.4.?命令控制器

          Spring的CommandController是Spring MVC的重要部分。命令控制器提供了一種和數(shù)據(jù)對(duì)象交互的方式,并動(dòng)態(tài)地將來(lái)自HttpServletRequest的參數(shù)綁定到你指定的數(shù)據(jù)對(duì)象上。它的功能和Struts中的ActionForm有點(diǎn)像,不過(guò)在Spring中,你不需要實(shí)現(xiàn)任何接口來(lái)實(shí)現(xiàn)數(shù)據(jù)綁定。首先,讓我們看一下有哪些可以使用的命令控制器:

          • AbstractCommandController --你可以使用該抽象命令控制器來(lái)創(chuàng)建自己的命令控制器,它能夠?qū)⒄?qǐng)求參數(shù)綁定到你指定的命令對(duì)象。這個(gè)類(lèi)并不提供任何表單功能,但是它提供驗(yàn)證功能,并且讓你在子類(lèi)中去實(shí)現(xiàn)如何處理由請(qǐng)求參數(shù)產(chǎn)生的命令對(duì)象。

          • AbstractFormController--一個(gè)支持表單提交的抽象控制器類(lèi)。使用這個(gè)控制器,你可以定義表單,并使用從控制器獲取的數(shù)據(jù)對(duì)象構(gòu)建表單。當(dāng)用戶(hù)輸入表單內(nèi)容,AbstractFormController將用戶(hù)輸入的內(nèi)容綁定到命令對(duì)象,驗(yàn)證表單內(nèi)容,并將該對(duì)象交給控制器,完成相應(yīng)的操作。它支持的功能有防止重復(fù)提交、表單驗(yàn)證以及一般的表單處理流程。子類(lèi)需要實(shí)現(xiàn)自己的方法來(lái)指定采用哪個(gè)視圖來(lái)顯示輸入表單,哪個(gè)視圖顯示表單正確提交后的結(jié)果。如果你需要表單,但不想在應(yīng)用上下文中指定顯示給用戶(hù)的視圖,就使用這個(gè)控制器。

          • SimpleFormController --這是一個(gè)form cotnroller,當(dāng)需要根據(jù)命令對(duì)象來(lái)創(chuàng)建相應(yīng)的form的時(shí)候,該類(lèi)可以提供更多的支持。你可以為其指定一個(gè)命令對(duì)象,顯示表單的視圖名,當(dāng)表單提交成功后顯示給用戶(hù)的視圖名等等。

          • AbstractWizardFormController --這是一個(gè)抽象類(lèi),繼承這個(gè)類(lèi)需要實(shí)現(xiàn)validatePage()processFinish()processCancel() 方法。

            你有可能也需要寫(xiě)一個(gè)構(gòu)造器,它至少需要調(diào)用setPages()setCommandName()方法。setPages()的參數(shù)是一個(gè)String數(shù)組,這個(gè)數(shù)組包含了組成向?qū)У囊晥D名。setCommandName()的參數(shù)是一個(gè)String,該參數(shù)將用來(lái)在視圖中調(diào)用你的命令對(duì)象。

            AbstractFormController的實(shí)現(xiàn)一樣, 你需要使用命令對(duì)象(其實(shí)就是一個(gè)JavaBean, 這個(gè)bean中包含了表單的信息)。你有兩個(gè)選擇:在構(gòu)造函數(shù)中調(diào)用setCommandClass()方法(參數(shù)是命令對(duì)象的類(lèi)名),或者實(shí)現(xiàn)formBackingObject()方法。

            AbstractWizardFormController 有幾個(gè)你可以復(fù)寫(xiě)(override)的方法。最有用的一個(gè)是referenceData(..)。這個(gè)方法允許你把模型數(shù)據(jù)以Map的格式傳遞給視圖;getTargetPage() 允許你動(dòng)態(tài)地更改向?qū)У捻?yè)面順序,或者直接跳過(guò)某些頁(yè)面;onBindAndValidate() 允許你復(fù)寫(xiě)內(nèi)置的綁定和驗(yàn)證流程。

            最后,我們有必要提一下setAllowDirtyBack()setAllowDirtyForward()兩個(gè)方法。 你可以在getTargetPage()中調(diào)用這兩個(gè)方法,這兩個(gè)方法將決定在當(dāng)前頁(yè)面驗(yàn)證失敗時(shí),是否允許向?qū)耙苹蚝笸恕?/p>

            AbstractWizardFormController的更詳細(xì)內(nèi)容請(qǐng)參考JavaDoc。在Spring附帶的例子jPetStore中,有一個(gè)關(guān)于向?qū)?shí)現(xiàn)的例子: org.springframework.samples.jpetstore.web.spring.OrderFormController



          大盤(pán)預(yù)測(cè) 國(guó)富論
          posted on 2007-08-30 12:32 華夢(mèng)行 閱讀(2333) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Spring
          主站蜘蛛池模板: 东阳市| 水富县| 达尔| 全椒县| 苏州市| 邢台市| 清苑县| 海原县| 抚远县| 松滋市| 太白县| 靖州| 淮北市| 四会市| 和硕县| 兴和县| 陆川县| 宣化县| 星子县| 台前县| 广丰县| 安达市| 贡山| 承德市| 平定县| 古交市| 奉节县| 兴文县| 大丰市| 新疆| 英吉沙县| 石狮市| 图们市| 裕民县| 武鸣县| 大田县| 湄潭县| 瓦房店市| 佛冈县| 科尔| 迁西县|