Tapestry 5 组件类

Tapestry 5 组件类
本文档根据 http://tapestry.apache.org/tapestry5/tapestry-core/guide/component-classes.html 翻译整理过来,请高手指正,转载请注明出处!
 
Tapestry 5 的组件类要比 Tapestry 4 简单些,它们没有要继承的基类、是具体而非抽象的且没有 XML 文件,不过还是存在少量的以 Java annotations 形式的配置,但现在那些都直接声明在类的属性上,优于声明在抽象的 getters 和 settes 方法上( Tapestry 4 中)。
 
页面、组件和组件混入类都以同种方式创建。
组件类基础
在 Tapestry 5 中创建页面和组件轻而易举!
 
不同于 Tapestry 4 , Tapestry 5 中组件类不再是抽象的且不继承框架的基类。它们是纯粹的 POJOs ( Plain Old Java Objects )。
 
仅具有少量约束:
§           类必须声明是公共的( public )。
§           类必须放在正确的包下,按照 application configuration
§           类必须具有一个标准公 共 的无参构造器。
 
以下是一个非常基础的组件:
 
java 代码
  1. package org.example.myapp.components;   
  2.     
  3. import org.apache.tapestry.MarkupWriter;   
  4. import org.apache.tapestry.annotations.BeginRender;   
  5.     
  6. public class HelloWorld   
  7. {   
  8.     @BeginRender  
  9.     void renderMessage(MarkupWriter writer)   
  10.     {   
  11.         writer.write("Bonjour from HelloWorld component.");   
  12.     }   
  13. }   
这个组件仅用来输出一个固定的信息。 BeginRender annotation 是一个组件生命周期 annotation ,用来告诉 Tapestry 什么时候在什么情况下调用你类中的方法。
 
还有一点与 Tapestry 4 不同的是,方法不再需要声明为公共的 ( public ),可以具有你想要的任何可见性。
 
组件包
组件类必须存放在一个相应的包中(运行时代码转换和类重载的需要)。
这些包存放在应用根目录 ${root} 包下。
 
页面类放置在 ${root}.pages 下,页面名匹配于这个包下的类名。
 
组件类放置在 ${root}.components 下,组件类型(组件模板中标签属性 t:type 的引用)匹配于这个包下的类名。
 
混入( mixins )类放置在 ${root}.mixins 下, Mixin 类型匹配于这个包下的类名。
 
另外,整个应用存在基类很常见,通常是一些抽象的基类,不需要直接被引用。这些不应直接放在 pages 、components 、mixins 包下,因为它们这时看起来是有效的 pages 、 components 、 mixins ,我们用 ${root}.base 包来存放这些基类。
 
子文件夹/ 子包
 
类不必直接放入 ${root} 包下( pages 、 components 、 mixins 等等),可以创建子包来存放一些类。子包名将成为页面名或组件类型的一部分。因此你可以定义页面组件 com.example.myapp.pages.admin.CreateUser ,与此同时页面逻辑名(显示在 URL 上的)将会是 admin/CreateUser
 
页面与组件
 
在 Tapestry 5 中,页面与组件的区别已经非常小了。实际上仅有的不同就是包名: ${root}.pages.PageName 用于页面, ${root}. components.ComponentType 用于组件。
 
Tapestry 4 中,页面与组件的区别很大,暴露出分隔的接口以及用于编码继承的抽象实现体系。
 
Tapestry 5 中,页面仍用于表现,但它已真正成为 Tapestry 的内部( internal )类。页面组件仅仅是页面组件树的根组件。
 
类转换
 
Tapestry 以使用你的类做为出发点,在运行时对类进行转换,其原因就包括 Tapestry 如何在多个请求中缓存( pools )页面。
For the most part, these transformations are both sensible and invisible. In a few limited cases, they are maginally leaky -- for instance, the requirement that instance variables be private -- but we feel that the programming model in general will support very high levels of developer productivity.
类转换多半是合理的且不可见的,少数受限的情况下,它们的被忽略无关紧要——比如,一个实例需要是私有的——但是我们会发现设计模式通常会支持一个更高的开发效率。
 
因为转换发生在运行时,所以转换时并不会影响你实际中创建的 Tapestry 应用。此外,测试时你的类完全是简单的 POJOs 。
 
