Tapestry 组件基础教程文档

收录于 2023-04-20 00:10:05 · بالعربية · English · Español · हिंदीName · 日本語 · Русский язык · 中文繁體

如前所述,组件和页面是相同的,除了页面是根组件并且包含一个或多个子组件。组件始终驻留在页面内,并执行页面的几乎所有动态功能。
Tapestry 组件使用 交互式 AJAX 呈现一个简单的 HTML 链接到复杂的网格功能。一个组件也可以包含另一个组件。 Tapestry 组件由以下项目组成-
Component Class-组件的主要 Java 类。 XML 模板-XML 模板类似于页面模板。组件类将模板呈现为最终输出。某些组件可能没有模板。在这种情况下,输出将由组件类本身使用 MarkupWriter 类生成。 Body-在页面模板中指定的组件可能具有自定义标记,称为"组件主体"。如果组件模板具有 <body/> 元素,然后<body/> 元素将被组件的主体替换。这类似于前面 XML 模板部分中讨论的布局。 渲染-渲染是将组件的 XML 模板和主体转换为行为的过程组件的 ual 输出。 参数-用于在组件和页面之间创建通信,从而在它们之间传递数据。 事件-将组件的功能委托给其容器/父级(页面或其他组件)。它广泛用于页面导航目的。

渲染

组件的渲染是在一系列预定义阶段中完成的。组件系统中的每个阶段都应该在组件类中通过约定或注解定义相应的方法。
// Using annotaion 
@SetupRender 
void initializeValues() { 
   // initialize values 
}
// using convention 
boolean afterRender() { 
   // do logic 
   return true; 
}
下面列出了各个阶段、其方法名称和注释。
注解 默认方法名称
@SetupRender setupRender()
@BeginRender beginRender()
@BeforeRenderTemplate beforeRenderTemplate()
@BeforeRenderBody beforeRenderBody()
@AfterRenderBody afterRenderBody()
@AfterRenderTemplate afterRenderTemplate()
@AfterRender afterRender()
@CleanupRender cleanupRender()
每个阶段都有特定的目的,它们如下-

设置渲染

SetupRender 启动渲染过程。它通常设置组件的参数。

开始渲染

BeginRender 开始渲染组件。它通常呈现组件的开始/开始标签。

BeforeRenderTemplate

BeforeRenderTemplate 用于装饰 XML 模板,在模板周围添加特殊标记。它还提供了跳过模板渲染的选项。

BeforeRenderBody

BeforeRenderTemplate 提供了一个选项来跳过组件主体元素的渲染。

AfterRenderBody

AfterRenderBody 会在组件主体渲染完成后被调用。

AfterRenderTemplate

AfterRenderTemplate 将在组件的模板渲染后调用。

渲染后

AfterRender 是 BeginRender 的对应物,通常呈现结束标记。

清理渲染

CleanupRender 是 SetupRender 的对应物。它释放/处置在渲染过程中创建的所有对象。
渲染阶段的流程不仅仅是向前的。它根据阶段的返回值在阶段之间来回移动。
例如,如果 SetupRender 方法返回 false,则渲染会跳转到 CleanupRender 阶段,反之亦然。要清楚了解不同阶段之间的流程,请查看下图中的流程。
注释列表

简单组件

让我们创建一个简单的组件 Hello,它将输出消息为"Hello, Tapestry"。以下是 Hello 组件及其模板的代码。
package com.example.MyFirstApplication.components;  
public class Hello {  
}
<html  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
  
   <div> 
      <p>Hello, Tapestry (from component).</p> 
   </div> 
  
</html>
Hello 组件可以在页面模板中调用为-
<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
<t:hello />  
</html>
同样,组件可以使用 MarkupWriter 而不是模板呈现相同的输出,如下所示。
package com.example.MyFirstApplication.components; 
  
import org.apache.tapestry5.MarkupWriter; 
import org.apache.tapestry5.annotations.BeginRender;   
public class Hello { 
   @BeginRender 
   void renderMessage(MarkupWriter writer) { 
      writer.write("<p>Hello, Tapestry (from component)</p>"); 
   } 
}
让我们更改组件模板并包含 元素,如下面的代码块所示。
<html>  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> 
      <t:body /> 
   </div> 
</html>
现在,页面模板可能在组件标记中包含正文,如下所示。
<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <t:hello> 
      <p>Hello, Tapestry (from page).</p> 
   </t:hello> 
</html>
输出如下-
<html> 
   <div> 
      <p>Hello, Tapestry (from page).</p> 
   </div> 
</html>

参数

