Tapestry4开发指南.docx
《Tapestry4开发指南.docx》由会员分享,可在线阅读,更多相关《Tapestry4开发指南.docx(48页珍藏版)》请在冰豆网上搜索。
Tapestry4开发指南
Tapestry4开发指南
一,简介
使用“开发指南”这个名词,实在是惭愧。
随着接触面的增广,随着各种技术的不断了解,才逐渐发现自己欠缺得更多。
书读得越多,才发觉自己的知识越匮乏。
半年前,非常自不量力地将自己对Tapestry3.0.x的实践总结出来,写了一个所谓的《Tapestry开发指南》,而现在Tapestry4发布,我觉得将这个所谓的“开发指南”更新到Tapestry4,对自己来说,更像是一种交代。
有很多不足之处,希望朋友们能够不遗余力地指出,就是对我最大的支持。
Tapestry4的雏形是Tapestry3.1,Tapestry的作者Howard,不光开发了Tapestry,还同时开发了一个轻量级框架Hivemind。
所以Tapestry3.1的开发一开始就处于Hivemind框架之下。
后来由于种种原因,Howard没有将Tapestry3.1从Hivemind中剥离出来,于是就成为了今天的Tapestry4.0。
很多朋友都不是很认同Hivemind,认为Hivemind是与Spring类似的IoC框架。
刚开始的时候,我也同样很不认同Hivemind,毕竟使用Spring很熟悉了。
而且我们团队的整个技术架构已经日趋成熟。
就如同我当初评价Tapestry4与Hivemind之间的融合:
“除非有足够且必要的理由,不然别说让我去说服团队将Spring转型为Hivemind,就连我自己都说服不了自己。
”
随着对Tapestry4的深入,我开始理解为什么Howard没有将Tapestry从Hivemind中剥离。
就团队而言,我依然不认为有必要说服团队转型。
但是就我个人而言,仅仅在IoC和DI的使用上,我却觉得使用Hivemind比Spring简单。
当然,简单并非最重要的理由,但是当我们处于某一个特殊条件下,或许使用Hivemind也不失一个值得参考的选择。
另外,最重要的是,如果着眼于Tapestry本身,Hivemind就好比是一个良好的地基,Tapestry作为上层建筑,任何我们认为不合理,不适合自己特殊需要的Tapestry官方实现,都可以通过Hivemind的IoC及DI进行重构。
于是,现在的Tapestry4变得非常有趣,首先,它本身是一个框架,可以使用Tapestry4来创建动态,灵活的web应用程序,另外,可以通过Hivemind对Tapestry4自身功能进行重构,以便实现任何我们希望达到的特殊功能。
打个比方说:
Tapestry4就好比一把起子,我们可以通过Hivemind对这把起子的起子头进行任意更换,这样我们就可以适应任何形状或者接口的螺丝。
在后面,我们会看到令人兴奋的示例来介绍这种“换起子头”的思想。
关于Tapestry4.0的理论知识,如果有兴趣,可以参看我以前写的,关于Tapestry3.0的开发指南。
实际上,虽然版本升级了,使用方式也有了很大变化,但是Tapestry本质的思想和理论并没有变化。
这就是为什么虽然Tapestry4.0才刚刚发布,我却可以比别人更快地熟悉Tapestry4.0的使用。
对于理论的介绍,这里就不在累述了。
记得我以前学习Tapestry3.0的时候,还是通过查询Tapestry2.4的理论资料来学习的。
对于本文档,我希望定位在快速熟悉Tapestry4.0。
凡是我在本文档中提到的组件,如果没有做特别解释,那么就表示其用法与T3中基本相同,而对于T3的组件,我在以前些的文档中已经介绍了绝大部分。
所以如果你是新手,建议你先参看我以前写的文档(
二,QuickStart
现在Tapestry4已经发布beta-9版本,从其changelog上,我们可以看到,Tapestry4的开发已经日趋成熟,基本上官方现在修改最多的都已经仅仅是文档。
所以,我现在已经在使用Tapestry4来开发项目。
为了配合这篇userguide,我写了一个quickstart示例。
我们可以一步一步从项目配置开始,逐步了解Tapestry4。
1)搭建环境
我们需要如下东东:
Eclipse3.1及其以上版本:
http:
//www.eclipse.org/downloads/index.php
MyEclipse4.0及其以上版本:
JavaSE5.0及其以上版本:
Resin3.0.x:
Tapestry4.0包:
http:
//jakarta.apache.org/site/downloads/downloads_tapestry.cgi
Tapestry4.0支持包:
http:
//jakarta.apache.org/tapestry/dependencies.html
OK,现在我们开始搭建Tapestry项目。
对于Eclipse的配置,我们就略过了。
使用MyEclipse新建一个WebProject:
我们将项目名称命名为MyTapestry4:
点击Finish,我们新建了一个WebProject:
然后我们将下载好的Tapestry4及其支持包拷贝到WEB-INF/lib/目录中:
然后将包文件载入项目:
OK,基本的项目配置完成,现在我们在src下新建包:
com.tapestry4:
然后在WEB-INF目录下新建一个XML文件,命名为hivemind.xml,内容如下:
在这里,hivemind.xml中module的id是与java包名com.tapestry4对应的,这个id只是起标识的作用,因为Hivemind可以拥有很多的配置文件,所以一般都使用包名作为id以保证唯一性。
接着,我们在WEB-INF/目录下再新建一个application文件MyTapestry4.application,其内容如下:
在application文件中,我们做了两件事:
第一:
声明了项目名称:
name=”MyTapestry4”;
第二:
我们定义了page文件与java文件相互对应的默认包路径,Tapestry4根据这个路径自动去寻找与Home.page同名的Home.java文件,如果找不到,那么就会默认使用BasePage类。
然后我们进行web.xml配置:
为了测试项目是否已经正常配置,我们可以做点小测试:
首先在com.tapestry4下新建一个Home.java文件:
在Tapestry4中,java文件可以不再是abstract的,这个差别相比于Tapestry3还是很突出的。
因为一个很简单的理由,一旦Tapestry4的java文件不再是抽象类,那么就可以进行单元测试了。
在后面,我们会看到如何进行单元测试。
接着在WEB-INF/下建一个Home.page文件:
最后,我们在web/目录下新建一个Home.html文件:
2)让我们的项目跑起来
将resin解压到硬盘,当然,使用tomcat,jetty等,都可以用下面的方式来启动项目。
首先,打开Eclipse的Window->Preference:
在MyEclipse的ApplicationServer选项下,我们找到Resin3,然后在右边进行Resin配置。
首先指定ResinServer为Enable,然后指定ResinHomeDirectory地址。
然后我们要确保JDK的版本是否正确,并且加载两条JVM参数:
-Dorg.apache.tapestry.disable-caching=true
-Dorg.apache.tapestry.enable-reset-service=true
使用过Tapestry3的朋友对这两条参数都非常熟悉了,它们的作用是关闭Tapestry的页面缓存,这样就能够让我们在开发项目的时候,修改html和page之后,不需要频繁地重新启动项目。
但是在加载这两条参数之后,内存消耗比较大,所以在项目发布的时候,我们就不再使用这两条参数了。
一旦你正确地配置了Resin,我们就可以在MyEclipse中启动Resin了。
首先点击MyEclipse的J2EE项目配置管理:
然后在下拉菜单中选择我们的MyTapestry4项目,点击右边的Add按钮:
选择我们已经配置好的ResinServer,最后点击Finish。
OK,现在我们可以清楚地看到,我们的项目已经被部署到Resin的deploy目录下了。
接着,我们启动Resin,就可以启动我们的项目了:
在Eclipse的控制台,我们可以清楚地看到项目启动的整个过程:
嘿嘿,OK了。
我们的项目已经搭建成功,打开一个浏览器,在地址栏中输入:
http:
//127.0.0.1:
8080/MyTapestry4/app
其实搭建Tapestry4项目,很简单吧?
^0^
三,更深入使用Tapestry4.0
现在,我们还是和以前一样,做一个最熟悉的示例:
购物车。
只是这次我们手把手一步一步地完成这个示例。
1)登陆
OK,现在项目已经搭建完成了,对于购物车示例,第一个页面应该是一个登陆页面。
登陆页面应该有一个表单,有一个用户名输入,一个密码输入,同时还需要对用户名和密码进行效验。
修改Home.java文件如下:
packagecom.tapestry4;
importorg.apache.tapestry.IRequestCycle;
importorg.apache.tapestry.html.BasePage;
publicabstractclassHomeextendsBasePage{
//用户名
publicabstractStringgetUsername();
//密码
publicabstractStringgetPassword();
//登陆表单的监听方法
publicvoidloginSubmit(IRequestCyclecycle){
System.out.println(this.getUsername());
System.out.println(this.getPassword());
}
}
在Home.page文件中,我们修改如下:
xmlversion="1.0"encoding="GBK"?
>
DOCTYPEpage-specificationPUBLIC
"-//ApacheSoftwareFoundation//TapestrySpecification4.0//EN"
"http:
//jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
loginSubmit"/>
首先我们看到的是对username和password两个property的定义,与Tapestry3不同的是,现在Tapestry4.0不需要为property指定类型,也就是说,Tapestry4.0会根据程序实际运行时装载到property的数据来自动转换对应的类型。
在java中,我们声明了两个property调用的抽象方法:
//用户名
publicabstractStringgetUsername();
//密码
publicabstractStringgetPassword();
因此,即便不用在page中声明这两个property的类型,Tapestry4.0也知道它们是String。
接着我们声明了三个组件:
loginSubmit"/>
Form组件和TextField组件的基本定义和用法与Tapestry3.0差不多,所以对其原理这里就不再累述。
对于Home.html我们修改如下:
登陆
|
用户名:
|
密码:
|
|
在Html中嵌入jwcid与Tapestry3.0一样,只是唯一不同的是,在Tapestry4.0中,“jwcid”这个名词可以修改为你任意指定的单词。
现在,开启服务器,启动项目,我们会看见一个表单页面:
然后我们输入用户名和密码,就可以看见eclipse的控制台打印出对应的值:
其实仔细看看Home.java中的loginSubmit监听方法,其IRequestCycle参数我们并没有使用,所以,该监听方法可以简便为:
//登陆表单的监听方法
publicvoidloginSubmit(){
System.out.println(this.getUsername());
System.out.println(this.getPassword());
}
现在,我们再增加一些表单效验,比如,我们要求进行客户端用户名和密码效验,它们都必须输入,而且密码必须大于6位字符,于是修改Home.page中的Form组件和TextField组件声明为:
loginSubmit"/>
required"/>
【用户名】"/>
required,minLength=6"/>
【密码】"/>
运行项目之后,我们忽然发现如下页面:
从Tapestry4的报错页面中,我们发现,原来一旦对TextField添加客户端效验,就必须让其运行在Body组件之中,那么我们在Home.html的
标签中添加Body组件:
再次访问Home页面,OK,一切正常:
也许你觉得非常奇怪,我们并没有写任何JavaScript代码,那么又如何完成客户端的JavaScript效验呢?
这就是Tapestry组件动态script的魅力了。
在这里我们使用的Form组件,在Tapestry4.0中,Form组件自带了一些动态script代码,不论Form组件使用在任何情况下的任何项目中,只要开启
就可以实现JavaScript效验。
Tapestry的组件就好比一个黑盒子,动态script就好比这个盒子中一块我们不需要了解的JavaScript代码,只要我们按动这个“盒子”上的一个“开关”,动态Script就会通过Tapestry框架自动生成适应当前表单的JavaScript代码。
因此,即便这段动态Script不是我自己写的,我同样可以毫无顾忌地使用。
2)水果商店
OK,现在登陆已经实现了,现在我们来为“购物车”添加一些商品,假设我们都是卖水果的:
我们定义一个普通的水果VO:
packagecom.tapestry4;
publicclassFruit{
privateIntegerid;
privateStringname;//名称
privatefloatprice;//单价
privateintmount;//数量
publicintgetMount(){
returnmount;
}
publicvoidsetMount(intmount){
this.mount=mount;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicfloatgetPrice(){
returnprice;
}
publicvoidsetPrice(floatprice){
this.price=price;
}
publicIntegergetId(){
returnid;
}
publicvoidsetId(Integerid){
this.id=id;
}
}
然后定义一个商品业务逻辑类:
packagecom.tapestry4;
importjava.util.ArrayList;
importjava.util.List;
publicclassProducts{
privatestaticListproductList;
publicstaticListgetProductList(){
if(productList==null){
productList=newArrayList();
productList.add(createFruit(1,"苹果",1.00f,20));
productList.add(createFruit(2,"西瓜",0.80f,10));
productList.add(createFruit(3,"桔子",1.50f,25));
productList.add(createFruit(4,"梨子",2.00f,30));
}
returnproductList;
}
publicstaticFruitcreateFruit(Integerig,Stringname,floatprice,intmount){
Fruitfruit=newFruit();
fruit.setId(ig);
fruit.setName(name);
fruit.setPrice(price);
fruit.setMount(mount);
returnfruit;
}
publicstaticFruitfindFruitById(Integerig){
if(productList==null){
productList=getProductList();
}
Fruitfruit=null;
for(Fruitf:
productList){
if(f.getId().intValue()==ig.intValue()){
fruit=f;
}
}
returnfruit;
}
}
现在,我们需要一个展示商品的页面,命名为FirstPage:
Shop.java
packagecom.tapestry4;
importjava.util.List;
importorg.apache.tapest