Tapestry

一、TAPESTRY技术的综述。
    tapestry是平行于struts/Spring MVC/webwork /jsf等开发工具的语言。tapestry是基于组件的开发工具。

它具有组件的可重用性。因为大量重复使用的Tapestry组件,以及高度复用的表现层逻辑,使得工作效率大幅度

提升。Tapestry组件是一个“黑盒子”,用于表现HTML响应,以及响应HTTP请求。
Tapestry组件通过其规范定义。规范是一个XML文档,其中定义了组件类型,参数,组件模板,包含的组件以及被

包含组件之间的联系,还有所有的assets。
    Tapestryde:优点:
    1) 能够保证对HTML最少限度的干扰,Tapestry对HTML页面的介入可以仅仅是增加一个jwcid(Java Web

Component ID)属性。这个明确地划分了美工和程序员之间的界限。
    2) 页面的描述基于组件, Page规范描述了组件之间的联系,而java文件负责处理逻辑。
    3) 由于表现层逻辑全部放在了java文件里面,相比JAVA SCRIPT描述更加灵活。
    4) 随着我们项目的深入开展,可复用的组件逻辑越来越多,开发的效率大大提高。
    Tapestry框架是标准Servlet API的一种扩展。它需要J2SDK1.2或更高版本的J2SDK和一个与Servlet API

2.2(或更高)兼容的应用服务器/Servlet容器。
    一个Tapestry应用由许多拥有唯一名称的页面组成。一个页面由一个模板和一些可复用的控件构成。模板由

标准的HTML标签和一些额外的属性和标签构成,这些额外的属性和标签是为了告诉Tapestry框架这个页面的那些

部分是由Tapestry控件组成。
    Tapestry应用拥有高度的可升级性,它利用缓存和对象池使每个请求的处理时间最小化。Tapestry应用拥有