类重载
Component classes are monitored for changes by the framework. Classes are reloaded when changed. This allows you to build your application with a speed approaching that of a scripting environment, without sacrificing any of the power of the Java platform.
框架监视着组件类的改动,类改变时会被重载。 Classes are reloaded when changed. 这允许你在不需要牺牲任何 Java 平台能力的情况下,构建应用的速度接近于脚本环境。
 
实例变量
 
Tapestry 组件可以包含实例变量(不同于 Tapestry 4 ,你得使用抽象属性)。
 
实例变量必须是私有的 。 Tapestry 将会执行运行时类的修改来支持实例变量,而且仅对私有变量有效。类中可以有非私有的变量,由于 Tapestry 池化和重新使用页面与组件,你这时会看到应用中的意外行为。对含有非静态且非私有的属性变量, Tapestry 将输出一个错误日志。
 
注意你需要提供 getter 和 settter 方法访问你类的实例变量。 Tapestry 不会自动做这事。
 
瞬态实例变量
 
除非你的实例变量被 annotation 装饰,否则它就是瞬态的实例变量。这意味着它们的值在每一个请求结束时(当页面从请求中分离时)被重置为默认的值。
 
假如你的变量能够在多个请求中保持它的值,你就需要在变量上使用 Retain annotation 来打破这一重置的规则。你需要注意的是没有客户相关的数据存入在这个属性变量里,因为后面的请求,相同页面实例可能被不同用户所使用。与此同时,相同用户后来的发出请求,也可能是不同的页面实例被使用。
 
使用持久化属性变量( persistent fields )在多个请求中保持信息。
 
此外, final 属性变量不会被重置。
构造器
Tapestry 将会使用默认的无参构造器来实例化你的类。其它构造器将被忽略。
注入
依赖注入( Injection )通过附加的 annotations 发生在属性级别。在运行时阶段,属性包含的注入将变为只读性的。
参数
组件参数( Component parameters )也使用私有的类属性来表示,要在属性上加上 Parameter annotation 。
持久化属性
属性可以被加上 annotation 以便它们在跨请求中保持值。
内嵌的组件
组件通常包含其他组件,组件内置在其他组件里时就叫做内嵌的组件。包含内嵌组件的组件,其模板将包含 <comp></comp> 元素来识别内嵌组件放置在何处。
 
我们可以在模板中定义组件的类型,或者使用 Component annotation 定义组件类型与参数来创建组件实例变量,对于后者你不能提供 <comp></comp> 元素的类型属性,在模板中只提供 id 属性就行(假如你提供类型属性的话, Tapestry 将会使用使用被 annotation 声明的属性的类型并输出一个错误日志)。
Example:
java 代码
  1. package org.example.app.pages;   
  2.     
  3. import org.apache.tapestry.annotations.Component;   
  4. import org.example.app.components.Count;   
  5.     
  6. public class Countdown   
  7. {   
  8.     @Component(parameters =   
  9.     { "start=5""end=1""value=countValue" })   
  10.     private Count _count;    
  11.     
  12.     private int _countValue;   
  13.     
  14.     public int getCountValue()   
  15.     {   
  16.         return _countValue;   
  17.     }   
  18.     
  19.     public void setCountValue(int countValue)   
  20.     {   
  21.         _countValue = countValue;   
  22.     }   
  23. }    
 
以上定义的内嵌组件 id 为 "count" (此 id 源自属性的名字)。组件的类型是 org.example.app.components.Count 。 Count 组件的参数 start 和 end 绑定了字面值( literal values ), value 参数绑定了 Countdown 组件的 countValue 属性。
 
需要注意的是组件类里默认的绑定前缀是 "prop:" ,以上实例中我们可以写成 "value=prop:countValue" 来完整的显示绑定。
 
然而,某些字面值,比如上例中的数字字面值被接受为 prop: 前缀,即使他们并不是真正的属性(这给应用开发者带来了极大的方便)。我们也可以使用 "literal:" 前缀, "start=literal:5" 可以完成同样的事情。
 
我们可以在组件模板中指定其他的参数,但是组件类里的参数优先。
TODO: May want a more complex check; what if user uses prop: in the template and there's a conflict?
我们可以利用 Component annotation 的 id 属性覆盖默认的组件 id (即属性名)。
 
如果在组件类中定义一个组件,而模板中没有相应的 <comp></comp> 元素, Tapestry 会输出一个错误日志。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值