`

Tapestry 5 页面导航

阅读更多
Tapestry 5 页面导航
 
 
本文根据http://tapestry.apache.org/tapestry5/tapestry-core/guide/pagenav.html翻译整理过来,请高手指正,转载请注明出处!
 
 
本质上,Tapestry应用是许多相关的工作在一起的页面的集合。从某种程度来说,每一个页面就是一个应用。
 
任何单个的请求对应一个页面。请求来源于两种形式:
  • 动作请求(Action Requests)指向一个特定的页面组件,在组件内部触发一个事件。
  • 呈现请求(render requests)指向一个特定的页面,将页面的HTML标记流输出到客户端。
动作请求与呈现请求的划分是Tapestry 5 中新出现的概念,它的某些方面是基于Portlet规范的思想,区分出这两种类型的请求减轻了许多在传统web应用中当用户使用浏览器的后退按钮或点击刷新按钮时的问题。
 
动作请求
 
动作请求表现为超链接(ActionLink)或表单提交(Form)的形式。
这两种情况,事件处理方法返回的值控制着送往用户端web浏览器的响应。
 
动作请求的URL包含页面名字、组件的嵌套id和在组件中触发事件的名字(通常是"action")。此外,一个动作请求可以包含额外的上下文信息(context information),以提供给事件处理方法(与方法参数有关)。
 
这些URL暴露了一些应用的内部结构。随着时间的推移,一个应用在维护中组件的id可能会改变,这就是说动作请求的URL不能被收藏(存为书签)。幸运的是,用户很少有这种机会来改变组件的id(参见下文):
 
以下是动件请求事件处理方法(动作的监听方法)的不同返回说明。
 
Null response
 
如果一个事件处理方法没有返回值或者返回null,此时当前页面(包含该组件的页面)会呈现响应(即响应请求)。
当前页面的页面呈现链接被创建并重定向到客户端。客户端浏览器随后提交的将是一个产生新页面的新请求。用户将会在浏览器看到一个新产生的内容。地址栏里的URL将会是一个呈现请求的URLrender request URL)。呈现请求的URL简短且包含较少的应用结构信息(比如,他不包含组件id和事件类型)。呈现请求URL是可供用户收藏的。动作请求URL是暂时性的,仅当应用处于激活状态时有意义,这并不意味着可以用于随后的session
 
String response
 
当返回一个字符串时,此字符串应该是页面的逻辑名(而非页面的全类名)。另外,页面的名字不区分大小写。
其次,呈现请求的URL被构造并重定向到客户端。
 
Page response
 
我们也可以返回一个页面实例,而非一个页面名字。
一个页面可以通过InjectPage annotation被注入。
通常,我们会在页面返回前以某种方式设置页面(举例如下,即对页面属性对象赋值)。
你也可以返回页面内的一个组件,但些时将会产生一个运行时警告。
 
Link response
 
事件处理方法可以直接返回一个Link实例,Link 被转换为URL然后重定向URL到客户端。
ComponentResources对象可以被注入到页面或组件中,它的方法可以创建action page链接(它们实际上定义在ComponentResourcesCommon中)。
 
Stream response
 
事件处理方法也能返回一个StreamResponse对象,这个对象封装了一个送往客户端浏览器的流(stream)。这对把组件产生的imagePDF送往客户端是很有用的。
 
Object response
 
事件处理方法返回任何其他对象类型都是错误的。
 
页面呈现请求(Page Render Requests
 
呈现请求在结构与行为上要比动作请求简单。简单情况下,URL仅仅是页面的逻辑名。
 
页面可以有一个活化上下文(activation context)。活化上下文表现为页面状态的持久化信息。实际上,活化上下文通常是一些数据库持久化对象的id
 
当一个页面有活化上下文时,上下文的值被追加到URL路径中。并不是所有的页面都有活化上下文。
 
当呈现请求链接被创建时,活化上下文可以被显式设值(PageLink组件有一个context参数可以用来设值)。当没有提供显式活化上下文时,页面会自己查找它的活化上下文。
 
这种查找表现为事件的触发。事件名字为passivate(我们马上会看到它的一个相对应的名字activate)。方法返回的值被用做上下文。
 
For example:
public class ProductDetail
{
 private Product _product;
  
  . . .
  
  long onPassivate() { return _product.getId(); }   
}
 
活化上下文可以由一连串的值组成,即方法返回的是数组或List列表。
 
页面激活Page activation
 
当一个页面呈现请求到来时,页面会在它呈现前被激活。
激活主要为了两个目的:
  • 它允许页面把内部状态数据编码到URL中(上面讨论到的活化上下文)。
  • It provides coarse approach to validating access to the page.它提拱了粗略的方法来校验页面是否可被访问。
后者提到的校验,通常涉及到用户标识及访问;如果我们的页面仅允许特定的用户访问,就可以用页面的激活事件来负责这个访问的校验。
一个页面的激活事件处理器(activate event handler)对应着它的钝化事件处理器(passivate handler):
 . . .
  
  void onActivate(long productId)
 {
     _product = _productDAO.getById(productId);
 }
  
  . . .
在此相关的部分是:当页面呈现时,它可能包含更多的动作请求URL(链接与表单)。那些链接与表单的动作请求也一样通过激活页面开始,然后再执行其他的操作。这形成了一个不断的包含同样活化上下文请求链。
 
从某种程度上说,我们也可以使用持久化页面值(persistent page value)来完成相同的效果,但这种方法需要一个激活的sessionURL不可收藏。
 
激活事件处理器(方法)也可以返回一个值,它与动作请求的事件触发器返回的值是一样的。这通常用于访问校验场景。
页面导航模式(Page Navigation Patterns)
动件链接和上下文及页面上下文可以以许多方式组合在一起。
让我们通过一个产品分类页来介绍一个经典的主列表/详细页关系的例子。在这个例子中,ProductListing页面是产品的列表页,ProductDetails页是相应的显示特定产品的详细页。
 
动作请求/持久化数据
 
这种模式下,ProductListing页面使用动作事件,ProductDetails页面使用了持久化属性。
 
ProductListing.html:
  <t:loop source="products" value="product">
    <a t:type="actionlink" t:id="select" context="product.id">${product.name}</a>
  </t:loop>
ProductListing.java:
 @InjectPage
 private ProductDetails _details;
  
  Object onActionFromSelect(long productId)
 {
    _details.setProductId(productId);
    
    return _details;
 }
ProductDetails.java:
 @Inject
 private ProductDAO _dao;
  
  private Product _product;
  
  @Persist
 private long _productId;
  
  public void setProductId(long productId) { _productId = productId; }
  
  void onActivate()
 {
    _product = _dao.getById(_productId);
 }
 
以上代码极少,也许对原型来说已经足够好了。
当用户点击一个链接时,动作请求URL起初类似http://.../productlisting.select/99,然后最终的呈现请求的URL将会类似http://.../productdetails。注意产品id"99")并没有显示在呈现请求的URL中。
 
它还有一些次要的缺点:
  • 它需要一个session(用来在请求之间保存_productId属性)。
  • 如果ProductDetails页面在被访问前已设置了一个有效的产品id,就有可能失败(原有值丢失)。
  • URL并没有指出产品的标识,如果用户收藏了这个URL,随后他们会引发先前的情况(没有有效的产品id)。
动作请求/活化上下文(Action Requests / Persistent Data??)
 
我们可以使用passivation activation 上下文来避免使用session,使得链接更可收藏,从而在不改变ProductListing页面的情况下改进先前的实例。
 
ProductDetails.java:
 @Inject
 private ProductDAO _dao;
  
  private Product _product;
  
  private long _productId;
  
  public void setProductId(long productId) { _productId = productId; }
  
  void onActivate(long productId)
 {
    _productId = productId;
    
    _product = _dao.getById(_productId);
 }
  
  long onPassivate() { return _productId; }
 
这里的改变保证了呈现请求的URL包含产品id,如http://.../productdetails/99
 
此种方法的优点是页面到页面的连接发生在类型安全的Java代码中——ProductListing页面的onActionFromSelect方法。它也有不好的地方就是点击一个链接服务端需要两次往返过程(由两个页面完成这一请求)。
 
呈现请求一次
 
这是一件最通用的主列表/详细页的版本。
 
ProductListing.html:
<t:loop source="products" value="product">
    <a t:type="pagelink" page="productdetails" context="product.id">${product.name}</a>
</t:loop>
ProductListing.java:
不需要代码来处理链接。
 
ProductDetails.java:
 @Inject
 private ProductDAO _dao;
  
  private Product _product;
  
  private long _productId;
   
  void onActivate(long productId)
 {
    _productId = productId;
    
    _product = _dao.getById(_productId);
 }
  
  long onPassivate() { return _productId; }
 
不再需要setProductId()方法。
 
局限性
 
随着我们应用流程的扩展,我们可能会发现找不到一个合理的方式去避免在不同的请求间(在页面活化上下文之外)持久化某些数据。比如:如果从ProductDetails页面开始,允许用户导航到相关的一些页面然后又返回到ProductDetails页面,这就开始需要在页面到页面再到页面间保持传递的产品id
 
在某些方面,持久化值更有意义。随后,我们将会实现客户端持久化策略(client-side persistence strategy),它将对持久化数据进行编码,如产品id属性将自动的加入到查询参数中(和隐藏的表单域)。
 
分享到:
评论
3 楼 liuwq0223 2007-03-20  
Great!
学习中...
2 楼 pengzhan 2007-03-19  
兄弟,很不错的,继续努力呀!!
1 楼 lococode 2007-03-17  
good,希望共进步!

相关推荐

    Tapestry5开发文档手册.doc

    本文将使用Tapestry 5 创建一个CRUD(创建、读取、更新、删除)应用,展示Tapestry在页面导航、依赖注入、输入验证和状态管理等方面的使用。同时,还会介绍如何利用Tapestry的内置Ajax功能创建自定义组件。 开发...

    tapestry5中文文档

    这包括页面导航、依赖注入和资源注入、用户输入验证以及状态管理。Tapestry 还内置了Ajax支持,使得创建Ajax组件变得更加容易。 在开始使用Tapestry 5 开发之前,确保安装了Java SE Development Kit 5.0或更高版本...

    Tapestry5最新中文入门实例教程

    Tapestry 5通过定义组件之间的链接关系来实现页面导航。这种机制不仅使得页面之间的跳转更加简洁明了,而且还可以轻松地管理和组织应用程序的结构。 ##### 3.2 依赖注入(Dependency Injection)与资源注入(Resource ...

    Tapestry 5开发指南(英文)

    - **页面和组件路径**:Tapestry 5使用声明式的方式映射URL到页面和组件,简化了路由和导航。 - **链接生成**:生成安全、语义化的链接是Tapestry 5的强项,它会自动处理URL参数和安全需求。 6. **国际化和本地化...

    tapestry官方中文文档

    5. **事件处理和页面导航**: Tapestry支持事件驱动的编程模型。当用户与页面交互时,Tapestry会触发相应的事件,并调用处理方法。此外,页面之间的导航可以通过声明式的方式定义,使得应用的流程更加清晰。 6. **...

    Tapestry简单入门.rar_java Tapestry_tapestry

    4. **编写第一个页面**:在Tapestry中,一个页面是由一个或多个组件组成的。你需要定义一个类来表示页面,并在HTML模板中声明组件。 接下来,我们转向"tapestry组件.docx",组件是Tapestry的核心组成部分,它们是可...

    Tapestry5开发文档.pdf

    通过这个示例,读者可以学习到Tapestry中的页面导航、依赖注入、输入验证和状态管理等关键概念。此外,还将探讨如何利用Tapestry的内建Ajax支持创建自定义组件。 为了开始使用Tapestry 5,你需要安装Java SE ...

    Tapestry 5.0.18 环境搭建(eclipse)

    1. `<display-name>`标签设置了应用的显示名称,这里是"Tapestry 5 Tutorial"。 2. `<context-param>`定义了一个参数,`tapestry.app-package`参数指定了应用的主要包名,即`com.tapestry.tutorial`。这个包必须包含...

    Tapestry API

    7. **URL路由与页面导航** `PageRenderRequestHandler`和`PageRedirector`接口处理URL到页面的映射和页面间的跳转,确保了URL的语义化和易于理解。 8. **错误处理与验证** Tapestry的异常处理机制允许开发者通过`...

    Tapestry通用WEB框架

    5. **页面生命周期**:Tapestry定义了页面从初始化到销毁的完整生命周期。每个页面都有一个对应的Java类,该类在页面加载、提交表单等操作时被实例化和调用。 6. **切换皮肤**:在Tapestry中,可以轻松实现皮肤的...

    Tapestry spindle插件下载

    Tapestry通过组件事件处理和页面导航规则来管理应用程序的流程,这使得开发者能够专注于业务逻辑,而不是繁琐的页面跳转和状态管理。 **Tapestry Spindle插件的功能** 1. **代码提示与补全**:Tapestry Spindle...

    tapestry官方中文文档及中文字典

    3. **页面导航**:讨论页面之间的导航控制,如URL映射、重定向和转发。 4. **错误和异常处理**:如何捕获和处理运行时错误,以及定义自定义的错误页面。 5. **性能优化**:提供性能调优的建议,如缓存策略、页面编译...

    Tapestry开发指南

    页面导航通常是无状态的,通过URL参数或隐式对象实现。 4. **类型安全的链接和表单** 与传统Web框架不同,Tapestry的链接和表单是类型安全的。这意味着在生成链接或处理表单提交时,Tapestry会自动绑定请求参数到...

    Tapestry4开发指南

    在Tapestry4的开发过程中,路由和页面导航也是一个关键部分。框架自动处理URL到页面组件的映射,使得开发者可以轻松地创建链接和表单提交,而无需编写复杂的URL解析代码。同时,Tapestry4支持页面级和应用程序级的...

    tapestry5.3.3+spring+hibernate整合源码

    Tapestry的类型安全URL映射使得开发者能够清晰地定义页面之间的导航,避免了常见的URL编码错误。 Spring框架的核心是依赖注入(DI),它允许通过配置文件或注解来管理对象的生命周期和依赖关系。这样,对象之间的...

    Tapestry

    `IEngine`是Tapestry的核心组件,负责整个应用的生命周期管理和页面导航。 总的来说,Tapestry通过组件化、模型-视图-控制器的设计以及强大的OGNL表达式,为Java开发者提供了一种高效、灵活的Web应用开发工具。通过...

    Tapestry 学习文档

    对于状态管理,Tapestry提供了一种机制,可以在服务器端持久化组件状态,即使在页面刷新或导航后也能恢复。 6. **性能优化**: 由于Tapestry生成的页面是服务器端渲染的,因此它可以进行一些性能优化,如延迟加载...

Global site tag (gtag.js) - Google Analytics