|
一、 引言 TSH,Tapestry3.03(以下稱T3)+Spring1.26+Hiebernate3.05這是我們開發(fā)項(xiàng)目所用的框架,其中Tapestry的版本變化很快,目前已經(jīng)達(dá)到了5.0bata版,Tapestry4(以下稱T4)已經(jīng)成為大部分Tapestry開發(fā)人員的主流開發(fā)工具,不管在論壇還是在組件交流區(qū),T4都有著比T3的優(yōu)勢(shì)。T4到底和T3的區(qū)別是什么?T4能否參與TSH?
二、 Tapestry4和Tapestry3區(qū)別 1. 前提條件: Tapestry4 幾乎可以和任何相對(duì)較新的 Java 版本合作(Java 1.3 及以上版本),但最好是使用 Java 5.0。Tapestry 的幾個(gè)可選特性只能在 Java 5 下工作。而且,現(xiàn)在真的是沒有什么理由不 轉(zhuǎn)換到 Java 5:它是穩(wěn)定并經(jīng)過良好測(cè)試的,已經(jīng)經(jīng)過了最初始的發(fā)展痛苦。 2. 微內(nèi)核: tapestry4.0中使用hivemind作為微內(nèi)核,Hivemind也是一個(gè)依賴注射的容器,其功能有一部分與spring重合。 3. org.apache.tapestry.engine:T4參與TSH不能像T3 在engine類將Spring應(yīng)用上下文作為“appContext” 屬性存放在Tapestry應(yīng)用的“Global”對(duì)象中。
4. T4的升級(jí)主要是體現(xiàn)在以下幾個(gè)新特性:
Tapestry4新特性(一)-default binding types
一、default binding types(默認(rèn)的綁定類型) 每一個(gè)組件的參數(shù)都可以定義默認(rèn)的綁定類型,如果一個(gè)綁定的參數(shù)沒有前綴,將使用默認(rèn)的綁定類型。 下面的代碼實(shí)現(xiàn)同樣的功能: <ul element="ul" jwcid="@Foreach" source="ognl:items" value="ognl:item"> <li><span jwcid="@Insert" value="ognl:item.name"/> </ul> <ul element="ul" jwcid="@Foreach" source="items" value="item"> <li><span jwcid="@Insert" value="item.name"/> </ul> 加粗的部分顯示前后的變化,之所以可以這樣定義,是因?yàn)镮nsert組件定義value參數(shù)的默認(rèn)綁定類型為ongl. 注意:默認(rèn)的綁定參數(shù)總是可以被顯式的綁定聲明覆蓋掉。 如果沒有定義默認(rèn)的綁定參數(shù),那么在html模板中定義的默認(rèn)綁定參數(shù)為literal,頁面定義文件里的默認(rèn)綁定參數(shù)為ognl 修訂: 從beta4版本開始,此特性已經(jīng)被刪除, Beta4的change log: Remove default-binding attribute from element(HLS) 但是“如果沒有定義默認(rèn)的綁定參數(shù),那么在html模板中定義的默認(rèn)綁定參數(shù)為literal,頁面定義文件里的默認(rèn)綁定參數(shù)為ognl”這個(gè)效果經(jīng)測(cè)試依然存在。 懷念: 此段文字在beta3中存在,beta4后就刪掉了! Binding Type Defaults Tapestry 4.0 introduces a new idea: default binding types. Each component parameter may define a default binding type (using the default-binding attribute of the <parameter> element). If a binding reference does not have a prefix, the default binding type is used. Because of this, the following two snippets are identical: <ul element="ul" jwcid="@Foreach" source="ognl:items" value="ognl:item"> <li><span jwcid="@Insert" value="ognl:item.name"/> </ul> <ul element="ul" jwcid="@Foreach" source="items" value="item"> <li><span jwcid="@Insert" value="item.name"/> </ul> This works because the Insert component defines the default-binding for the value parameter to be "ognl". Likewise, the source and value parameters of the Foreach component are defined to be "ognl". However, the element parameter of the Foreach component has a binding type of "literal". This is a decision made by the component author. If a particular parameter is (nearly) always bound using a particular binding type, then a default-binding may be set. The default binding can always be overriden with an explicit binding type prefix. What about parameters that don‘t define a default binding type? The answer to this question (which includes all informal parameters), is that it depends on whether the parameter is bound in an HTML template, or in a page or component specification. In an HTML template, the default binding type is "literal". In a specification, the default binding type is "ognl".
Tapestry4新特性(二)-listener method
二、listener method 如果使用過tapestry的應(yīng)該知道listener方法在4.X以前版本中的定義,如public void formSubmit(IRequestCycle cycle),方法必須 有一個(gè)IRequestCycle參數(shù)。參數(shù)的取得方式如下:Object[] parameters = cycle.getServiceParameters(); 在4.X中參數(shù)的取得可以通過以下兩種方式: 1. 調(diào)用IRequestCycle.getListenerParameters()方法,需要傳入IRequestCycle實(shí)例作為參數(shù)。 2. 按照參數(shù)的聲明順序依次定義為listener方法的參數(shù)。 第二種方法比較符合軟件的設(shè)計(jì)思維,而且參數(shù)的類型在傳入后保存,而不是想象中的統(tǒng)一String類型。 例如: <a jwcid="@DirectLink" listener="doClick" parameters="{ objectId, index }"> . . . </a> 其中objectId為String類型,index為int,聲明中使用了默認(rèn)的參數(shù)綁定類型。 對(duì)應(yīng)的方法聲明如下 public void doClick(String objectId, int index) { . . . } 此為第二種方式,可見方法的定義符合自然習(xí)慣,當(dāng)然你也可以通過傳統(tǒng)的方法,如下所示: public void doClick(IRequestCycle cycle) { Object[] parameters = cycle.getListenerParameters(); String objectId = (String)parameters[0]; int index = ((Integer)parameters[1]).intValue(); . . . } 這種方式是為了向后兼容以前的版本,當(dāng)然也適用那種參數(shù)數(shù)目不確定的情況。 Tapestry默認(rèn)搜索以下的方法聲明: • public void method(parameters)(頁面的跳轉(zhuǎn) cycle.activate()如何實(shí)現(xiàn)?) • public void method(IRequestCycle cycle, parameters) (傾向于使用此方式) • public void method()(無需參數(shù)傳遞和頁面跳轉(zhuǎn)的情況,估計(jì)可能性不大) • public void method(IRequestCycle cycle)(傳統(tǒng)方式) 不要試圖通過參數(shù)的類型來映射listener方法,tapestry是根據(jù)參數(shù)的數(shù)目來確定方法的。
Tapestry4新特性(三)-global property source
三、Global Property Source(全局的消息屬性配置) 消息屬性配置聽起來不是很舒服,暫時(shí)這樣稱呼好了,消息屬性配置也就是通稱的國際化配 置,通過配置一個(gè)properties文件使不同語言的瀏覽者看到對(duì)應(yīng)語言的版本,一般 的使用如下,一個(gè)page頁面,例如example.page,同目錄下放一個(gè) example.properties,在 example.html中使用<span key="key"/>來指定顯示值, 中文可以使用example_zh_CN.properties來配置??雌饋硗Ψ奖愕?,可 tapestry4.0以前的版本的國際化不支持全局的屬性配置文件,必須每個(gè)頁面定義 自己的,無法幾個(gè)頁面共享,但實(shí)際開發(fā)中,多頁面共享屬性配置是很常見的, tapestry4.0中可以通過以下方式獲得全局的屬性配置文件: 創(chuàng)建一個(gè)跟你的項(xiàng)目全局配置文件,如yourApp.application,此文件在4.0以前的 版本中是必須的,4.0中如果沒有必要配置,可以不需要此文件(扯遠(yuǎn)了),yourApp 是根據(jù)你在web.xml定義的,例如 <servlet> <servlet-name>tapesty4</servlet-name> <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> 那屬性定義文件就應(yīng)該是tapestry4.properties,這樣在此文件中定義一個(gè):test= 測(cè)試,在Home.html中使用< span key="test">test</span>,看到“測(cè)試”正確顯示。
Tapestry4新特性(四)-源代碼標(biāo)注的異常處理
Tapestry本來提供的debug功能就十分強(qiáng)大,4.0版本中提供了更加詳細(xì)的報(bào)錯(cuò)機(jī)制,可以顯示錯(cuò)誤的代碼,并在報(bào)錯(cuò)的地方加亮標(biāo)注,具體截圖 (省略)
Tapestry4新特性(五)-Friendly URLs
Tapestry4.0以前版本中的URL一直被人所詬病,當(dāng)然現(xiàn)在已經(jīng)有很多的解決方 案,4.0版本中已經(jīng)對(duì)此做了改進(jìn), 因?yàn)楝F(xiàn)在的版本需要通過hivemind來配置,所以需要設(shè)置hivemind.xml中的一些屬 性,具體配置如下: <?xml version="1.0"?> <module id="tapestry4" version="1.1.0"> <contribution configuration-id="tapestry.url.ServiceEncoders"> <page-service-encoder id="page" extension="html" service="page"/> <direct-service-encoder id="direct" stateless-extension="direct" stateful-extension="sdirect"/> <asset-encoder id="asset" path="/assets/"/> <extension-encoder id="extension" extension="svc" after="*"/> </contribution> </module>
同時(shí)web.xml中加入映射: <servlet> <servlet-name>tapestry4</servlet-name> <servlet-class> org.apache.tapestry.ApplicationServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>tapestry4</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>tapestry4</servlet-name> <url-pattern>*.direct</url-pattern> </servlet-mapping>
<servlet-mapping> <servlet-name>tapestry4</servlet-name> <url-pattern>*.sdirect</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>tapestry4</servlet-name> <url-pattern>/assets/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>tapestry4</servlet-name> <url-pattern>*.svc</url-pattern> </servlet-mapping> 如果希望首頁的調(diào)用不是通過/app來映射,可以在web.xml中更改redirect: <filter-name>redirect</filter-name> <filter-class>org.apache.tapestry.RedirectFilter</filter-class> <init-param> <param-name>redirect-path</param-name> <param-value>/Home.html</param-value> </init-param> </filter> 這樣鍵入http://localhost:8080/tapestry4,系統(tǒng)導(dǎo)航到http://localhost: 8080/tapestry4/Home.html, 添加一個(gè)Page頁面例如Test.page,在Home.html中加入<a href="#" jwcid="@PageLink" page="Test">test</a>, 在生成的Home.html中生成的test的鏈接地址為:http://localhost: 8080/tapestry4/Test.html
Tapestry4新特性(六)-自動(dòng)定位頁面類文件
關(guān)于此特性的介紹請(qǐng)參考:http://jakarta./tapestry/current/UsersGuide/page-class.html 說明: 通俗點(diǎn)說就是您可以不定義.page文件或者定義的.page文件中不指定class 屬性,而讓服務(wù)器自動(dòng)根據(jù).html文件的路徑來尋找對(duì)應(yīng)的類文件。 配置: 在.application的定義文件中添加: <meta key="org.apache.tapestry.page-class-packages" value="org.edynasty.pages"/> 這樣如果在文檔根目錄下有個(gè)Home.html文件,你就可以將Home.java放到 org.edynasty.pages(實(shí)際開發(fā)中配置為您自己的包名)包中,tapestry自動(dòng)根據(jù) Home.hmtl構(gòu)造org.edynasty.pages.Home來定位頁面的類文件,當(dāng)然您也可以在WEB -INF目錄下放一個(gè)Home.page,不需要定義class屬性,tapestry自動(dòng)按照上邊的原 理定位。 效果: 這樣您可以不需要維護(hù).page中的class屬性,直接根據(jù).html文件來寫對(duì)應(yīng) 的類文件。而且可以根據(jù)業(yè)務(wù)邏輯來定義目錄結(jié)構(gòu),例如將 org.edynasty.pages.user定義為user相關(guān)的類,.html也就可以放到user目錄下 邊,目錄結(jié)構(gòu)如下: user/ListUsers.html user/EditUser.html course/ListCourses.html course/EditCourses.html Home.html
Tapestry4新特性(七)-Application和Session范圍對(duì)象的使用
Application和Session范圍對(duì)象的使用
關(guān)于此特性的介紹請(qǐng)參考:http://jakarta./tapestry/UsersGuide/state.html 說明: Application和Session范圍的概念就不說了,T4以前的版本只可以分別指定一個(gè)對(duì)象, 以前版本的定義如下: <property name="org.apache.tapestry.visit-class" value="your.package.Visit"/> <property name="org.apache.tapestry.global-class" value="your.package.Global"/>, T4中可以指定任意多的對(duì)象,而且默認(rèn)的visit和global仍然可以使用。
配置:在hivemodule.xml的定義文件中添加: <contribution configuration-id="tapestry.state.ApplicationObjects"> <state-object name="applicationUser" scope="application"> <create-instance class="org.edynasty.model.User"/> </state-object> <state-object name="sessionUser" scope="session"> <create-instance class="org.edynasty.model.User"/> </state-object> </contribution> 兩個(gè)user分別對(duì)應(yīng)Application和Session范圍,在需要使用user的page中注入: <inject property="applicationUser" type="state" object="applicationUser"/> <inject property="sessionUser" type="state" object="sessionUser"/>,通過 getter和setter方法調(diào)用。
效果:怎么說呢,可以不需要在一個(gè)visit中定義N多屬性,因?yàn)镾ession的創(chuàng)建需要資源, 只要操作一個(gè)visit的屬性,就需要?jiǎng)?chuàng)建整個(gè)visit,分別定義之后,可以在需要存取時(shí)分別創(chuàng)建。
三、 T4能否參與TSH
答案是肯定的,其實(shí)主要面臨的是T4與spring 的整合問題,簡(jiǎn)單實(shí)現(xiàn)描述如下: 通過hivemind在tapestry中使用spring
tapestry4.0中使用hivemind作為微內(nèi)核,Hivemind也是一個(gè)依賴注射的容器,其 功能有一部分與spring重合,但spring 有良好的用戶基礎(chǔ),所以使用hivemind訪 問spring中定義的bean是在tapestry中集成spring的關(guān)鍵,這個(gè)功能可以通過一個(gè) 軟件包實(shí)現(xiàn),項(xiàng)目地址:http:///projects/diaphragma/,下載 tapestry- spring.jar包,放入系統(tǒng)類路徑,就可以在頁面和組件的定義中使用 hivemind提供的注射功能訪問spring中的bean定義。 hivemind.xml不需要做任何 修改,但spring容器必須通過web容器啟動(dòng),web.xml中啟動(dòng)spring容器: <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <servlet> <servlet-name>context</servlet-name> <servlet-class> org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> 這樣spring中定義一個(gè)bean,例如 <bean id="user" class="tapestry4.pages.User"> <property name="name"> <value>jimlaren</value> </property> </bean>
Home.page中定義注入: <inject property="user" object="spring:user"/> Home.html中訪問:<span jwcid="@Insert" value="user.name" />
四、 在我們面前可選擇的這種架構(gòu)真的太多了,例如JSF,我們是將路標(biāo)指向它,還是繼續(xù)我們的Tapestry之路,是一個(gè)選擇。Tapestry的理念是先進(jìn)的,但是它版本的更換速度真的太快了,我們使用的工具M(jìn)yEclipse最新版本5.0M,對(duì)于新特性的支持里提到了JSF,竟然沒有提到對(duì)T4的支持。 而在新的開源項(xiàng)目Cognition Framework的實(shí)現(xiàn),完全是采用Tapestry + Spring + Hibernate (Cognition Modeler is an Eclipse plug-in, a RAD tool for developing open source Java web applications faster than you ever have before.),但是目前它還只對(duì)mysql支持穩(wěn)定,看來Tapestry的應(yīng)用還是有前景的。
|