跟传统Servlet应用相仿的性能。
    Tapestry的学习曲线会长一点,因为它与流行的Web应用框架不太相同 。
    注意我们需要三个文件:*.html/*.page/*.java,分别表示了HTML的模板,页面属性,逻辑属性。
    首先简介一下web.xml,这可以使我们了解TAPESTRY是怎么工作的。
    web.xml的描述:
    <?xml version="1.0"?>
    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd>
    <web-app>
     <display-name>test</display-name>
     <servlet>
        <servlet-name>tapestry</servlet-name>
        <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
     </servlet>

     <servlet-mapping>
        <servlet-name>tapestry</servlet-name>
        <url-pattern>/app</url-pattern>
     </servlet-mapping>
    </web-app>
    因为Tapestry框架是标准Servlet API的一种扩展,它实际上是建立在J2EE框架上的。这个从WEB.XML的描述

中可以看出.j2ee从URL的请求中分离出/app=>tapestry这个servlet名=>servlet-class

org.apache.tapestry.ApplicationServlet处理类.下面就与J2EE SERVLET处理的差不多了.
     可以猜测org.apache.tapestry.ApplicationServlet做了以下工作:
     1)拦截HTML文件,找到页面描述,创建类A,将其中的jwcid属性变换为对A的调用,从而获取属性值.进而获得页

面实例.A可能在创建之后放入对象缓冲池,以备后来使用。
     2)当提交表单时,处理LISTENER,处理页面表单逻辑.
     3)其他工作同STRUTS SERVLET类似.

二、在WINDOWS下如何使用TAPESTRY
    1. 从官方网站:http://tapestry.apache.org/download.html下载tapestry-bin-5.1.0.5.zip并解压到:

D:\tapestry\tapestry-project-5.1.0.5 ,需要指出的是D:\tapestry\tapestry-project-5.1.0.5\lib下包含了

开发一个Tapestry应用的全部jar包
    2. 安装myeclipse6.0。
    3. 下面介绍如何创建一个简单的tapestry应用
        启动 myeclipse ,新建 java web project.
        展开工程(test)右键点击JRE System library 选择 build path >> configure build path. 新对话

框中选择 libraries 选项卡,点击 add library>>user library>>user libraries>>new ,起一个名字本文中为

T5-lib 然后点击 add JARs 将 D:\env\tapestry-project-5.1.0.5\lib 目录下的全部jar文件导入. 然后选中

T5-lib 点击finish 。
        修改web-inf下web.xml文件,同前面例子。

    4. 在WebRoot目录下(web-inf同级目录),创建Home.html。(Tapestry程序入口,名字在.appliaction文件

中定义)代码如下:
<span jwcid="@Insert" value="ognl:HelloWorld" />
   
    5. 在web-inf目录下创建名为 Home.page 的xml文件。如下:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 4.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<page-specification class="mytapestry.Home">
        
</page-specification>
    6. 最后在 mytapestry 包下写一个java类:
package mytapestry;
import org.apache.tapestry.html.BasePage;
       
public abstract class Home extends BasePage{
     public String getHelloWorld(){
        return "Hello World!";
     }
}
    7. 启动tomcat 在浏览器输入 http://localhost:8080/test/app 应该看到如下页面
   
        Hello World!
       
   


   
三.Tapestry框架的简介

    一个基于Tapestry的web应用可能包含了以下几种文件:应用规范文件,hivemind配置文件,HTML模板文件,

页面规范文件,页面类文件,组件包规范文件,组件规范文件,组件类文件,动态脚本文件。下面一个一个来详

细讲述。
   
        1. 三种配置文件(应用程序规范文件,hivemodule配置文件,组件包规范文件)
   
        1.1 应用程序规范文件:是一个以应用程序servlet名称命名的,以“.application”为扩展名的xml文

件。一个web应用只能有一个应用程序规范文件。他制定了应用程序的各种细节配置,页面和组件配置,组件包配

置等等。如果我们不为应用程序配置应用程序规范文件,Tapestry会为我们提供一个默认的。
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE application PUBLIC
       "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
       "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
            
      <application name="test">
         <meta key="org.apache.tapestry.page-class-packages" value="test_path"/>
         <library id="contrib" specification-path="/org/apache/tapestry/contrib/Contrib.library"/>
         <page name="Home" specification-path="Home.page"/>
      </application>           
            <application>为根标签元素,name制定了serlvet名称。
            <meta>用于配置应用程序细节。在此我们为应用程序配置页面类的默认定义包路径。那么Tapestry

将自动在test_path路径下寻找页面类。
            <library>导入了外部组件包.
           
        1.2 hivemind配置文件:HiveMind框架是一个依赖注入微核心框架,Tapestry框架构建在HiveMind之上

。如果你的程序业务层没有用到hivemind,不必配置hivemodule文件。下面给了一个为应用程序配置Friendly

URL的例子:
<?xml version="1.0" encoding="UTF-8"?>
    <module id="test" version="1.0.0">
        <contribution configiration-id="tapestry.url.ServiceEncoders" />
            <direct-service-encoder id ="direct" stateless-extension="direct" stateful-

extension="sdirect" />
            <direct-service-encoder id ="action" stateless-extension="action" stateful-

extension="saction" />
            <page-service-encoder id="page" extension="page" service="page" />
            <page-service-encoder id="external" extension="external" service="external" />
            <asset-encoder id="asset" path="/assets" />
            <extension-encoder id="ext" id="ext" extension="svc" after="*"/>
    </contribution>
</module>
         1.3 组件包规范文件: 为了跨项目积累组件,我们可以将组件打成jar包,然后通过在应用程序规范文

件中引入组件包的方式,调用组件包中的自定义组件。组件包规范文件的后缀为“.library”的XML文件,命名任

意。
       
        2. Tapestry页面的组成
        2.1 HTML模板:HTML模板就是标准的静态HTML页面,在HTML模板中我们通过jwcid(Java Web Component

ID)标签属性调用Tapestry组件。例如上例中的 <span jwcid="@Insert" value="ognl:HelloWorld" />         

 
        在上面的代码中,调用了Tapestry的官方组件Insert,value属性是Insert组件的参数之一。"@"符号用

于区分jwcid是一个组件类型还是一个组件ID,如果是一个组件ID,tapestry将在HTML模板对应的页面规范中寻找

对应该组件ID的组件调用配置。(亦可这样理解,"@"为官方组件,无"@"为自定义组件,自定义组件需要在

“.page”文件中详细配置该组件的用法。)
           
        2.2 页面规范:是以页面名称命名且后缀是.page的XML文件,这个后缀为.page的XML文件必须声明

Tapestry的页面规范DOCTYPE。
            例如在上例中:
      <span jwcid="@Insert" value="ognl:HelloWorld" />     
      也可以这样来表示:
            HTML模板:
      <span jwcid="@Insert" value="ognl:HelloWorld" />
            页面规范:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE page-specification PUBLIC
 "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
 "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">
               
<page-specification class="mytapestry.Home">
    <component id="test" type="Insert">
        <binding name="value" value="HelloWorld" />
    </component>
</page-specification>
        2.3 页面类:必须继承org.apache.tapestry.html.BasePage类,如:
package mytapestry;
import org.apache.tapestry.html.BasePage;
           
    public abstract class Home extends BasePage{
    public String getHelloWorld(){
        return "Hello World!";
    }
}        3. Tapestry组件的组成
        在Tapestry中,一个组件通常由HTML模板,组件规范,组件类,动态脚本文件4个文件组成,除了组件规

范以外,其他三个文件都不是必须的。
   
        4. ognl
        OGNL是 Object Graph Navigation Language 的简称,是一种绑定方式的表达式语言。
        OGNL是OpenSymphony的一个开源项目。OGNL最重要的也是最根本的作用是简化调用Java类中的

getter/setter方法,同时,他也是一种功能单一且易于使用的表达式语言,OGNL表达式就式该语言的全部。对于

OGNL如何与模板对象绑定,Tapestry已经实现,我们不需要关心。同时,虽然OGNL表达式带有运算功能,但是

Tapestry框架将页面逻辑全部放到了页面类中,因此根本没必要使用OGNL表达式来处理页面逻辑。
        Tapestry框架的整个调用过程:Home.html -> Home.page -> Home.class


四、各种组件的使用(只列举了一些常用的,更多请参见TAPESTRY官方网站)
1、Foreach
   source:是对应的java类里的List 对象或者是个数组 需要抽象 或者提供set get方法
   value:是循环这个source对象代表当前的一个 ,需要在page文件中设置问一个属性,可以不在对应的java类

里有这个属性
   index:是循环的索引值 同value一样 在page文件中设置一个属性即可 <property name="index"/>
在循环的时候 会自动为vlaue和index赋当前的值

   <table cellspacing="6">
  <tr>
   <td>ID</td>
   <td>&nbsp;</td>
   <td>Name</td>
   <td>&nbsp;</td>
   <td>Level</td>
  </tr>
  <tr>
   <td colspan="5"><hr></td>
  </tr>
  <tr jwcid="@Foreach" source="ognl:customerList" value="ognl:customer" element="tr">
   <td><span jwcid="@Insert" value="ognl:customer.id"/></td>
   <td>&nbsp;</td>
   <td><span jwcid="@Insert" value="ognl:customer.fullName"/></td>
   <td>&nbsp;</td>
   <td><span jwcid="@Insert" value="ognl:customer.memberLevel"/></td>
  </tr>
</table>


<property-specification name="customerList" type="java.util.List" persistent="yes"/><property-

specification name="customer" type="Customer"/>
public abstract class SalesPage extends BasePage {
    public abstract List getCustomerList();
 
    public abstract List setCustomerList(List value);
}

public class Customer implements Serializable {
    private Integer id;
    private String fullName;
    private String memberLevel;
    public Customer(Integer id, String fullName, String memberLevel) {
        this.id = id;
        this.fullName = fullName;
        this.memberLevel = memberLevel;
    }

    public Integer getId() { return id; }
  
    public String getFullName() { return fullName; }

    public String getMemberLevel() { return memberLevel; }
}
    调用过程如下:source="ognl:customerList"==》getCustomerList()==》得到一LIST
    该LIST在FOREACH每次循环LIST中顺序取出一对象A(类型为ognl:customer),该对象A在FOREACH循环中它的

属性被引用(调用:getId() ,getFullName(), getMemberLevel() )。
     


2、Hidden组件 总是多余S的处理
 <input jwcid="@Hidden" type="hidden" value="ognl:blahblah" encode="false"/>
    用来存储一些页面的状态变量。

3、 Insert 组件 
    <input type="text" jwcid="name@Insert" value="ognl:user.name"/>
    页面表现时,将会到页面类中寻找getUser().getName()方法获取初值并输出
    相当于在页面上显示数据.

4、 TextField 组件 
    <input type="text" jwcid="username@TextField" value="ognl:username"/>
    页面表现时,将会到页面类中寻找getUsername()方法获取初值
    *如果是修改信息页面,通常初始值要在页面表现之前由setUsername()手动设置从数据库中读取出来的值
    表单提交时,通过setUsername()写入新值(即用户输入值),在类中通过getUsername()获取新值
    相当于在修改个人信息时,首先读出用户名赋予文本框(用户名)初值,用户修改时填入新值,后台获取之
    *Hidden属性区分是普通文本输入框(默认false)和密码输入框(hidden="ognl:true")
    readonly属性设置只读 readonly="true"为只读(后台可读取)
    *disabled属性设置是否可写 diabled="true"为不可写(后台也不可读取)

6、 TextArea 组件 
    <textarea jwcid="content@TextArea" value="ognl:content" cols="40" rows="10"></textarea>
    页面表现时,将会到页面类中寻找getContent()方法获取初值
    工作原理同TextField

7、 RadioGroup/Radio 组件 
    <span jwcid="headImage@RadioGroup" selected="ognl:headImage">
      <input jwcid="@Radio" type="radio" value="1"/>头像1
      <input jwcid="@Radio" type="radio" value="2"/>头像2
      <input jwcid="@Radio" type="radio" value="3"/>头像3
      <input jwcid="@Radio" type="radio" value="4"/>头像4
      <input jwcid="@Radio" type="radio" value="5"/>头像5
      <input jwcid="@Radio" type="radio" value="6"/>头像6
    </span>
    RadioGroup为每一个Radio提供一个唯一的ID。RadioGroup跟踪当前被选中的属性值,并且只有一个Radio能

够被选中.
    页面提交时,RadioGroup组件就利用OGNL表达式向headImage字段写入被选中的Radio组件的value参数值.
    页面表现时(修改页面),将会到页面类中寻找getHeadImage()方法获取初值,然后寻找@Radio组件中与其相同

的组件并勾选上.

8、 PropertySelection 组件
    使用PropertySelection组件必须要构造一个类来实现IPropertySelectionModel接口,并且重写该接口的5个

方法.
    public int getOptionCount() //提供下拉菜单的长度
    public Object getOption(int index) //提供select标签的option
    public String getLabel(int index) //提供select标签的Label值,也就是下拉菜单显示的内容
    public String getValue(int index) //提供select标签的value值
    public Object translatue(String value) //selected后的返回值,value值未必就是我们需要的返回

值,可以在这个方法里面对返回的value做对应的转换或修改.
    1.属性下拉框
    <select jwcid="gender@ProPertySelection" name="genderSelect" value="ognl:gender"

model="supportedGender">
      <option selected>先生</option>
      <option>女士</option>
    </select>


代码
GenderSelectionModel.java  
public class GenderSelectionModel implements IPropertySelectionModel {  
 
    public static final String male = "先生";  
 
    public static final String female = "女士";  
 
    public static final String[] genderOptions = { male, female };  
 
    public int getOptionCount() {  
        return genderOptions.length;  
    }  
 
    public Object getOption(int index) {  
        return this.translatue(genderOptions[index]);  
    }  
 
    public String getLabel(int index) {  
        return genderOptions[index].toString();  
    }  
 
    public String getValue(int index) {  
        return genderOptions[index];  
    }  
 
    public Object translatue(String value) {  
        if (value.equals("先生")) {  
            return "1";  
        } else {  
            return "0";  
        }  
    }  

 

代码
ModUserInfo.java  
public IPropertySelectionModel getSupportedGender() {  
    return new GenderSelectionModel();  


    存入数据库中"1"代表先生,"0"代表女士,通过translatue(String value)方法转换
    页面表现时,通过model属性给出的IPropertySelectionModel获取下拉选项,即getSupportedGender().
    然后通过getGender()方法获取初值,比如获取"0",则在页面显示时寻找value值为"0"的选项即为"女士",并选

择之作为初始选择项.

   2. 日志类型下拉框
    <select jwcid="logType@PropertySelection" name="typeSelect" value="ognl:logType"

model="supportedType">
      <option>心情日记</option>
      <option>情感天地</option>
      <option>生活感触</option>
    </select>


代码
TypeSelectionModel.java  
public class TypeSelectionModel implements IPropertySelectionModel {  
      
    private List typeList = new ArrayList();  
 
    public TypeSelectionModel(List typeList) {  
        this.typeList = typeList;  
    }  
 
    public int getOptionCount() {  
        return typeList.size();  
    }  
 
    public Object getOption(int index) {  
        return ((LogType)typeList.get(index)).getValue();  
    }  
 
    public String getLabel(int index) {  
        return ((LogType) typeList.get(index)).getName();  
    }  
 
    public String getValue(int index) {  
        return ((LogType) typeList.get(index)).getValue();  
    }  
 
    public Object translatue(String value) {  
        return value;  
    }  

 

代码
ModLog.java  
public IPropertySelectionModel getSupportedType() {  
    TypeSelectionModel typeSelectionModel =   
                           new TypeSelectionModel(loadType(getUser().getUserId()));  
    return typeSelectionModel;  
}  
 
private List loadType(int userid) {  
    ...//从数据库载入该用户的日志类型列表  


    页面表现时,通过model属性给出的IPropertySelectionModel获取下拉选项,即getSupportedType().
    然后通过value属性给出的初始值即,getLogType()方法获取初值,比如获取"2",则在页面显示时寻找value值

为"2"的选项即为"生活感触",并选择之作为初始选择项.

9、 Form组件 
    <form jwcid="logForm@Form">
      ...
    </form>
    Form的监听(listener)方法可以有两种方式:
      1. 在Form组件中声明.
        <form jwcid="logForm@Form" listener="ognl:listener:onLogin">
          ...
        </form>
      2. 在submit类型组件中声明.
        <input type="submit" jwcid="onLogin@Submit" listener="listener:onLogin" value="发表"/>或者
        <span jwcid="@ImageSubmit" image="..." listener="listener:onLogin"><img src="..." width=""

height=""/></span>
      前一种方式当Form中只要有submit就会触发监听方法,后一种方式是Form中有多个submit,各自实现不同的

监听方法.

9、 Conditional 组件 
    <span jwcid="@Conditional" condition='ognl:item.sex.equals("1")'>先生</span>
    <span jwcid="@Conditional" condition='ognl:item.sex.equals("0")'>女士</span>
    conditional参数为true时运行Conditional组件中的HTML模板内容.
    在Tapestry4.0以后就不支持该组件了, 可以使用其他组件来实现:
    1. Contrib:Choose和Contrib:When (contrib:外围爱好者根据需要自行编译并贡献的软件)
    <library id="contrib" specification-

path="classpath:/org/apache/tapestry/contrib/Contrib.library"/>(.application文件中引入Contrib类包)
    <span jwcid="@contrib:Choose">
      <span jwcid="@contrib:When" condition='ognl:user.gender.equals("1")'>先生</span>
      <span jwcid="@contrib:When" condition='ognl:user.gender.equals("0")'>女士</span>
    </span>
    2. If组件
    <span jwcid="@If" condition='ognl:item.sex.equals("1")'>先生</span>
    <span jwcid="@If" condition='ognl:item.sex.equals("0")'>女士</span>
    3. Else组件
    <span jwcid="@Else">man</span>


     本文是参考互联网相关文章写成的,这里向原始创新者表示感谢。其中有很多我自己的观点。希望大家在阅

读本文的基础上花费2-3天对TAPESTRY技术有个大致的了解。互联网讲的很松散也很难懂,我特意改变了他们的叙

转载于:https://my.oschina.net/huewenhua/blog/681639

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值