这些参数的主要目的是在组件的字段和页面的属性/资源之间创建连接。使用参数,组件与其对应的页面相互通信和传输数据。这称为 双向数据绑定
比如在用户管理页面中用于表示年龄的文本框组件通过参数获取其初始值(在数据库中可用)。同样,当用户的年龄更新并提交回来后,组件会通过相同的参数将更新后的年龄发回。
要在组件类中创建新参数,请声明一个字段并指定一个 @Parameter 注释。这个@Parameter 有两个可选参数,它们是-
required-使参数成为必需的。如果未提供,Tapestry 会引发异常。 value-指定参数的默认值。
该参数应在页面模板中指定为组件标签的属性。属性的值应该使用绑定表达式/扩展来指定,我们在前面的章节中讨论过。我们之前学到的一些扩展是-
Property expansion (prop:«val»)-从页面类的属性中获取数据。 Message expansion (message:«val»)-从 index.properties 文件中定义的键中获取数据。 Context expansion (context:«val»)-从 Web 上下文文件夹/src/main/webapp 获取数据。 Asset expansion (asset:«val»)-从嵌入在 jar 文件/META-INF/assets 中的资源中获取数据。 Symbol expansion (symbol:«val») -从 AppModule.javafile 中定义的符号中获取数据。
Tapestry 有更多有用的扩展,下面给出了其中一些-
Literal expansion (literal:«val»)-文字字符串。 Var expansion (var:«val»)-允许读取或更新组件的渲染变量。 Validate expansion (validate:«val»)-用于指定对象验证规则的专用字符串。例如,validate:required, minLength = 5、 Translate (translate:«val»)-用于在输入验证中指定 Translator 类(将客户端转换为服务器端表示)。 Block (block:«val»)-模板中块元素的 id。 Component (component:«val»)-模板中另一个组件的 id。
以上所有扩展都是只读的,除了 Property 扩展和 Var 扩展。组件使用它们与页面交换数据。使用扩展作为属性值时,不应使用 ${...}。而是使用没有美元和大括号符号的扩展。

组件使用参数

让我们通过在组件类中添加 name参数并相应地更改组件模板和页面模板来修改Hello组件以动态呈现消息来创建一个新组件HelloWithParameter。
创建一个新的组件类 HelloWithParameter.java 添加一个私有字段并使用 @Parameter 注释命名。使用 required 参数使其成为必需参数。
@Parameter(required = true) 
private String name;
添加一个私有字段,结果带有 @Propery 注释。结果属性将在组件模板中使用。组件模板无法访问用 @Parameter 注释的字段,只能访问用 @Property 注释的字段。组件模板中可用的变量称为渲染变量。
@Property 
 private String result;
添加 RenderBody 方法并将值从 name 参数复制到 result 属性。
@BeginRender 
void initializeValues() { 
   result = name; 
}
添加一个新的组件模板 HelloWithParamter.tml 并使用 result 属性来呈现消息。
<div> Hello, ${result} </div>
在测试页面 (testhello.java) 中添加一个新属性 Username。
public String getUsername() { 
   return "User1"; 
}
在页面模板中使用新创建的组件,并在 HelloWithParameter 组件的 name 参数中设置 Username 属性。
<t:helloWithParameter name = "username" /> 
完整列表如下-
package com.example.MyFirstApplication.components;  
import org.apache.tapestry5.annotations.*;  
public class HelloWithParameter { 
   @Parameter(required = true) 
   private String name; 
     
   @Property 
   private String result; 
   
   @BeginRender 
   void initializeValues() { 
      result = name; 
   } 
}
<html  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> Hello, ${result} </div> 
  
</html>
package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.*;  
public class TestHello { 
   public String getUsername() { 
      return "User1"; 
   } 
}
<html title = "Hello component test page" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <t:helloWithParameter name = "username" />
   
</html> 
结果如下-
<div> Hello, User1 </div>

高级参数

在前面的章节中,我们分析了如何在自定义组件中创建和使用一个简单的参数。高级参数也可能包含完整的标记。在这种情况下,标记应在组件标记内指定,例如页面模板中的子部分。内置的 if 组件具有成功和失败条件的标记。成功标记指定为组件标记的主体,失败标记使用 elseparameter 指定。
让我们看看如何使用 if 组件。 if 组件有两个参数-
test-简单的基于属性的参数。 Else-用于指定替代标记的高级参数,如果条件失败
Tapestry 将使用以下逻辑检查 test 属性的值并返回 true 或 false。这称为 类型强制,一种将一种类型的对象转换为具有相同内容的另一种类型的方法。
如果数据类型是String,则"True"如果非空且不是文字字符串"False"(不区分大小写)。 如果数据类型是数字,如果非零则为真。 如果数据类型是 Collection,则为 True 如果非空。 如果数据类型为 Object,则为 True(只要不为 null)。
如果条件通过,组件渲染它的主体;否则,它呈现 else 参数的主体。
完整列表如下-
package com.example.MyFirstApplication.pages; 
public class Testif { 
   public String getUser() { 
      return "User1"; 
   } 
}
<html title = "if Test Page" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   
   <body> 
      <h1>Welcome!</h1>  
      <t:if test = "user"> 
         Welcome back, ${user} 
         <p:else>
            Please <t:pagelink page = "login">Login</t:pagelink>  
         </p:else> 
      </t:if>
   </body>
   
</html>

组件事件/页面导航

