作者:Kenny Lee | 來源:http://www.topxp.org |
簡單介紹
不必關心鏈接!不必關心請求(http request)到了哪裏!不必關心響應(http response)要轉向哪裏!Tapestry構建於底層的request-resonse模式,基於Servlet技術,抽象出面向組件開發的模型。Tapestry關心的是:頁面、組件、事件、對象、方法、屬性!
安裝jar包
1、
將Tapestry解壓目錄下的lib目錄中的jar包拷貝到WEB-INF/lib目錄。
並將重複的包刪除(commons-logging.jar/javassist.jar/ognl-2.6.11.jar)
2、
在web.xml中添加:
<servlet> <servlet-name>app</servlet-name> <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/app</url-pattern> </servlet-mapping> |
這是Tapestry的中央控制器。Tapestry頁面的顯示,所有的請求,都會被髮送到這個Servlet上。
實例1:最簡單的Tapestry程序
在WebRoot下添加Home.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 </body> </html> |
並訪問網址:
http://localhost:8088/[context path]/app |
結果頁面顯示Home.html裏面的內容。
這是因爲Tapestry總是會包含一個名字叫”Home”的頁面,默認情況下就是根路徑下的Home.html
實例2:添加簡單的動態內容
Home.html改爲:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"> </span> </body> </html> |
重新訪問網址:http://localhost:8088/[context path]/app
在這個頁面上,用到了Tapestry的Insert組件(Component)。它帶一個參數,通過一個ognl表達式來傳遞。
在應用服務器的啓動參數中添加:-Dorg.apache.tapestry.disable-caching=true,可以避免每次修改頁面模板的時候重啓服務器。
jwc = Java Web Component
實例3:創建鏈接,指向某個頁面
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"></span> <p> <a href="#" jwcid="@PageLink" page="Home">刷新</a> </body> </html> |
這次,通過一個PageLink組件,指向Home頁面,PageLink組件會自動產生指向Home頁面的鏈接(我們不必關心這個鏈接!)。
實例4:簡單的計數器
直到現在爲止,我們還沒有涉及到java類,但是已經讓Tapestry成功運行起來了!該是寫點java代碼的時候了。我們想要創建一個計數器,每當用戶點擊“計數器增1”的時候,我們將這個計數器加1,然後在頁面上顯示出這個結果。
在傳統的請求-響應模式中,我們針對這個問題,需要考慮的是:遞交一個請求,創建相應的Action來接收這個請求,並維護計數器的值,然後決定成功轉向的頁面,將結果顯示在頁面上。
在Tapestry中,我們需要考慮的是:在哪個頁面處理這個事件,結果如何顯示在頁面上?
下面是Home.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"></span> <p> <a href="#" jwcid="@PageLink" page="Home">刷新</a> <p> 計數器當前的值是:<span jwcid="@Insert" value="ognl:counter"></span> <a href="#" jwcid="@DirectLink" listener="listener:doClick">計數器增1</a> </body> </html> |
DirectLink指定的listener爲:doClick,這將觸發一個事件,實際上就是將要調用doClick()方法。
doClick()方法將要寫在哪裏?因爲現在的頁面,其動態數據無法簡單獲得,所以,必須給當前頁面創建一個對應的類,我們的方法將創建在這個類裏面。
package com.bjsxt.crm.web.tapestry.test;
import org.apache.tapestry.annotations.Persist; import org.apache.tapestry.html.BasePage;
public abstract class Home extends BasePage {
@Persist public abstract int getCounter(); public abstract void setCounter(int count);
public void doClick(){ int counter = getCounter(); counter = counter + 1; setCounter(counter); } } |
注意:在這個例子中,類名需定義爲Home;listener的名字爲doClick,而不是doClick()
另外,需要在web-inf目錄下添加配置文件:app.application
<?xml version="1.0"?>
<!DOCTYPE application PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" "http://tapestry.apache.org/dtd/Tapestry_4_0.dtd">
<application> <meta key="org.apache.tapestry.page-class-packages" value="com.bjsxt.crm.web.tapestry.test"/> </application> |
配置的主要目的是讓Tapestry瞭解如何關聯頁面和頁面類。
實例5:帶一個參數的計數器
Home.html改爲:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"></span> <p> <a href="#" jwcid="@PageLink" page="Home">刷新</a> <p> 計數器當前的值是:<span jwcid="@Insert" value="ognl:counter"></span> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:1">計數器增1</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:5">計數器增5</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:10">計數器增10</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:clearCounter">清空計數器</a> </body> </html> |
對應的Home類:
package com.bjsxt.crm.web.tapestry.test;
import org.apache.tapestry.annotations.Persist; import org.apache.tapestry.html.BasePage;
public abstract class Home extends BasePage {
@Persist public abstract int getCounter(); public abstract void setCounter(int count);
public void doClick(int increment){ int counter = getCounter(); counter = counter + increment; setCounter(counter); }
public void clearCounter(){ setCounter(0); } } |
實例6:帶兩個參數的計算器
Home.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"></span> <p> <a href="#" jwcid="@PageLink" page="Home">刷新</a> <p> 計數器當前的值是:<span jwcid="@Insert" value="ognl:counter"></span> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:1">計數器增1</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:5">計數器增5</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:10">計數器增10</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:clearCounter">清空計數器</a> <br>
<a href="#" jwcid="@DirectLink" listener="listener:plus" parameters="ognl:{3,5}">計算3+5,</a> 計算結果是:<span jwcid="@Insert" value="ognl:result"></span> </body> </html> |
使用ognl:{param1,param2}這樣的方式來傳遞多個參數。
對應的Home類:
package com.bjsxt.crm.web.tapestry.test;
import org.apache.tapestry.annotations.Persist; import org.apache.tapestry.html.BasePage;
public abstract class Home extends BasePage {
@Persist public abstract int getCounter(); public abstract void setCounter(int count);
public abstract int getResult(); public abstract void setResult(int result);
public void doClick(int increment){ int counter = getCounter(); counter = counter + increment; setCounter(counter); }
public void clearCounter(){ setCounter(0); }
public void plus(int a,int b){ setResult(a + b); } } |
實例7:Tapestry表單及提交
假設現在要提交一個Person對象:
package com.bjsxt.crm.web.tapestry.test;
import java.util.Date;
public class Person {
//姓名 private String name;
//年齡 private int age;
//出生日期 private Date birthday;
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
我們在Home頁面添加一個鏈接指向添加頁面(AddPerson)
Home.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body> 第一個Tapestry程序 現在時間是:<span jwcid="@Insert" value="ognl:new java.util.Date()"></span> <p> <a href="#" jwcid="@PageLink" page="Home">刷新</a> <p> 計數器當前的值是:<span jwcid="@Insert" value="ognl:counter"></span> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:1">計數器增1</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:5">計數器增5</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:doClick" parameters="ognl:10">計數器增10</a> <br> <a href="#" jwcid="@DirectLink" listener="listener:clearCounter">清空計數器</a> <br>
<a href="#" jwcid="@DirectLink" listener="listener:plus" parameters="ognl:{3,5}">計算3+5,</a> 計算結果是:<span jwcid="@Insert" value="ognl:result"></span>
<p> <a href="#" jwcid="@PageLink" page="AddPerson">添加人員信息</a> </body> </html> |
AddPerson.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html jwcid="@Shell" title="添加人員信息"> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Insert title here</title> </head> <body jwcid="@Body"> <form jwcid="@Form" success="listener:save"> <table width="100%" border="0" cellspacing="1" cellpadding="0"> <tr> <td width="17%">姓名</td> <td width="20%"><input type="text" name="textfield" jwcid="@TextField" value="ognl:person.name"/></td> <td width="10%">年齡</td> <td width="19%"><input type="text" name="textfield2" jwcid="@TextField" value="ognl:person.age"/></td> <td width="10%">出生日期</td> <td width="24%"><input type="text" name="textfield22" jwcid="@DatePicker" translator="translator:date,pattern=yyyy-MM-dd" value="ognl:person.birthday"/></td> </tr> <tr> <td colspan="6"><div align="center"> <input type="submit" name="Submit" value="提交"/> </div></td> </tr> </table>
</form> </body> </html> |
注意:在頁面中的Tapestry組件(使用了jwcid標記)的標籤,必須有相應的close tag,特別注意<input/>標籤,必須有close tag。
AddPerson.java
package com.bjsxt.crm.web.tapestry.test;
import org.apache.tapestry.event.PageBeginRenderListener; import org.apache.tapestry.event.PageEvent; import org.apache.tapestry.html.BasePage;
public abstract class AddPerson extends BasePage implements PageBeginRenderListener{
public abstract Person getPerson(); public abstract void setPerson(Person person);
public void pageBeginRender(PageEvent event) { setPerson(new Person()); }
public void save(){ Person person = getPerson(); System.out.println("name="+getPerson().getName()); System.out.println("age="+getPerson().getAge()); System.out.println("birthday="+getPerson().getBirthday()); }
}
|
注意,需定義一個PageBeginRenderListener,來給Person賦予初始化值,否則,OGNL在解釋它(Person對象)的屬性時,會發生異常!
如何提交中文
我們必須在app.application中添加如下配置:
<?xml version="1.0"?> <!DOCTYPE application PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" "http://tapestry.apache.org/dtd/Tapestry_4_0.dtd"> <application> <meta key="org.apache.tapestry.template-encoding" value="GBK"/> <meta key="org.apache.tapestry.output-encoding" value="GBK"/> <meta key="org.apache.tapestry.page-class-packages" value="com.bjsxt.crm.web.tapestry.test"/> </application> |
如何轉向其它頁面
利用@InjectPage註解直接注入頁面。如:
@InjectPage("ShowProject") public abstract ShowProject getShowProject();
public IPage doSubmit() { ShowProject showProject = getShowProject();
showProject.setProject(getProject());
return showProject; }
|
Tapestry概要
在Tapestry中不用寫Action,而是listener method。你不用去構建URL地址,而是使用DirectLink組件,並配置它調用listener method。
Tapestry以組件爲中心。所謂以組件爲中心,即:
l Tapestry應用程序由一系列頁面(page)組成
l 頁面由更小的組件(Component)組成
l 組件本身也有可能由其它的組件組合而成的(不限制組合的深度)
l 每個頁面會有唯一的,不重複的名字
l 在每個頁面裏面的組件,其標識也是不能重複的(默認的情況下,Tapestry會給頁面中的每個組件自動生成一個ID標識)
Tapestry與Spring的集成
集成需要用到第三方的類庫,可以下載: http://howardlewisship.com/downloads/tapestry-javaforge/tapestry-spring-1.0.0-bin.zip
將其解壓之後,將其中的jar包拷貝到類路徑中。
在我們的頁面類中,就可以用@InjectObject(“spring:userManager”)等類似的方法來訪問userManager對象了。
如:
@InjectObject("spring:userManager") public abstract UserManager getUserManager(); |
Tapestry組件開發