Apache Tapestry - 组件

如前所述,除了Page是根组件并包含一个或多个子组件之外,组件和页面是相同的.组件总是驻留在页面内,几乎完成页面的所有动态功能.

Tapestry组件使用交互式AJAX 呈现复杂网格功能的简单HTML链接.组件也可以包括另一个组件. Tapestry组件包含以下项目 :

  • 组件类 : 组件的主要Java类.

  • XML模板 :  XML模板类似于页面模板.组件类将模板呈现为最终输出.某些组件可能没有模板.在这种情况下,输出将由组件类本身使用 MarkupWriter 类生成.

  • Body : 页面模板中指定的组件可能具有自定义标记,它被称为"组件主体".如果组件模板具有< body/> 元素,那么< body/>元素将被组件的主体替换.这类似于前面XML模板部分讨论的布局.

  • 渲染 : 渲染是一个将XML模板和组件主体转换为组件实际输出的过程.

  • 参数 : 用于在组件和组件之间创建通信.页面,从而在它们之间传递数据.

  • 事件 : 委托从组件到其容器/父级(页面或其他组件)的功能.它广泛用于页面导航目的.

渲染

组件的渲染是在一系列预定阶段完成.组件系统中的每个阶段都应该具有由组件类中的约定或注释定义的相应方法.

// Using annotaion 
@SetupRender 
void initializeValues() { 
   // initialize values 
}

// using convention 
boolean afterRender() { 
   // do logic 
   return true; 
}

下面列出了阶段,方法名称和注释.

注释默认方法名称
@SetupRendersetupRender()
@BeginRenderbeginRender()
@BeforeRenderTemplatebeforeRenderTemplate()
@BeforeRenderBodybeforeRenderBody()
@AfterRenderBodyafterRenderBody()
@AfterRenderTemplateafterRenderTemplate()
@AfterRenderafterRender ()
@CleanupRendercleanupRender()

每个阶段都有特定目的,它们如下:<

SetupRender

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

BeginRender

BeginRender开始渲染组件.它通常呈现组件的begin/start标记.

BeforeRenderTemplate

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

BeforeRenderBody

BeforeRenderTemplate提供跳过组件主体元素渲染的选项.

AfterRenderBody

在渲染组件的主体后将调用AfterRenderBody.

AfterRenderTemplate

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

AfterRender

AfterRender是BeginRender的对应物,通常会渲染关闭标记.

CleanupRender

CleanupRender是SetupRender的对应物.它释放/处理在渲染过程中创建的所有对象.

渲染阶段的流程不仅仅是向前的.它在阶段之间来回移动,具体取决于阶段的返回值.

例如,如果SetupRender方法返回false,则渲染跳转到CleanupRender阶段,反之亦然.为了清楚地了解不同阶段之间的流程,请查看下面给出的图表中的流程.

Annotation列表

简单组件

让我们创建一个简单的组件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>"); 
   } 
}

让我们更改组件模板并包含< body/>元素如下面的代码块所示.

<html>  
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   
   <div> 
      <t:body /> 
   </div> 
</html>

现在,页面模板可能在组件标记中包含body,如下所示.

<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有两个可选参数,分别为 :

  • 必需 : 使参数成为必需参数.如果没有提供,Tapestry会引发异常.

  • value : 指定参数的默认值.

应在页面模板中将参数指定为组件标记的属性.应使用Binding Expression/Expansion指定属性的值,我们在前面的章节中对此进行了讨论.我们之前学到的一些扩展是&减去;

  • 物业扩张(道具:&laquo; val&raquo;) : 从页面类的属性中获取数据.

  • 消息扩展(消息:&laquo; val&raquo;) : 从index.properties文件中定义的密钥中获取数据.

  • 上下文扩展(上下文:&laquo; val&raquo;) : 从web上下文文件夹/src/main/webapp获取数据.

  • 资产扩展(资产:&laquo; val&raquo;)&minus ;从jar文件中嵌入的资源中获取数据,/META-INF/assets.

  • 符号扩展(符号:&laquo; val&raquo;) : 从AppModule.javafile中定义的符号中获取数据.

Tapestry还有许多有用的扩展,其中一些在下面和下面给出;

  • 文字扩展(字面意思:&laquo; val&raquo;) : 文字字符串.

  • Var展开(var:&laquo; val&raquo;) : 允许读取或更新组件的渲染变量.

  • 验证扩展(验证:&laquo; val&raquo;) : 用于指定对象验证规则的专用字符串.例如,验证:必需,minLength = 5.

  • 翻译(翻译:&laquo; val&raquo;) : 用于在输入验证中指定转换器类(将客户端转换为服务器端表示).

  • 阻止(阻止:&laquo; val&raquo; ) : 模板中块元素的ID.

  • 组件(组件:&laquo; val&raquo;) : 模板中另一个组件的id.

以上所有扩展都是只读的,但属性扩展和Var扩展除外.组件使用它们与页面交换数据.将扩展用作属性值时,不应使用 $ {...} .相反,只需使用没有美元和大括号符号的扩展.

组件使用参数

让我们通过修改Hello组件来创建一个新组件HelloWithParameter通过在组件类中添加 name 参数并相应地更改组件模板和页面模板来动态呈现消息.

  • 创建一个新的组件类 HelloWithParameter.java .

  • 添加一个私有字段并将其命名为 @Parameter 注释.使用必需的参数使其成为必需参数.