Tapestry 应用程序是相互交互的 页面集合。到目前为止,我们已经学会了如何在没有任何通信的情况下创建单独的页面。组件事件的主要目的是使用服务器端事件在页面之间(以及页面内)提供交互。大多数组件事件源自客户端事件。
例如,当用户单击页面中的链接时,Tapestry 将使用目标信息调用同一个页面本身,而不是调用目标页面并引发服务器端事件。 Tapestry 页面将捕获事件,处理目标信息并在服务器端重定向到目标页面。
Tapestry 遵循用于页面导航的 发布/重定向/获取 (RPG) 设计模式。在 RPG 中,当用户通过提交表单进行 post 请求时,服务器会处理已发布的数据,但不会直接返回响应。相反,它将执行客户端重定向到另一个页面,这将输出结果。 RPG 模式用于防止通过浏览器后退按钮、浏览器刷新按钮等重复提交表单,Tapestry 通过提供以下两种类型的请求来提供 RPG 模式。
组件事件请求-这种类型的请求针对页面中的特定组件并在组件内引发事件。此请求仅进行重定向,不输出响应。 呈现请求-这些类型的请求以页面为目标并将响应流式传输回客户端。
要了解组件事件和页面导航,我们需要知道挂毯请求的 URL 模式。两种类型的请求的 URL 模式如下-
组件事件请求-
/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
呈现请求-
/<<page_name_with_path>>/<<context_information>>
URL 模式的一些示例是-
可以通过https://«domain»/«app»/index请求索引页面。 如果索引页面在子文件夹管理员下可用,则可以通过 https://«domain»/«app»/admin/index 请求。 如果用户点击索引页中带有 id testActionLink 组件,则 URL 将是 https://«domain»/«应用»/index.test.

活动

默认情况下,Tapestry 为所有请求引发 OnPassivateOnActivate 事件。对于组件事件请求类型,tapestry 根据组件引发额外的一个或多个事件。 ActionLink 组件引发 Action 事件,而 Form 组件引发多个事件,例如 Validate、Success 等,
可以使用相应的方法处理程序在页面类中处理事件。方法处理程序是通过方法命名约定或通过 @OnEvent 注释创建的。方法命名约定的格式为 On«EventName»From«ComponentId»
具有 id test 的 ActionLink 组件的动作事件可以通过以下任一方法处理-
void OnActionFromTest() { 
}  
@OnEvent(component = "test", name = "action") 
void CustomFunctionName() { 
} 
如果方法名没有任何特定的组件,那么所有具有匹配事件的组件都会调用该方法。
void OnAction() { 
} 

OnPassivate 和 OnActivate 事件

OnPassivate 用于为 OnActivate 事件处理程序提供上下文信息。通常,Tapestry 提供上下文信息,它可以用作 OnActivateevent 处理程序中的参数。
例如,如果上下文信息是 int 类型的 3,则 OnActivate 事件可以调用为-
void OnActivate(int id) { 
} 
在某些情况下,上下文信息可能不可用。在这种情况下,我们可以通过 OnPassivate 事件处理程序将上下文信息提供给 OnActivate 事件处理程序。 OnPassivate 事件处理程序的返回类型应用作 OnActivate 事件处理程序的参数。
int OnPassivate() { 
   int id = 3; 
   return id; 
} 
void OnActivate(int id) { 
} 

事件处理程序返回值

Tapestry 根据事件处理程序的返回值发出页面重定向。事件处理程序应返回以下任一值。
Null Response-返回空值。 Tapestry 将构建当前页面 URL 并作为重定向发送到客户端。
public Object onAction() { 
   return null; 
}
String Response-返回字符串值。 Tapestry 将构建与该值匹配的页面的 URL,并将其作为重定向发送到客户端。
public String onAction() { 
   return "Index"; 
}
Class Response-返回页面类。 Tapestry 将构造返回页面类的 URL 并作为重定向发送到客户端。
public Object onAction() { 
   return Index.class 
}
Page Response-返回一个用@InjectPage 注释的字段。 Tapestry 将构建注入页面的 URL 并作为重定向发送到客户端。
@InjectPage 
private Index index;  
public Object onAction(){ 
   return index; 
}
HttpError-返回 HTTPError 对象。 Tapestry 将发出客户端 HTTP 错误。
public Object onAction(){ 
   return new HttpError(302, "The Error message); 
}
Link Response-直接返回链接实例。 Tapestry 将从 Link 对象构造 URL 并作为重定向发送到客户端。 Stream Response-返回 StreamResponse 对象。 Tapestry 会将流作为响应直接发送到客户端浏览器。用于直接生成报表和图片并发送给客户端。 Url Response-返回 java.net.URL 对象。 Tapestry 将从对象中获取相应的 URL 并作为重定向发送到客户端。 Object Response-返回上述指定值以外的任何值。 Tapestry 将引发错误。

事件上下文

通常,事件处理程序可以使用参数获取上下文信息。例如,如果上下文信息是 int 类型的 3,那么事件处理程序将是-
Object onActionFromTest(int id) {  
} 
Tapestry 正确处理上下文信息并通过参数将其提供给方法。有时,由于编程的复杂性,Tapestry 可能无法正确处理它。届时,我们可能会得到完整的上下文信息并自行处理。
Object onActionFromEdit(EventContext context) { 
   if (context.getCount() > 0) { 
      this.selectedId = context.get(0); 
   } else { 
      alertManager.warn("Please select a document."); 
      return null; 
   } 
}