Tapestry

          記錄學(xué)習(xí)Tapestry專(zhuān)用布格格。很多文章都轉(zhuǎn)載網(wǎng)絡(luò)。

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            20 隨筆 :: 0 文章 :: 4 評(píng)論 :: 0 Trackbacks

          Tapestry的rewind一直是學(xué)習(xí)和使用Tapestry的難點(diǎn),rewind是用來(lái)處理表單提交的,表單默認(rèn)使用的是 DirectService來(lái)提交。在詳細(xì)介紹之前,先說(shuō)明下此文中需要用到的一些概念,首先是表單組件,我這里指的是指繼承自 AbstractFormComponent類(lèi)的組件,例如:TextField、TextArea、Checkbox等,而不是具體的Form組件,表 單組件使用時(shí)必須在Form組件中,這些組件在rewind時(shí)調(diào)用繼承自AbstractFormComponent的 rewindFormComponent來(lái)讀取數(shù)據(jù),并將數(shù)據(jù)賦值給容器或者頁(yè)面。
          我們來(lái)看一下最簡(jiǎn)單的TextField組件,組件定義如下

          代碼
          1. <input??jwcid= "price@TextField" ?type= "text" ?value= "ognl:picture.price" ??translator= "translator:number,pattern=##.##" ??validators= "validators:min=0" ?displayName= "價(jià)格" ? class = "input_text" />??

          再看一下TextField中的rewindFormComponent組件方法
          代碼
          1. protected?void?rewindFormComponent(IMarkupWriter?writer,?IRequestCycle?cycle)?{??
          2. ???????//從請(qǐng)求中得到參數(shù)值??
          3. ????????String?value?=?cycle.getParameter(getName());??
          4. ??
          5. ????????try?{??
          6. ?????????????//用translator來(lái)轉(zhuǎn)換值??
          7. ????????????Object?object?=?getTranslatedFieldSupport().parse(this,?value);??
          8. //用validators來(lái)驗(yàn)證值??
          9. ????????????getValidatableFieldSupport().validate(this,?writer,?cycle,?object);??
          10. ????????????//賦值給容器或者頁(yè)面??
          11. ????????????setValue(object);??
          12. ????????}?catch?(ValidatorException?e)?{??
          13. ????????????getForm().getDelegate().record(e);??
          14. ????????}??
          15. ????}??

          可以看到在rewindFormComponent中,主要是從請(qǐng)求中取得用戶(hù)輸入的值,然后進(jìn)行處理,最后賦值給容器或者頁(yè)面,上面的例子中會(huì) 調(diào)用頁(yè)面類(lèi)的getPicture().setPrice(“用戶(hù)輸入的值”)來(lái)進(jìn)行賦值。這樣整個(gè)表單的提交就可以理解為所有的表單組件讀取用戶(hù)輸入的 值并賦值給頁(yè)面的過(guò)程。
          整個(gè)表單提交的詳細(xì)處理過(guò)程如下:
            * initialize():頁(yè)面初始化
            * pageBeginRender() ("rewind"):getRequestCycle().isRewinding()為true
            * rewind of the form / setting of properties:所有表單組件調(diào)用rewindFormComponent來(lái)取值賦值
            * Deferred listeners (for Submit components):調(diào)用Submit組件的listener
            * Form's listener:調(diào)用Form組件的listener
            * pageEndRender() ("rewind"): getRequestCycle().isRewinding()為true
            * pageBeginRender() (normal): getRequestCycle().isRewinding()為false
            * pageEndRender() (normal): getRequestCycle().isRewinding()為false
          我 們可以看到pageBeginRender和pageEndRender被調(diào)用了兩次,兩次中的區(qū)別為RequestCycle(). isRewinding,因?yàn)槲覀冊(cè)谑褂脮r(shí)經(jīng)常利用pageBeginRender的初始化值,所以這里有很多使用上的誤區(qū),如果在 pageBeginRender中從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)來(lái)初始化跟表單提交無(wú)關(guān)的變量的話,就可能被調(diào)用兩次,這個(gè)是應(yīng)該避免的。什么叫跟表單提交無(wú)關(guān)的變量 呢,就是表單組件中跟賦值無(wú)關(guān)的,例如上邊提到的value="ognl:picture.price",這時(shí)picture就是與表單提交相關(guān)的變量, 如果你沒(méi)有初始化,那么在賦值時(shí)調(diào)用getPicture().setPrice()就會(huì)出現(xiàn)空指針異常,因?yàn)檫@是的picture為null。我們舉個(gè) 例子來(lái)看一下表單無(wú)關(guān)的變量,假如這個(gè)picture頁(yè)面會(huì)顯示一個(gè)創(chuàng)建picture的表單和所有picture的列表,那這個(gè)picture的列表就 是與表單提交無(wú)關(guān)的變量,如果你在pageBeginRender中初始化的話,就需要區(qū)分是否rewind,否則表單提交時(shí)就會(huì)被初始化兩次,讓我們看 一下代碼:
          代碼
          1. public?abstract?void?setPictures(List<Picture>?pictures);??
          2. public?abstract?void?setPictureInList();//用于For中的value??
          3. public?abstract?void?setPicture(Picture?picture);//用于表單創(chuàng)建??
          4. public?abstract?Picture?getPicture();??
          5. public?void?pageBeginRender(PageEvent?event)?{??
          6. if(getPicture()==null){??
          7. setPicture(new?Picture());??
          8. }??
          9. setPictures(getPictureService().findAll());??
          10. }??
          判 斷picture是否為null并賦值在頁(yè)面顯示和rewind中都是需要的,因?yàn)轫?yè)面顯示時(shí),需要調(diào)用getPicture().getPrice (),頁(yè)面rewind時(shí),需要調(diào)用getPicture().setPrice(),這兩個(gè)階段中的picture都不能為null。但 setPictures會(huì)在表單提交時(shí)被調(diào)用兩次,在rewind階段初始化它是沒(méi)有用處的,所以這時(shí)就要對(duì)是否rewind進(jìn)行判斷。修改后的代碼如 下:
          代碼
          1. public?void?pageBeginRender(PageEvent?event)?{??
          2. if(getPicture()==null){??
          3. setPicture(new?Picture());??
          4. }??
          5. if?(!event.getRequestCycle().isRewinding())?{??
          6. setPictures(getPictureService().findAll());??
          7. }??
          8. }??
          這 樣就可以避免在rewind時(shí)對(duì)pictures進(jìn)行不必要的賦值。這里還要提到的一點(diǎn)是頁(yè)面顯示和提交后的頁(yè)面很可能不是同一個(gè)頁(yè)面類(lèi)的實(shí)例,大家都知 道頁(yè)面類(lèi)的實(shí)例是從實(shí)例池取到的,用戶(hù)打開(kāi)頁(yè)面顯示表單完后的頁(yè)面類(lèi)實(shí)例和用戶(hù)提交表單時(shí)的用來(lái)rewind的頁(yè)面類(lèi)實(shí)例不一定是同一個(gè),即使是一個(gè)實(shí) 例,也是被重新初始化過(guò)的,不要想當(dāng)然的認(rèn)為顯示表單后再提交那個(gè)實(shí)例應(yīng)該保存原來(lái)顯示的東西,這個(gè)應(yīng)該理清楚。
          posted on 2007-03-30 22:32 Tapestry 閱讀(472) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Tapestry
          主站蜘蛛池模板: 韶山市| 威远县| 延边| 荥经县| 木里| 渑池县| 奈曼旗| 巴中市| 阳原县| 溧阳市| 宜黄县| 余庆县| 德昌县| 灌阳县| 若尔盖县| 罗城| 华坪县| 广州市| 莱州市| 宝清县| 金山区| 阿合奇县| 达日县| 武冈市| 永丰县| 横山县| 武隆县| 太谷县| 巨野县| 扶余县| 永福县| 高邑县| 泌阳县| 加查县| 宁城县| 江都市| 新干县| 凭祥市| 丰都县| 遵义县| 六盘水市|