@Parameter(required = true) 
private String name;

  • 使用 @Propery 注释添加私有字段,结果. result属性将在组件模板中使用.组件模板无权访问使用 @Parameter 注释的字段,并且只能访问使用 @Property 注释的字段.组件模板中可用的变量称为渲染变量.

@Parameter(required = true) 
private String name;

  • 添加RenderBody方法并将name参数中的值复制到result属性./p>

@Property 
 private String result;

  • 添加新组件模板 HelloWithParamter.tml 并使用result属性呈现消息.

<div> Hello, ${result} </div>

  • 在测试页面(testhello.java)中添加一个新属性Username.

public String getUsername() { 
   return "User1"; 
}

  • 在页面模板中使用新创建的组件并设置名称参数 HelloWithParameter 组件中的用户名属性.

<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组件具有成功和失败条件的标记.成功标记被指定为组件标记的主体,失败标记使用 else参数指定.

让我们看看如何使用如果组件. if组件有两个参数 :

  • test : 基于简单属性的参数.

  • 其他 : 用于指定备用标记的高级参数,如果条件失败

Tapestry将使用以下逻辑检查test属性的值并返回对或错.这称为类型强制,一种将一种类型的对象转换为具有相同内容的另一种类型的方法.

  • 如果数据类型为 String ,则为"非",如果为非空,而不是文字字符串"False"(不区分大小写).

  • 如果数据类型为 Number ,则为True,如果非零.

  • 如果数据类型是集合,如果非空则为真.

  • 如果数据类型为对象,则为True(只要它不为空).

如果条件通过,则组件呈现其正文;否则,它呈现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应用程序是一个页面集合与之交互彼此.到目前为止,我们已经学会了如何在没有任何通信的情况下创建单个页面. Component事件的主要目的是使用服务器端事件在页面之间(在页面内)提供交互.大多数组件事件都源自客户端事件.

例如,当用户单击页面中的链接时,Tapestry将使用目标信息调用同一页面本身,而不是调用目标页面并引发服务器端事件. Tapestry页面将捕获事件,处理目标信息并执行服务器端重定向到目标页面.

Tapestry遵循发布/重定向/获取(RPG)设计模式用于页面导航.在RPG中,当用户通过提交表单执行发布请求时,服务器将处理发布的数据,但不会直接返回响应.相反,它会将客户端重定向到另一个页面,该页面将输出结果. RPG模式用于通过浏览器后退按钮,浏览器刷新按钮等防止重复表单提交,Tapestry通过提供以下两种类型的请求来提供RPG模式.

  • 组件事件请求 : 此类请求针对页面中的特定组件,并在组件内引发事件.此请求仅进行重定向,但不输出响应.

  • 渲染请求 : 这些类型的请求以页面为目标并将响应流回客户端.

要了解组件事件和页面导航,我们需要了解tapestry请求的URL模式.两种类型的请求的URL模式如下 :

  • 组件事件请求:

/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>

  • 呈现请求 :

/<<page_name_with_path>>/<<context_information>>

网址格式的一些示例是 :

  • 可以通过 https://&laquo; domain&raquo;/&laquo; app&raquo;/index 请求索引页.

  • 如果索引页面在子文件夹管理员下可用,则可以通过 https://&laquo; domain&raquo;/&laquo; app&raquo;/admin/index 来请求它.

  • 如果用户在索引页面中点击了带 id test ActionLink组件,则该URL将为 https://&laquo; domain&raquo;/&laquo; app&raquo;/index.test .

活动

默认情况下,Tapestry为所有请求引发 OnPassivate OnActivate 事件.对于组件事件请求类型,tapestry根据组件引发其他一个或多个事件. ActionLink组件引发一个Action事件,而Form组件引发多个事件,如验证,成功等,

事件可以在页面中处理class使用相应的方法处理程序.方法处理程序可以通过方法命名约定或通过 @OnEvent 注释创建.方法命名约定的格式为开&laquo; EventName&raquo; From&laquo; ComponentId&raquo; .

ActionLink组件的动作事件 id test 可以通过以下任一方法处理 :

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值. Tapestry将构造当前页面URL并作为重定向发送给客户端.

public Object onAction() { 
   return null; 
}

  • 字符串响应 : 返回字符串值. Tapestry将构造与该值匹配的页面的URL并作为重定向发送给客户端.

public String onAction(){
 return"Index"; 
}

  • 类响应 : 返回页面类. Tapestry将构造返回的页面类的URL并作为重定向发送给客户端.

public Object onAction(){
 return Index.class 
}

  • 页面回复 : 返回使用@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); 
}

  • 链接响应 : 直接返回链接实例.Tapestry将从Link对象构造URL并作为重定向发送给客户端.

  • 流响应 : 返回 StreamResponse 对象.Tapestry将流作为响应直接发送到客户端浏览器.它用于直接生成报告和图像并发送它是给客户的.

  • 网址响应 : 返回 java.net.URL 对象. Tapestry将从对象获取相应的URL并作为重定向发送给客户端.

  • 对象响应 : 返回任何其他值Tapestry会引发错误.

Event Co ntext

通常,事件处理程序可以使用参数获取上下文信息.例如,如果上下文信息是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; 
   } 
}