目录

Apache Tapestry - 快速指南

Apache Tapestry - Overview

Apache Tapestry是一个用Java编写的开源Web框架。 它是一个component based web framework 。 Tapestry组件是Java类。 它们既不是从框架特定的基类继承,也不是接口的实现,它们只是简单的POJO(普通的旧Java对象)。

Tapestry使用的Java的重要特征是Annotation 。 Tapestry网页是使用一个或多个组件构建的,每个组件都有一个基于XML的模板和用大量Tapestry的Annotations修饰的组件类。 Tapestry可以创建从小型单页Web应用程序到由数百页组成的大型Web应用程序。

Tapestry的好处

挂毯提供的一些好处是 -

  • 高度可扩展的Web应用程序。
  • Adaptive API.
  • 快速而成熟的框架。
  • 持久状态存储管理。
  • Build-in Inversion of Control.

Tapestry的特点

Tapestry具有以下功能 -

  • Live class reloading
  • 清晰详细的异常报告
  • Static structure, dynamic behaviors.
  • 广泛使用普通旧Java对象(PO​​JO)
  • 减少代码,提供更多。

为何选择Tapestry?

Java已经有很多Web框架,比如JSP,Struts等,那么,为什么我们需要另一个框架呢? 今天的大多数Java Web框架都很复杂,学习曲线也很陡峭。 它们是老式的,每次更新都需要编译,测试和部署周期。

另一方面,Tapestry通过提供live class reloading为Web应用程序编程提供了一种现代方法。 虽然其他框架引入了大量的接口,抽象和基类,但Tapestry只引入了一小部分注释,并且仍然提供了编写具有丰富AJAX支持的大型应用程序的能力。

Apache Tapestry - Architecture

Tapestry尽可能地尝试使用Java的可用功能。 例如,所有Tapestry页面都只是POJO。 它不强制执行任何自定义接口或基类来编写应用程序。 相反,它使用Annotation(轻量级选项来扩展Java类的功能)来提供功能。 它基于经过Java Servlet API考验的Java Servlet API并作为Servlet过滤器实现。 它为Web应用程序提供了一个新的维度,编程非常简单,灵活,易于理解和强大。

工作流 (Workflow)

让我们讨论请求挂毯页面时发生的操作顺序。

工作流程

Step 1 - Java Servlet接收页面请求。 此Java Servlet的配置方式是将传入请求转发到tapestry。 配置在web.xml完成,如以下程序中所指定。 Filter和Filter Mapping标记将所有请求重定向到Tapestry Filter

<!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>My Tapestry Application</display-name> 
   <context-param> 
      <param-name>tapestry.app-package</param-name> 
      <param-value>org.example.myapp</param-value> 
   </context-param> 
   <filter> 
      <filter-name>app</filter-name> 
      <filter-class>org.apache.tapestry5.TapestryFilter</filter-class> 
   </filter> 
   <filter-mapping> 
      <filter-name>app</filter-name> 
      <url-pattern>/*</url-pattern> 
   </filter-mapping> 
</web-app> 

Step 2 - Tapestry Filter通过其Service()方法调用HttpServletRequestHandler服务。

Step 3 - HttpServletRequestHandler将请求和响应存储在RequestGlobals 。 它还将请求和响应包装为Request和Response对象,并将其发送到RequestHandler。

Step 4 - RequestHandler是Servlet API的HttpServletRequest之上的抽象。 RequestHandler一些显着特征是在RequestHandler部分完成的。 可以通过在RequestHandler中编写过滤器来扩展tapestry的功能。 RequestHandler提供了几个内置过滤器,其中包括 -

  • CheckForUpdates Filter - 负责实时类重新加载。 此过滤器检查java类的更改并根据需要更新应用程序。

  • Localization Filter - 确定用户的位置并为应用程序提供本地化支持。

  • StaticFiles Filter - 识别静态请求并中止进程。 进程中止后,Java Servlet将控制并处理请求。

  • Error Filter - 捕获未捕获的异常并显示异常报告页面。

RequestHandler还在RequestQlobals中修改并存储请求和响应,并调用MasterDispatcher服务。

Step 5 - MasterDispatcher负责通过调用多个调度程序来呈现页面是一个特定的顺序。 MasterDispatcher调用的四个主要调度员如下 -

  • RootPath Dispatcher - 它识别请求的根路径“/”,并将其呈现与Start页面相同。

  • Asset Dispatcher - 它通过检查URL模式/ assets /来识别资产(Java资产)请求,并将请求的资产作为字节流发送。

  • PageRender Dispatcher - 大量的挂毯操作在PageRender Dispatcher和下一个调度程序Component Dispatcher中完成。 此调度程序识别该请求的特定页面及其激活上下文(附加信息)。 然后它呈现该特定页面并将其发送到客户端。 例如,如果请求网址为/ product/12123434,则调度程序将检查是否有任何名为product/12123434的类可用。 如果找到,则调用product/12123434类,生成响应并将其发送给客户端。 如果没有,它会检查产品类别。 如果找到,它会调用带有额外信息的产品类121234434,生成响应并将其发送到客户端。 此额外信息称为激活上下文。 如果没有找到类,它只是将请求转发给Component Dispatcher。

  • Component Dispatcher - Component Dispatcher将页面的URL与模式 - /“class_name”/“component_id”:“event_type”/“activation_context”进行匹配。 例如,/ product/grid:sort/asc表示产品类,网格组件,sortevent类型和asc激活上下文。 这里,event_type是可选的,如果没有提供,则将触发默认事件类型操作。 通常,组件调度程序的响应是将重定向发送到客户端。 大多数情况下,重定向将在下一个请求中与PageRender Dispatcher匹配,并将正确的响应发送给客户端。

Apache Tapestry - Installation

在本章中,我们将讨论如何在我们的机器上安装Tapestry。

先决条件(Prerequisite)

Tapestry唯一的依赖是Core Java 。 Tapestry是独立开发的,不使用任何第三方库/框架。 即使是tapestry使用的IoC库也是从头开始开发的。 用Tapestry编写的Web应用程序可以从控制台本身构建和部署。

我们可以使用Maven, EclipseJetty来改善开发体验。 Maven提供快速启动应用程序模板和选项,以便在Java的事实上的开发服务器Jetty中托管应用程序。 Eclipse提供了广泛的项目管理功能,并与maven集成良好。

理想的挂毯应用程序开发需要以下内容 -

  • Java 1.6或更高版本
  • Apache Maven
  • Eclipse IDE
  • Jetty服务器

验证Maven安装

希望你已经在你的机器上安装了Maven。 要验证Maven安装,请键入以下命令 -

mvn --version

您可以看到如下所示的响应 -

Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-1110T22:11:47+05:30) 
Maven home: /Users/workspace/maven/apache-maven-3.3.9 
Java version: 1.8.0_92, vendor: Oracle Corporation 
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre 
Default locale: en_US, platform encoding: UTF-8 
OS name: "mac os x", version: "10.11.4", arch: "x86_64", family: "mac"

如果未安装Maven,请访问Maven网站下载并安装最新版本的maven。

下载Tapestry

Tapestry的最新版本是5.4,可以从Tapestry网站下载。 下载binary包就足够了。 如果我们使用Maven快速启动模板,则无需单独下载Tapestry。 Maven自动下载必要的Tapestry Jars并配置应用程序。 我们将在下一章讨论如何使用Maven创建基本的Tapestry应用程序。

Apache Tapestry - Quick Start

在Tapestry安装之后,让我们使用Maven创建一个新的初始项目,如下所示 -

$ mvn archetype:generate -DarchetypeCatalog=http://tapestry.apache.org

您可以看到如下所示的响应 -

[INFO] Scanning for projects... 
[INFO] 
[INFO] --------------------------------------------------------------------------------- 
[INFO] Building Maven Stub Project (No POM) 1 
[INFO] ---------------------------------------------------------------------------------
[INFO] 
[INFO] >>> maven-archetype-plugin:2.4:generate (default-cli) > 
generatesources @ standalone-pom >>> 
[INFO]  
[INFO] <<< maven-archetype-plugin:2.4:generate (default-cli) 
< generatesources @ standalone-pom <<< 
[INFO] 
[INFO] --- maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom --- 
[INFO] Generating project in Interactive mode 
[INFO] No archetype defined. Using maven-archetype-quickstart 
(org.apache.maven.archetypes:maven-archetype-quickstart:1.0)

在Maven构建所有操作之后,选择原型来创建Tapestry 5 QuickStart项目,如下所示 -

Choose archetype -

选择一个数字或应用过滤器(格式:[groupId:] artifactId,区分大小写):: 1

现在您将获得如下所示的响应 -

Choose org.apache.tapestry:quickstart version: 
1: 5.0.19
2: 5.1.0.5 
3: 5.2.6 
4: 5.3.7 
5: 5.4.1 

提取QuickStart版本号如下 -

Choose a number: 5: 5

这里,QuickStart项目采用选项5的版本“5.4.1”。 现在,Tapestry原型逐一询问以下信息如下 -

  • 5.1 groupId - 定义属性'groupId'的值:: com.example

  • 5.2 artifactId - 定义属性'artifactId'的值:: Myapp

  • 5.3 version - 定义属性'version'的值:1.0-SNAPSHOT ::

  • 5.4 package name - 定义属性'包'的值:com.example :: com.example.Myapp

现在您的屏幕要求您确认 -

确认属性配置 -

  • groupId - com.example

  • artifactId - Myapp

  • version - 1.0-SNAPSHOT

  • package - com.example.Myapp

验证所有属性并使用下面显示的选项确认更改 -

 Y: : Y 

你会看到如下所示的屏幕。

[INFO] ---------------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: quickstart:5.4.1 
[INFO] ---------------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.example 
[INFO] Parameter: artifactId, Value: Myapp 
[INFO] Parameter: version, Value: 1.0-SNAPSHOT 
[INFO] Parameter: package, Value: com.example.Myapp 
[INFO] Parameter: packageInPathFormat, Value: com/example/Myapp 
[INFO] Parameter: package, Value: com.example.Myapp 
[INFO] Parameter: version, Value: 1.0-SNAPSHOT 
[INFO] Parameter: groupId, Value: com.example 
[INFO] Parameter: artifactId, Value: Myapp 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/test/java 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/main/webapp 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/main/resources/com/
example/Myapp 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/test/resource 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/test/conf 
[WARNING] Don't override file /Users/workspace/tapestry/Myapp/src/site 
[INFO] project created from Archetype in dir: /Users/workspace/tapestry/Myapp 
[INFO] --------------------------------------------------------------------------------- 
[INFO] BUILD SUCCESS 
[INFO] --------------------------------------------------------------------------------- 
[INFO] Total time: 11:28 min 
[INFO] Finished at: 2016-09-14T00:47:23+05:30 
[INFO] Final Memory: 14M/142M 
[INFO] ---------------------------------------------------------------------------------

在这里,您已成功构建Tapestry快速入门项目。 使用以下命令移动到新创建的Myapp目录的位置并开始编码。

cd Myapp 

运行应用程序

要运行骨架项目,请使用以下命令。

mvn jetty:run -Dtapestry.execution-mode=development

你得到这样的屏幕,

[INFO] Scanning for projects... 
[INFO] 
[INFO] ---------------------------------------------------------------------------------
[INFO] Building Myapp Tapestry 5 Application 1.0-SNAPSHOT 
[INFO] ---------------------------------------------------------------------------------
........ 
........ 
........ 
Application 'app' (version 1.0-SNAPSHOT-DEV) startup time: 346 ms to build IoC 
Registry, 1,246 ms overall.  
 ______                  __             ____ 
/_  __/__ ____  ___ ___//_______ __ /__/ 
///_ `/ _ \/ -_|_-</ __/ __/ ////__\ 
/_/  \_,_/ .__/\__/___/\__/_/  \_,//____/ 
        /_/                   /___/  5.4.1 (development mode)   
[INFO] Started SelectChannelConnector@0.0.0.0:8080 
[INFO] Started Jetty Server

截至目前,我们已在Tapestry中创建了一个基本的快速入门项目。 要在Web浏览器中查看正在运行的应用程序,只需在地址栏中键入以下URL并按Enter键 -

https://localhost:8080/myapp

这里, myapp是应用程序的名称,开发模式下应用程序的默认端口是8080。

使用Eclipse

在上一章中,我们讨论了如何在CLI中创建Tapestry Quick Start应用程序。 本章介绍如何在Eclipse IDE创建框架应用程序。

让我们使用Maven原型来创建骨架应用程序。 要配置新应用程序,您可以按照以下步骤进行操作。

第1步:打开Eclipse IDE

打开Eclipse并选择File→New→Project ...→选项,如以下屏幕截图所示。

打开Eclipse

现在,选择Maven→Maven项目选项。

Note - 如果未配置Maven,则配置并创建项目。

选择Maven项目后,单击“下一步”再次单击“下一步”按钮。

Maven项目

之后,您将看到一个屏幕,您应该选择配置选项。 配置完成后,您将看到以下屏幕。

配置选项

第2步:目录配置

完成第一步后,您应该单击“ Add Remote Catalog 。 然后添加以下更改,如以下屏幕截图所示。

远程目录

现在,添加了Apache Tapestry目录。 然后,选择过滤器选项org.apache.tapestry quickstart 5.4.1,如下所示。

添加了目录

然后单击“下一步”,将出现以下屏幕。

组ID字段

第3步:配置GroupId,ArtifactId,版本和包

将以下更改添加到Tapestry Catalog配置。

更改配置

然后单击Finish按钮,现在我们已经创建了第一个框架应用程序。 第一次使用Maven时,项目创建可能需要一段时间,因为Maven为Maven,Jetty和Tapestry下载了许多JAR依赖项。 Maven完成后,您将在Package Explorer视图中看到一个新目录MyFirstApplication。

第4步:使用Jetty服务器运行应用程序

您可以使用Maven直接运行Jetty。 在Package Explorer视图中右键单击MyFirstApplication项目,然后选择Run As→Maven Build ...您将看到如下所示的屏幕。

Jetty服务器

在配置对话框中,输入目标选项为“jetty:run”,然后单击“运行”按钮。

目标选项

Jetty初始化后,您将在控制台中看到以下屏幕。

Jetty初始化

第5步:在Web浏览器中运行

键入以下URL以在Web浏览器中运行应用程序 -

https://loclhost:8080/MyFirstApplication

运行Web浏览器

第6步:停止Jetty服务器

要停止Jetty服务器,请单击控制台中的红色方块图标,如下所示。

停止服务器

Apache Tapestry - Project Layout

以下是Maven Quickstart CLI创建的源代码的布局。 此外,这是标准Tapestry应用程序的建议布局。

├── build.gradle 
├── gradle 
│   └── wrapper 
│       ├── gradle-wrapper.jar 
│       └── gradle-wrapper.properties 
├── gradlew 
├── gradlew.bat 
├── pom.xml 
├── src 
│   ├── main 
│   │   ├── java 
│   │   │   └── com 
│   │   │       └── example 
│   │   │           └── MyFirstApplication 
│   │   │               ├── components 
│   │   │               ├── data 
│   │   │               ├── entities 
│   │   │               ├── pages 
│   │   │               └── services 
│   │   ├── resources 
│   │   │   ├── com 
│   │   │   │   └── example 
│   │   │   │       └── MyFirstApplication 
│   │   │   │           ├── components 
│   │   │   │           ├── logback.xml 
│   │   │   │           └── pages 
│   │   │   │               └── Index.properties  
│   │   │   ├── hibernate.cfg.xml 
│   │   │   └── log4j.properties
│   │   └── webapp 
│   │       ├── favicon.ico 
│   │       ├── images 
│   │       │   └── tapestry.png 
│   │       ├── mybootstrap 
│   │       │   ├── css 
│   │       │   │   ├── bootstrap.css 
│   │       │   │   └── bootstrap-theme.css 
│   │       │   ├── fonts 
│                   ├── glyphicons-halflings-regular.eot 
│   │       │   │   ├── glyphicons-halflings-regular.svg 
│   │       │   │   ├── glyphicons-halflings-regular.ttf 
│   │       │   │   ├── glyphicons-halflings-regular.woff 
│   │       │   │   └── glyphicons-halflings-regular.woff2 
│   │       │   └── js 
│   │       └── WEB-INF 
│   │           ├── app.properties 
│   │           └── web.xml 
│   ├── site 
│   │   ├── apt 
│   │   │   └── index.apt 
│   │   └── site.xml 
│   └── test 
│       ├── conf 
│       │   ├── testng.xml 
│       │   └── webdefault.xml 
│       ├── java 
│       │   └── PLACEHOLDER 
│       └── resources 
│           └── PLACEHOLDER 
└── target     
   ├── classes     
   │   ├── com  
   │   │   └── example
   │   │       └── MyFirstApplication     
   │   │           ├── components     
   │   │           ├── data     
   │   │           ├── entities     
   │   │           ├── logback.xml     
   │   │           ├── pages 
   │   │           │   └── Index.properties 
   │   │           └── services     
   │   ├── hibernate.cfg.xml 
   │   └── log4j.properties     
   ├── m2e-wtp 
   │   └── web-resources 
   │       └── META-INF     
   │           ├── MANIFEST.MF 
   │           └── maven 
   │               └── com.example 
   │                   └──MyFirstApplication     
   │                     ├── pom.properties 
   │                       └── pom.xml     
   ├── test-classes 
   │   └── PLACEHOLDER 
   └── work         
      ├── jsp         
      ├── sampleapp.properties 
      └── sampleapp.script

默认布局的排列方式与WAR Internal File Format 。 使用WAR格式有助于在不进行打包和部署的情况下运行应用程序。 这种布局只是一个建议,但如果在部署时将应用程序打包成适当的WAR格式,则可以以任何格式安排应用程序。

源代码可分为以下四个主要部分。

  • Java Code - 所有java源代码都放在/src/main/java文件夹下。 Tapestry页面类放在“Pages”文件夹下,Tapestry组件类放在components文件夹下。 Tapestry服务类位于services文件夹下。

  • ClassPath Resources - 在Tapestry中,大多数类都有相关的资源(XML模板,JavaScript文件等)。 这些资源位于/src/main/resources文件夹下。 Tapestry页面类在“Pages”文件夹下有相关的资源,Tapestry组件类在Components文件夹下有相关的资源。 这些资源打包到WAR的WEB-INF/classes文件夹中。

  • Context Resources - 它们是Web应用程序的静态资源,如Images,Style Sheet和JavaScript Library / Modules. They are usually placed under the /src/main/webapp / Modules. They are usually placed under the /src/main/webapp文件夹下,它们被称为Context Resources 。 此外,Web应用程序描述文件(Java Servlet),web.xml放在上下文资源的WEB-INF文件夹下。

  • Testing Code - 这些是用于测试应用程序的可选文件,位于src/test/javasrc/test/ Resources文件夹下。 它们没有打包成WAR。

Convention Over Configuration

Apache Tapestry在编程的各个方面遵循Convention over Configuration 。 框架的每个功能都有一个合理的默认约定。

例如,正如我们在“项目布局”一章中所了解的那样,所有页面都需要放在/src/main/java/«package_path»/pages/文件夹中才能被视为Tapestry页面。

在另一种意义上,不需要将特定的Java类配置为Tapestry Pages。 将类放在预定义的位置就足够了。 在某些情况下,遵循Tapestry的默认约定是很奇怪的。

例如,Tapestry组件可以有一个方法setupRender ,它将在渲染阶段开始时触发。 开发人员可能希望使用他们自己的意见名称,例如initializeValue 。 在这种情况下,Tapestry提供Annotation来覆盖约定,如以下代码块所示。

void setupRender() { 
   // initialize component 
}  
@SetupRender 
void initializeValue() { 
   // initialize component 
}

两种编程方式在Tapestry中都有效。 简而言之,Tapestry的默认配置非常少。 只需在“Web.xml”中配置Apache Tapestry Filter (Java Servlet Filter)即可正常运行应用程序。

Tapestry提供了另一种配置应用程序的方法,它被称为AppModule.java

Apache Tapestry - Annotation

注释是Tapestry利用的一个非常重要的特性,用于简化Web应用程序开发。 Tapestry提供了许多自定义注释。 它具有类,方法和成员字段的注释。 如前一节所述,Annotation也可用于覆盖功能的默认约定。 Tapestry注释分为四个主要类别,它们如下所示。

组件注释

用于Pages,Components和Mixins类。 一些有用的注释是 -

  • @Property - 适用于领域。 用于将字段转换为Tapestry属性。

  • @Parameter - 适用于字段。 用于将字段指定为组件的参数。

  • @Environmental - 适用于领域。 用于在不同组件之间共享私有字段。

  • @import - 适用于类和字段。 用于包括Assets,CSS和JavaScript。

  • @Path - 与@Inject批注结合使用,根据路径注入资产。

  • @Log - 适用于类和字段。 用于调试目的。 可以使用发出组件的事件信息,如事件的开始,事件的结束等。

IoC注释

用于将对象注入IoC Container。 一些有用的注释是 -

  • @Inject - 适用于字段。 用于标记应注入IoC容器的参数。 它标记应注入组件的字段。

  • @Value - 适用于字段。 与@inject批注一起使用以注入文字值而不是服务(这是@Inject批注的默认行为)。

数据保持类的注释

它用于在类(通常是模型或数据保持类)中为高级组件指定组件特定信息,例如

  • Grid (用于创建高级表格数据,如报表,图库等)

  • BeanEditForm (用于创建高级表单)

  • Hibernate (用于高级数据库访问)等

这些Annotations被聚合并打包到一个单独的jar中,没有任何tapestry依赖。 一些注释是 -

  • @DataType - 用于指定字段的数据类型。 Tapestry组件可以使用此信息在表示层中创建设计或标记。

  • @Validate - 用于指定字段的验证规则。

这些分离使Tapestry应用程序能够使用Multi-Tier Design

Apache Tapestry - Pages and Components

Tapestry Application只是Tapestry Pages的集合。 它们协同工作以形成定义良好的Web应用程序。 每个页面都有一个相应的XML模板和零个,一个或多个组件。 页面和组件是相同的,除了页面是根组件并且通常由应用程序开发人员创建。

Components are children of the root Pagecomponent 。 Tapestry有许多内置组件,可以选择创建自定义组件。

页面组件

Pages

如前所述,Pages是Tapestry应用程序的构建块。 页面是普通的POJO,放在 - /src/main/java/«package_path»/pages/文件夹下。 每个页面都有一个相应的XML Template ,其默认位置是 - /src/main/resources/«package_name»/pages/

您可以在此处看到页面和模板的路径结构类似,只是模板位于Resource Folder

例如,Tapestry应用程序中包含名称的用户注册页面 - com.example.MyFirstApplication将具有以下页面和模板文件 -

  • Java Class -

    /src/main/java/com/example/MyFirstApplication/pages/index.java

  • XML Template -

    /src/main/resources/com/example/MyFirstApplication/pages/index.tml

让我们创建一个简单的Hello World页面。 首先,我们需要在 - /src/main/java/com/example/MyFirstApplication/pages/HelloWorld.java上创建一个Java Class

package com.example.MyFirstApplication.pages; 
public class HelloWorld { 
}

然后,在 - 创建一个XML模板 -

“/src/main/resources/com/example/MyFirstApplication/pages/helloworld.html”。

<html xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <head> 
      <title>Hello World Page</title> 
   </head> 
   <body> 
      <h1>Hello World</h1> 
   </body> 
</html>

现在,可以通过https://localhost:8080/myapp/helloworld访问此页面。 这是一个简单的挂毯页面。 Tapestry提供了更多功能来开发动态网页,我们将在后面的章节中讨论。

Apache Tapestry - Templates

让我们在本节中考虑Tapestry XML模板。 XML模板是一个格式良好的XML文档。 页面的表示(用户界面)层是XML模板。 除下面给出的项目外,XML模板还具有普通的HTML标记 -

  • Tapestry命名空间
  • Expansions
  • Elements
  • Components

现在让我们详细讨论它们。

Tapestry命名空间

Tapestry命名空间只是XML命名空间。 应在模板的根元素中定义命名空间。 它用于在模板中包含Tapestry组件和组件相关信息。 最常用的命名空间如下 -

  • xmlns:t =“https://tapestry.apache.org/schema/tapestry_5_4.xsd” - 用于标识Tapestry的元素,组件和属性。

  • xmlns:p =“tapestry:parameter” - 用于将任意代码块传递给组件。

Tapestry Namespace的一个例子如下 -

<html xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_3.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <head> 
      <title>Hello World Page</title> 
   </head>  
   <body> 
      <h1>Hello World</h1> 
      <t:eventlink page = "Index">refresh page</t:eventlink> 
   </body> 
</html>

扩展(Expansions)

扩展是在页面的呈现阶段动态更改XML模板的简单而有效的方法。 扩展使用$ {}语法。 有许多选项可以表达XML模板中的扩展。 让我们看看一些最常用的选项 -

物业扩张

它映射相应Page类中定义的属性。 它遵循Java Bean中的属性定义的Java Bean规范。 它更进一步忽略了属性名称的情况。 让我们使用属性扩展来更改“Hello World”示例。 以下代码块是修改后的Page类。

package com.example.MyFirstApplication.pages; 
public class HelloWorld {   
   // Java Bean Property 
   public String getName { 
      return "World!"; 
   } 
}

然后,更改相应的XML模板,如下所示。

<html xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <head> 
      <title>Hello World Page</title> 
   </head> 
   <body> 
      <!-- expansion --> 
      <h1>Hello ${name}</h1> 
   </body> 
</html>

在这里,我们在Page类中将name定义为Java Bean Property ,并使用扩展${name}在XML Template中对其进行动态处理。

消息扩展

每个Page类可能有也可能没有资源文件夹中的关联属性文件 - «page_name».properties 。 属性文件是纯文本文件,每行具有单个键/值对(消息)。 让我们为HelloWorld Page创建一个属性文件 -

“/src/main/resources/com/example/MyFirstApplication/pages/helloworld.properties”并添加“问候”消息。

Greeting = Hello

Greeting消息可以在XML模板中用作${message:greeting}

<html xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <head> 
      <title>Hello World Page</title> 
   </head> 
   <body> 
      <!-- expansion --> 
      <h1>${message:greeting} ${name}</h1> 
   </body> 
</html>

元素 (Elements)

Tapestry有一小组要在XML模板中使用的元素。 元素是在Tapestry命名空间下定义的预定义标记 -

https://tapestry.apache.org/schema/tapestry_5_4.xsd

每个元素都是为特定目的而创建的。 可用的挂毯元素如下 -

当嵌套两个组件时,父组件的模板可能必须包装子组件的模板。 元素在这种情况下很有用。 的一个用途是在模板布局中。

通常,Web应用程序的用户界面将具有公共页眉,页脚,菜单等。这些常用项目在XML模板中定义,它被称为模板布局或布局组件。 在Tapestry中,它需要由应用程序开发人员创建。 布局组件只是另一个组件,位于components文件夹下,该文件夹具有以下路径: src/main/«java|resources»/«package_name»/components

让我们创建一个名为MyCustomLayout的简单布局组件。 MyCustomLayout的代码如下 -

<!DOCTYPE html> 
<html xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <head> 
      <meta charset = "UTF-8" />
      <title>${title}</title>  
   </head> 
   <body> 
      <div>Sample Web Application</div> 
      <h1>${title}</h1> 
      <t:body/> 
      <div>(C) 2016 IoWiki.</div> 
   </body> 
</html> 

package com.example.MyFirstApplication.components;  
import org.apache.tapestry5.*; 
import org.apache.tapestry5.annotations.*; 
import org.apache.tapestry5.BindingConstants;  
public class MyCustomLayout { 
   @Property 
   @Parameter(required = true, defaultPrefix = BindingConstants.LITERAL) 
      private String title; 
}

在MyCustomLayout组件类中,我们声明了一个标题字段,并且通过使用注释,我们将其强制化。 现在,更改HelloWorld.html模板以使用我们的自定义布局,如下面的代码块所示。

<html>
   t:type = "mycustomlayout" title = "Hello World Test page"
      xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <h1>${message:greeting} ${name}</h1> 
</html>

我们在这里可以看到XML模板没有head和body标签。 Tapestry将从布局组件中收集这些详细信息,布局组件的将替换为HelloWorld模板。 一切都完成后,Tapestry将发出如下所示的类似标记 -

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset = "UTF-8" /> 
      <title>Hello World Test Page</title> 
   </head> 
   <body> 
      <div>Sample Web Application</div> 
      <h1>Hello World Test Page</h1> 
      <h1>Hello World!</h1> 
      <div>(C) 2016 IoWiki.</div> 
   </body> 
</html>

布局可以嵌套。 例如,我们可以通过包含管理功能来扩展我们的自定义布局,并将其用于管理部分,如下所示。

<html t:type = "MyCommonLayout" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <div><!-- Admin related items --><div> 
   <t:body/> 
</html>

《t:container》

是一个顶级元素,包含一个tapestry命名空间。 这用于指定组件的动态部分。

例如,网格组件可能需要一个模板来标识如何在HTML表格中呈现其行 - tr(和列td)。

<t:container xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <td>${name}</td> 
   <td>${age}</td> 
</t:container>

《t:block》

是模板中动态部分的占位符。 通常,块元素不呈现。 仅,模板中定义的组件使用块元素。 组件会将数据动态注入块元素并进行渲染。 一个流行的用例是AJAX

块元素为要呈现的动态数据提供精确的位置和标记。 每个块元素都应具有相应的Java属性。 只有这样它才能被动态渲染。 块元素的id应遵循Java变量标识符规则。 部分样品如下。

@Inject 
private Block block;  
<html t:type = "mycustomlayout" title = "block example" 
   xmlns:t = "https://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
<h1>${title}</h1>  
<!--  
   ... 
   ...  
--> 
<t:block t:id = "block"> 
   <h2>Highly dynamic section</h2> 
   I'v been updated through AJAX call 
   The current time is: <strong>${currentTime}</strong>
</t:block>  
<!--  
   ... 
   ...  
-->  
</html>

《t:content》

元素用于指定模板的实际内容。 通常,所有标记都被视为模板的一部分。 如果指定,则仅考虑其中的标记。 设计人员使用此功能来设计没有布局组件的页面。

《t:remove》

与内容元素正好相反。 remove元素中的标记不被视为模板的一部分。 它可用于仅用于服务器的注释和用于设计目的。

Assets

资产是静态资源文件,例如样式表,图像和JavaScript文件。 通常,资产放在Web应用程序根目录/src/main/webapp

<head> 
   <link href = "/css/site.css" rel = "stylesheet" type = "text/css"/>

Tapestry还将存储在Java Classpath中的文件视为Assets。 Tapestry提供了高级选项,可通过扩展选项将资产包含到模板中。

  • Context - 在Web上下文中获取资产的选项。

<img src = "${context:image/tapestry_banner.gif}" alt = "Banner"/>

asset - 组件通常将自己的资产与Java类一起存储在jar文件中。 从Tapestry 5.4开始,在类路径中存储资产的标准路径是META-INF/assets 。 对于库,存储资产的标准路径是META-INF/assets/«library_name»/. asset: META-INF/assets/«library_name»/. asset:还可以调用context: expansion来从Web上下文中获取资产。

<img src = "${asset:context:image/tapestry_banner.gif}" alt = "Banner"/>

可以使用Inject和Path注释将资产注入Tapestry页面或组件。 Path注释的参数是资产的相对路径。

@Inject 
@Path("images/edit.png") 
private Asset icon;

Path parameter还可以包含AppModule.java部分中定义的Tapestry符号。

例如,我们可以使用值context:skin/basic定义一个符号skin.root并使用它,如下所示 -

@Inject 
@Path("${skin.root}/style.css") 
private Asset style;

本地化(Localization)

通过tapestry包含资源可提供额外的功能。 一个这样的功能是“本地化”。 Tapestry将检查当前的语言环境并包含适当的资源。

例如,如果当前区域设置设置为de ,则将包含edit_de.png而不是edit.png。

CSS

Tapestry具有内置样式表支持。 Tapestry将注入tapestry.css作为核心Javascript堆栈的一部分。 从Tapestry 5.4开始,tapestry也包含bootstrap css framework 。 我们可以使用普通链接标记包含我们自己的样式表。 在这种情况下,样式表应该位于Web根目录 - /src/main/webapp/

<head> 
   <link href = "/css/site.css" rel = "stylesheet" type = "text/css"/>

Tapestry提供高级选项,通过扩展选项将样式表包含到模板中,如前所述。

<head> 
   <link href = "${context:css/site.css}" rel = "stylesheet" type = "text/css"/> 

Tapestry还提供了Import注释,以将样式表直接包含在Java类中。

@Import(stylesheet="context:css/site.css") 
public class MyCommonLayout { 
} 

Tapestry提供了许多通过AppModule.java管理样式表的选项。 一些重要的选择是 -

  • 可以删除tapestry默认样式表。

@Contribute(MarkupRenderer.class) 
public static void 
deactiveDefaultCSS(OrderedConfiguration<MarkupRendererFilter> configuration) { 
   configuration.override("InjectDefaultStyleheet", null); 
} 
  • 也可以通过覆盖其路径来禁用Bootstrap。

configuration.add(SymbolConstants.BOOTSTRAP_ROOT, "classpath:/METAINF/assets");
  • 启用动态最小化资产(CSS和JavaScript)。 我们还需要包含tapestry-webresources依赖(在pom.xml中)。

@Contribute(SymbolProvider.class) 
@ApplicationDefaults 
public static void contributeApplicationDefaults( 
   MappedConfiguration<String, String> configuration) { 
   configuration.add(SymbolConstants.MINIFICATION_ENABLED, "true"); 
} 
<dependency> 
   <groupId>org.apache.tapestry</groupId> 
   <artifactId>tapestry-webresources</artifactId> 
   <version>5.4</version> 
</dependency> 

客户端JavaScript

当前一代的Web应用程序在很大程度上依赖于JavaScript来提供丰富的客户端体验。 Tapestry承认它并为JavaScript提供一流的支持。 JavaScript支持深深扎根于挂毯,并且在编程的每个阶段都可用。

早些时候,Tapestry过去只支持Prototype和Scriptaculous。 但是,从版本5.4开始,tapestry完全重写了JavaScript层,使其尽可能通用,并为JQuery(JavaScript的事实库)提供了一流的支持。 此外,tapestry鼓励基于模块的JavaScript编程,并支持RequireJS,这是AMD的一种流行的客户端实现(异步模块定义 - JavaScript规范,以异步方式支持模块及其依赖性)。

Location

JavaScript文件是Tapestry应用程序的资产。 根据资产规则,JavaScript文件放在Web上下文/sr/main/webapp/或放在META-INF/assets/ location下的jar中。

链接JavaScript文件

链接XML模板中JavaScript文件的最简单方法是直接使用脚本标记,即《script language = "javascript" src = "relative/path/to/js"》《/script》 。 但是,tapestry不推荐这些方法。 Tapestry提供了几个选项来链接页面/组件本身的JavaScript文件。 其中一些在下面给出。

  • @import annotation - @import annotation提供了使用上下文表达式链接多个JavaScript库的选项。 它可以应用于Page类及其方法。 如果应用于Page类,则它适用于其所有方法。 如果应用于Page的方法,它只适用于该方法,然后Tapestry仅在调用方法时链接JavaScript库。

@Import(library = {"context:js/jquery.js","context:js/myeffects.js"}) 
public class MyComponent { 
   // ... 
}
  • JavaScriptSupport interface --JavaScriptSupport是由tapestry定义的接口,它有一个方法importJavaScriptLibrary来导入JavaScript文件。 只需使用@Environmental注释声明和注释即可轻松创建JavScriptSupport对象。

@Inject @Path("context:/js/myeffects.js") 
private Asset myEffects;  
@Environmental 
private JavaScriptSupport javaScriptSupport;  
void setupRender() { 
   javaScriptSupport.importJavaScriptLibrary(myEffects); 
}
  • JavaScripSupport只能使用@Environmental注释注入组件。 对于服务,我们需要使用@Inject批注或将其作为参数添加到服务构造函数方法中。

@Inject 
private JavaScriptSupport javaScriptSupport; 
public MyServiceImpl(JavaScriptSupport support) { 
   // ... 
}
  • addScript method - 这与JavaScriptSupport接口类似,只是它使用addScript方法,并且代码直接添加到页面底部的输出中。

void afterRender() { 
   javaScriptSupport.addScript(
      "$('%s').observe('click', hideMe());", container.getClientId()); 
}

JavaScript堆栈

Tapestry允许组合一组JavaScript文件和相关样式表,并将其用作单个实体。 目前,Tapestry包括基于Prototype和基于JQuery的堆栈。

开发人员可以通过实现JavaScriptStack接口开发自己的堆栈,并在AppModule.java注册它。 注册后,可以使用@import注释导入堆栈。

@Contribute(JavaScriptStackSource.class) 
public static void addMyStack(
   MappedConfiguration<String, JavaScriptStack> configuration) { 
   configuration.addInstance("MyStack", myStack.class); 
}  
@Import(stack = "MyStack") 
public class myPage { 
}

Apache Tapestry - Components

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

Tapestry组件使用interactive AJAX呈现简单的HTML链接到复杂的网格功能。 组件也可以包括另一个组件。 Tapestry组件包括以下项目 -

  • Component Class - Component Class的主要Java类。

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

  • 正文 - 页面模板中指定的组件可能具有自定义标记,并且它被称为“组件主体”。 如果组件模板具有《body /》元素,则“body /”元素将被组件的主体替换。 这类似于前面在XML模板部分中讨论的布局。

  • Rendering - 渲染是将组件的XML模板和主体转换为组件的实际输出的过程。

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

  • Events - 将组件的功能委托给其容器/父级(页面或其他组件)。 它广泛用于页面导航目的。

渲染(Rendering)

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

// 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)

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

BeginRender (BeginRender)

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

BeforeRenderTemplate

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

BeforeRenderBody (BeforeRenderBody)

BeforeRenderTemplate提供了跳过组件body元素渲染的选项。

AfterRenderBody (AfterRenderBody)

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

AfterRenderTemplate

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

AfterRender (AfterRender)

AfterRender是BeginRender的对应物,通常呈现close标签。

CleanupRender (CleanupRender)

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>

参数 (Parameters)

这些参数的主要目的是在组件的字段和页面的属性/资源之间创建连接。 使用参数,组件及其相应的页面在彼此之间进行通信和传输数据。 这称为Two Way Data Binding

例如,用于表示用户管理页面中的年龄的文本框组件通过参数获得其初始值(在数据库中可用)。 同样,在用户的年龄更新并提交回来之后,组件将通过相同的参数发回更新的年龄。

要在组件类中创建新参数,请声明一个字段并指定@Parameter注释。 这个@Parameter有两个可选参数,它们是 -

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

  • value - 指定参数的默认值。

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

  • 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») - 用于指定对象验证规则的专用字符串。 例如,验证:required,minLength = 5。

  • Translate (translate:«val») - 用于在输入验证中指定Translator类(将客户端转换为服务器端表示)。

  • Block (block:«val») - 模板中块元素的id。

  • Component (component:«val») - 模板中另一个组件的id。

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

组件使用参数

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

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

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

@Parameter(required = true) 
private String name;
  • 使用@Propery注释添加私有字段,结果。 result属性将在组件模板中使用。 组件模板无权访问使用@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。 这称为Type Coercion ,一种将一种类型的对象转换为具有相同内容的另一种类型的方法。

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

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

  • 如果数据类型为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应用程序是一collection of Pages彼此交互collection of Pages 。 到目前为止,我们已经学会了如何在没有任何通信的情况下创建单个页面。 Component事件的主要目的是使用服务器端事件在页面之间(在页面内)提供交互。 大多数组件事件源自客户端事件。

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

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

  • Component Event Request - 此类请求以页面中的特定组件为目标,并在组件内引发事件。 此请求仅执行重定向,不输出响应。

  • Render Request - 这些类型的请求以页面为目标,并将响应流回客户端。

要了解组件事件和页面导航,我们需要知道tapestry请求的URL模式。 两种请求的URL模式如下 -

  • Component Event Requests -

/<<page_name_with_path>>.<<component_id|event_id>>/<<context_information>>
  • Render Request -

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

URL模式的一些示例是 -

  • 索引页面可以通过https://«domain»/«app»/index请求。

  • 如果索引页面在子文件夹admin下可用,则可以通过https://«domain»/«app»/admin/index请求它。

  • 如果用户在索引页面中单击带有id testActionLink component ,则URL将为https://«domain»/«app»/index.test

事件 (Events)

默认情况下,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; 
   } 
}

Apache Tapestry - Built-In Components

本章通过适当的示例介绍了Tapestry的内置组件。 Tapestry支持超过65种内置组件。 您还可以创建自定义组件。 让我们详细介绍一些值得注意的组件。

如果是组件

if组件用于有条件地呈现块。 通过测试参数检查条件。

创建一个页面IfSample.java如下所示 -

package com.example.MyFirstApplication.pages;  
public class Ifsample {
   public String getUser() { 
      return "user1"; 
   } 
} 

现在,创建一个相应的模板文件,如下所示 -

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h3>If-else component example </h3> 
   <t:if test = "user"> 
      Hello ${user} 
      <p:else>
         <h4> You are not a Tapestry user </h4> 
      </p:else> 
   </t:if> 
</html>

请求页面将呈现如下所示的结果。

Result - http:// localhost:8080/MyFirstApplication/ifsample

如果是组件结果

除非和委托组件

unless component恰好与上面讨论的if组件相反。 虽然, delegate component本身不进行任何渲染。 相反,它通常将标记委托给块元素。 除非组件可以使用委托和块来有条件地交换动态内容。

创建一个页面, Unless.java如下。

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.Block; 
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.ioc.annotations.Inject; 
import org.apache.tapestry5.PersistenceConstants; 
import org.apache.tapestry5.annotations.Persist;  
public class Unless { 
   @Property 
   @Persist(PersistenceConstants.FLASH) 
   private String value;  
   @Property 
   private Boolean bool; 
   @Inject 
   Block t, f, n;  
   public Block getCase() { 
      if (bool == Boolean.TRUE ) { 
         return t; 
      } else { 
         return f; 
      } 
   }   
} 

现在,创建一个相应的模板文件,如下所示 -

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h4> Delegate component </h4> 
   <div class = "div1"> 
      <t:delegate to = "case"/> 
   </div> 
   <h4> If-Unless component </h4>  
   <div class = "div1"> 
      <t:if test = "bool"> 
         <t:delegate to = "block:t"/> 
      </t:if> 
      <t:unless test = "bool"> 
         <t:delegate to = "block:notT"/> 
      </t:unless> 
   </div>  
   <t:block id = "t"> 
      bool == Boolean.TRUE. 
   </t:block> 
   <t:block id = "notT"> 
      bool = Boolean.FALSE. 
   </t:block> 
   <t:block id = "f"> 
      bool == Boolean.FALSE. 
   </t:block> 
</html>

请求页面将呈现如下所示的结果。

Result - http:// localhost:8080/MyFirstApplication/unless

委托组件

循环组件

循环组件是循环集合项的基本组件,并为每个值/迭代渲染正文。

创建一个Loop页面,如下所示 -

Loop.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property;  
public class Loop { 
   @Property 
   private int i; 
}

然后,创建相应的模板Loop.tml

Loop.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <p>This is sample parameter rendering example...</p> 
   <ol>
      <li t:type = "loop" source = "1..5" value = "var:i">${var:i}</li> 
   </ol> 
</html>

循环组件有以下两个参数 -

  • source - 收集源。 1 ... 5是用于创建具有指定范围的数组的属性扩展。

  • var - 渲染变量。 用于呈现模板正文中的当前值。

请求页面将呈现如下所示的结果 -

循环组件

PageLink组件

PageLink组件用于将页面从一个页面链接到另一个页面。 创建一个PageLink测试页面如下 - PageLink.java

package com.example.MyFirstApplication.pages;  
   public class PageLink { 
}

然后,创建一个相应的模板文件,如下所示 -

PageLink.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <body> 
      <h3><u>Page Link</u> </h3> 
      <div class = "page"> 
         <t:pagelink page = "Index">Click here to navigate Index page</t:pagelink>
         <br/> 
      </div> 
   </body> 
</html>

PageLink组件有一个页面参数,该参数应该引用目标tapestry页面。

Result - http:// localhost:8080/myFirstApplication/pagelink

页面链接

EventLink组件

EventLink组件通过URL发送事件名称和相应的参数。 创建一个EventsLink页面类,如下所示。

EventsLink.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property;  
public class EventsLink { 
   @Property 
   private int x; 
   void onActivate(int count) { 
      this.x = x; 
   } 
   int onPassivate() { 
      return x; 
   } 
   void onAdd(int value) { 
      x += value; 
   }   
}

然后,创建相应的“EventsLink”模板文件,如下所示 -

EventsLink.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h3> Event link example </h3> 
   AddedCount = ${x}. <br/> 
   <t:eventlink t:event = "add" t:context = "literal:1">
      Click here to add count
   </t:eventlink><br/>  
</html>

EventLink有以下两个参数 -

  • Event - 要在EventLink组件中触发的事件的名称。 默认情况下,它指向组件的id。

  • Context - 它是一个可选参数。 它定义了链接的上下文。

Result - http:// localhost:8080/myFirstApplication/EventsLink

事件链接

单击计数值后,页面将在URL中显示事件名称,如以下输出屏幕截图所示。

事件链接结果

ActionLink组件

ActionLink组件类似于EventLink组件,但它仅发送目标组件ID。 默认事件名称是action。

创建一个页面“ActivationLinks.java”,如下所示,

ActivationLinks.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property;  
public class ActivationLinks {  
   @Property 
   private int x;  
   void onActivate(int count) { 
      this.x = x; 
   }  
   int onPassivate() { 
      return x; 
   } 
   void onActionFromsub(int value) { 
      x -= value; 
   } 
} 

现在,创建一个相应的模板文件,如下所示 -

ActivationLinks.tml

<html t:type = "Newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <div class = "div1"> 
      Count = ${count}. <br/> 
      <t:actionlink t:id = "sub" t:context = "literal:1">
         Decrement
      </t:actionlink><br/> 
   </div> 
</html> 

这里,单击ActionLink组件时将调用OnActionFromSub方法。

Result - http:// localhost:8080/myFirstApplication/ActivationsLink

行动链接

警报组件

警报对话框主要用于向用户发出警告消息。 例如,如果输入字段需要一些必需的文本但用户不提供任何输入,那么作为验证的一部分,您可以使用警告框来发出警告消息。

创建一个“警报”页面,如以下程序所示。

Alerts.java

package com.example.MyFirstApplication.pages;  
public class Alerts { 
   public String getUser() { 
      return "user1"; 
   } 
}

然后,创建一个相应的模板文件,如下所示 -

Alerts.tml

<html t:type = "Newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"  
   xmlns:p = "tapestry:parameter">  
   <h3>Alerts</h3> 
   <div class = "alert alert-info"> 
      <h5> Welcome ${user} </h5> 
   </div>
</html>

警报有三个严重级别,分别是 -

  • Info
  • Warn
  • Error

使用信息警报创建上述模板。 它被定义为alert-info 。 您可以根据需要创建其他严重性。

请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/Alerts

警报

Forms & Validation Components

Form Component用于在tapestry页面中创建用于用户输入的表单。 表单可以包含文本字段,日期字段,复选框字段,选择选项,提交按钮等。

本章详细介绍了一些值得注意的表单组件。

复选框组件

Checkbox Component用于在两个互斥选项之间进行选择。 使用Checkbox创建页面,如下所示 -

Checkbox.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property;  
public class Checkbox { 
   @Property 
   private boolean check1; 
   @Property 
   private boolean check2; 
}

现在,创建一个相应的模板Checkbox.tml ,如下所示 -

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h3> checkbox component</h3>  
   <t:form> 
      <t:checkbox t:id = "check1"/> I have a bike <br/> 
      <t:checkbox t:id = "check2"/> I have a car 
   </t:form>  
</html> 

这里,checkbox参数id与相应的布尔值匹配。

Result - 请求页面后,http:// localhost:8080/myFirstApplication /复选框产生以下结果。

复选框

TextField组件

TextField组件允许用户编辑单行文本。 创建页面Text如下所示。

Text.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.corelib.components.TextField;public class Text {  
   @Property 
   private String fname;  
   @Property 
   private String lname; 
}

然后,创建一个相应的模板,如下所示 - Text.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <p> Form application </p>
   <body>  
      <h3> Text field created from Tapestry component </h3> 
      <t:form>  
         <table> 
            <tr> 
               <td> 
                  Firstname: </td> <td><t:textfield t:id = "fname" /> 
               </td> 
               <td>Lastname: </td> <td> <t:textfield t:id = "lname" /> </td> 
            </tr> 
         </table>  
      </t:form>  
   </body> 
</html>

这里,Text页面包含一个名为fnamelname的属性。 组件ID由属性访问。

请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/Text

文本域

PasswordField组件

PasswordField是密码的专用文本字段条目。 创建页面密码如下所示 -

Password.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.corelib.components.PasswordField;  
public class Password {  
   @Property 
   private String pwd; 
}

现在,创建一个相应的模板文件如下图所示 -

Password.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <p> Form application </p>  
   <h3> Password field created from Tapestry component </h3> 
   <t:form> 
      <table> 
         <tr> 
            <td> Password: </td> 
            <td><t:passwordfield t:id = "pwd"/> </td> 
         </tr> 
      </table> 
   </t:form>
</html> 

这里,PasswordField组件具有参数id,它指向属性pwd 。 请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/Password

密码字段

TextArea组件

TextArea组件是一个多行输入文本控件。 创建一个页面TxtArea,如下所示。

TxtArea.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.corelib.components.TextArea;  
public class TxtArea {  
   @Property 
   private String str;  
}

然后,创建相应的模板文件,如下所示。

TxtArea.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h3>TextArea component </h3>
   <t:form>
      <table>
         <tr> 
            <td><t:textarea t:id = "str"/>
            </td>
         </tr>
      </table>
   </t:form>
</html>

这里,TextArea组件参数id指向属性“str”。 请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/TxtArea**

TextArea组件

选择组件

Select组件包含一个选项下拉列表。 创建一个SelectOption页面,如下所示。

SelectOption.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.corelib.components.Select;  
public class SelectOption { 
   @Property 
   private String color0; 
   @Property 
   private Color1 color1; 
   public enum Color1 { 
      YELLOW, RED, GREEN, BLUE, ORANGE 
   } 
}

然后,创建相应的模板如下 -

SelectOption.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <p> Form application </p>
   <h3> select component </h3>  
   <t:form> 
      <table> 
         <tr> 
            <td> Select your color here: </td> 
            <td> <select t:type = "select" t:id = "color1"></select></td> 
         </tr> 
      </table> 
   </t:form>
</html>

这里,Select组件有两个参数 -

  • Type - 属性的类型是枚举。

  • Id - Id指向Tapestry属性“color1”。

请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/SelectOption

选择组件

RadioGroup组件

RadioGroup组件为Radio组件提供容器组。 Radio和RadioGroup组件一起工作以更新对象的属性。 该组件应该包裹其他Radio组件。 创建一个新页面“Radiobutton.java”,如下所示 -

Radiobutton.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.PersistenceConstants; 
import org.apache.tapestry5.annotations.Persist; 
import org.apache.tapestry5.annotations.Property;  
public class Radiobutton {  
   @Property 
   @Persist(PersistenceConstants.FLASH)  
   private String value; 
}

然后,创建相应的模板文件如下图所示 -

Radiobutton.tml

<html t:type = "Newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <h3>RadioGroup component </h3> 
   <t:form>
      <t:radiogroup t:id = "value">
         <t:radio t:id = "radioT" value = "literal:T" label = "Male" /> 
         <t:label for = "radioT"/>    
         <t:radio t:id = "radioF" value = "literal:F" label = "Female"/> 
         <t:label for = "radioF"/>   
      </t:radiogroup>
   </t:form>
</html>

这里,RadioGroup组件id与属性“value”绑定。 请求页面将产生以下结果。

http://localhost:8080/myFirstApplication/Radiobutton

广播组

提交组件

当用户单击提交按钮时,表单将发送到标记的操作设置中指定的地址。 创建一个SubmitComponent页面,如下所示。

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.InjectPage;  
public class SubmitComponent { 
   @InjectPage 
   private Index page1; 
   Object onSuccess() { 
      return page1; 
   }     
}

现在,创建一个相应的模板文件,如下所示。

SubmitComponent.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <h3>Tapestry Submit component </h3> 
   <body> 
      <t:form> 
         <t:submit t:id = "submit1" value = "Click to go Index"/> 
      </t:form> 
   </body>
</html>

这里,Submit组件将值提交到Index页面。 请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/SubmitComponent

提交组件

表格验证

在客户输入所有必要数据然后提交表单后,表单验证通常发生在服务器上。 如果客户端输入的数据不正确或只是丢失,则服务器必须将所有数据发送回客户端,并请求使用正确的信息重新提交表单。

让我们考虑以下简单示例来理解验证过程。

创建页面Validate如下所示。

Validate.java

package com.example.MyFirstApplication.pages;  
import org.apache.tapestry5.annotations.Property; 
import org.apache.tapestry5.PersistenceConstants; 
import org.apache.tapestry5.annotations.Persist;  
public class Validate {  
   @Property 
   @Persist(PersistenceConstants.FLASH) 
   private String firstName; 
   @Property 
   @Persist(PersistenceConstants.FLASH) 
   private String lastName; 
}

现在,创建一个相应的模板文件,如下所示。

Validate.tml

<html t:type = "newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter"> 
   <t:form> 
      <table> 
         <tr> 
            <td><t:label for = "firstName"/>:</td> 
            <td><input t:type = "TextField" t:id = "firstName" 
            t:validate = "required, maxlength = 7" size = "10"/></td>   
         </tr> 
         <tr> 
            <td><t:label for = "lastName"/>:</td> 
            <td><input t:type = "TextField" t:id = "lastName" 
            t:validate = "required, maxLength = 5" size = "10"/></td>  
         </tr>  
      </table>  
      <t:submit t:id = "sub" value =" Form validation"/>  
   </t:form>
</html>

表格验证具有以下重要参数 -

  • Max - 定义最大值,例如=«最大值,20»。

  • MaxDate - 定义maxDate,例如=«最大日期,06/09/2013»。 同样,您也可以指定MinDate。

  • MaxLength - maxLength for eg =«maximum length,80»。

  • Min - 最小。

  • MinLength - 最小长度,例如=«minmum length,2»。

  • Email - 电子邮件验证,使用标准电子邮件regexp ^\w [._\w] *\w @\w [-._\w] *\w \。\ w2,6 $或无。

请求页面将产生以下结果 -

http://localhost:8080/myFirstApplication/Validate

表格验证

Apache Tapestry - Ajax Component

AJAX代表Asynchronous JavaScript and XML 。 它是一种借助XML, JSON, HTML, CSS,JavaScript创建更好,更快,更交互的Web应用程序的技术。 AJAX允许您在不重新加载网页的情况下异步发送和接收数据,因此速度很快。

区域组件

区域组件用于提供内容(标记)以及内容本身的位置。 Tape Component内部使用Zone Component的主体来生成内容。 生成动态内容后,Tapestry会将其发送到客户端,在正确的位置重新呈现数据,触发并动画HTML以吸引用户的注意力。

此Zone组件与EventLink组件一起使用。 EventLink可以选择使用t:zone属性将其绑定到特定区域。 在EventLink中配置区域后,单击EventLink将触发区域更新。 此外,EventLink事件(refreshZone)可用于控制动态数据的生成。

AJAX的一个简单示例如下 -

AjaxZone.tml

<html t:type = "Newlayout" title = "About MyFirstApplication" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd" 
   xmlns:p = "tapestry:parameter">  
   <body> 
      <h1>Ajax time zone example</h1>  
      <div class = "div1">  
         <a t:type = "eventlink" t:event = "refreshZone" href = "#" 
            t:zone = "timeZone">Ajax Link </a><br/><br/> 
         <t:zone t:id = "timeZone" id = "timeZone">Time zone: ${serverTime}</t:zone> 
      </div>  
   </body>
</html> 

AjaxZone.java

package com.example.MyFirstApplication.pages;  
import java.util.Date; 
import org.apache.tapestry5.annotations.InjectComponent; 
import org.apache.tapestry5.corelib.components.Zone; 
import org.apache.tapestry5.ioc.annotations.Inject; 
import org.apache.tapestry5.services.Request;  
public class AjaxZone { 
   @Inject 
   private Request request; 
   @InjectComponent 
   private Zone timeZone; 
   void onRefreshPage() { 
   } 
   Object onRefreshZone() { 
      return request.isXHR() ? timeZone.getBody() : null; 
   } 
   public Date getServerTime() { 
      return new Date(); 
   } 
} 

结果将显示在:http:// localhost:8080/MyFirstApplication/AjaxZone

阿贾克斯时区

Apache Tapestry - Hibernate

在本章中,我们将讨论BeanEditFormGrid component与Hibernate的集成。 Hibernate通过hibernate模块集成到tapestry中。 要启用hibernate模块,请在pom.xml文件中添加tapestry-hibernate依赖项和可选的hsqldb 。 现在,通过放置在资源文件夹根目录的hibernate.cfg.xml文件配置hibernate。

pom.xml (partial)

<dependency> 
   <groupId>org.apache.tapestry</groupId> 
   <artifactId>tapestry-hibernate</artifactId> 
   <version>${tapestry-release-version}</version> 
</dependency>  
<dependency> 
   <groupId>org.hsqldb</groupId> 
   <artifactId>hsqldb</artifactId> 
   <version>2.3.2</version> 
</dependency>

Hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC 
   "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
   "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
   <session-factory> 
      <property name = "hibernate.connection.driver_class">
         org.hsqldb.jdbcDriver
      </property> 
      <property name = "hibernate.connection.url">
         jdbc:hsqldb:./target/work/sampleapp;shutdown = true
      </property> 
      <property name = "hibernate.dialect">
         org.hibernate.dialect.HSQLDialect
      </property> 
      <property name = "hibernate.connection.username">sa</property> 
      <property name = "hibernate.connection.password"></property> 
      <property name = "hbm2ddl.auto">update</property>
      <property name = "hibernate.show_sql">true</property> 
      <property name = "hibernate.format_sql">true</property> 
   </session-factory> 
</hibernate-configuration> 

让我们看看如何使用Bean组件创建employee add page使用BeanEditForm组件和employee list page 。 持久层由Hibernate模块处理。

创建一个员工类并使用@Entity注释进行装饰。 然后,为相关字段添加验证注释,并为id字段添加hibernate相关注释@Id和@GeneratedValue。 另外,将性别设置为枚举类型。

Employee.java

package com.example.MyFirstApplication.entities;  
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id;  
import org.apache.tapestry5.beaneditor.NonVisual; 
import org.apache.tapestry5.beaneditor.Validate;  
@Entity 
public class Employee {  
   @Id 
   @GeneratedValue(strategy = GenerationType.IDENTITY) 
   @NonVisual 
   public Long id;  
   @Validate("required") 
   public String firstName;  
   @Validate("required") 
   public String lastName; 
   @Validate("required") 
   public String userName;  
   @Validate("required") 
   public String password;  
   @Validate("required") 
   public String email;  
   public String phone;  
   @Validate("required") 
   public String Street;  
   @Validate("required") 
   public String city;  
   @Validate("required") 
   public String state;  
   @Validate("required,regexp=^\\d{5}(-\\d{4})?$") 
   public String zip; 
} 
Gender.java (enum)  
package com.example.MyFirstApplication.data;  
public enum Gender { 
   Male, Female 
}

在页面下的新文件夹employee中创建员工列表页面ListEmployee.java ,在/src/main/resources/pages/employee文件夹中创建相应的模板文件ListEmployee.tml。 Tapestry通过删除重复数据为子文件夹提供短URL。

例如,ListEmployee页面可以通过普通URL(/ employee/listemployee)和短URL(/ employee/list)访问。

使用@Inject批注将Hibernate会话注入列表页面。 在列表页面中定义属性getEmployees ,并使用注入的会话对象向员工填充它。 完成员工类的代码,如下所示。

ListEmployee.java

package com.example.MyFirstApplication.pages.employee;  
import java.util.List;  
import org.apache.tapestry5.annotations.Import; 
import org.apache.tapestry5.ioc.annotations.Inject;  
import org.hibernate.Session; 
import com.example.MyFirstApplication.entities.Employee; 
import org.apache.tapestry5.annotations.Import;  
@Import(stylesheet="context:mybootstrap/css/bootstrap.css") 
public class ListEmployee { 
   @Inject 
   private Session session; 
   public List<Employee> getEmployees() { 
      return session.createCriteria(Employee.class).list(); 
   } 
} 

为ListEmployee类创建模板文件。 该模板将有两个主要组件,分别是 -

  • PageLink - 创建员工链接页面。

  • Grid - 用于呈现员工详细信息。 网格组件具有源属性以注入员工列表,并包括属性以包括要呈现的字段。

ListEmployee.tml(列出所有员工)

<html t:type = "simplelayout" title = "List Employee" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd"> 
   <h1>Employees</h1> 
   <ul> 
      <li><t:pagelink page = "employee/create">Create new employee</t:pagelink></li> 
   </ul>  
   <t:grid source = "employees" 
      include = "userName,firstName,lastName,gender,dateOfBirth,phone,city,state"/>  
</html>

创建员工创建模板文件并包含BeanEditForm组件。 该组件具有以下属性 -

  • object - 包括来源。

  • reorder - 定义要渲染的字段的顺序。

  • submitlabel - 表单提交按钮的消息

完整的编码如下 -

<html t:type = "simplelayout" title = "Create New Address" 
   xmlns:t = "http://tapestry.apache.org/schema/tapestry_5_4.xsd">  
   <t:beaneditform  
      object = "employee"  
      submitlabel = "message:submit-label" 
      reorder = "userName,password,firstName,lastName,
      dateOfBirth,gender,email,phone,s treet,city,state,zip" />  
</html> 

创建员工创建类并包括会话,员工属性,列表页面(导航链接)并定义组件的OnSuccess事件(更新数据的位置)。 会话数据使用hibernate会话持久保存到数据库中。

完整的编码如下 -

package com.example.MyFirstApplication.pages.employee;  
import com.example.MyFirstApplication.entities.Employee; 
import com.example.MyFirstApplication.pages.employee.ListEmployee; 
import org.apache.tapestry5.annotations.InjectPage; 
import org.apache.tapestry5.annotations.Property;  
import org.apache.tapestry5.hibernate.annotations.CommitAfter; 
import org.apache.tapestry5.ioc.annotations.Inject; 
import org.hibernate.Session;  
public class CreateEmployee { 
   @Property 
   private Employee employee;  
   @Inject 
   private Session session;  
   @InjectPage 
   private ListEmployee listPage;  
   @CommitAfter 
   Object onSuccess() { 
      session.persist(employee);  
      return listPage; 
   } 
}

添加CreateEmployee.properties文件并包含要在表单验证中使用的消息。 完整的代码如下 -

zip-regexp=^\\d{5}(-\\d{4})?$ 
zip-regexp-message = Zip Codes are five or nine digits. Example: 02134 or 901251655. 
submit-label = Create Employee 

员工创建页面和列表页面的屏幕截图如下所示 -

员工创造

创作页面

Apache Tapestry - Storage

每个Web应用程序都应该有一些方法来存储某些用户数据,如用户对象,用户首选项等。例如,在购物车应用程序中,用户选择的项目/产品应保存在临时存储桶(购物车)中,直到用户更喜欢购买产品。 我们可以将项目保存在数据库中,但由于所有用户都不打算购买所选项目,因此会过于昂贵。 因此,我们需要临时安排来存储/保留项目。 Apache Tapestry提供了两种持久化数据的方法 - 它们是 -

  • 持久性页面数据
  • 会话存储

两者都有自己的优点和局限。 我们将在以下部分进行检查。

持久性页面数据

持久性页面数据是一种简单的概念,用于在请求之间的单个页面中保存数据,它也称为Page Level Persistence 。 可以使用@Persist注释完成。

@Persist 
public int age; 

一旦使用@Persist对字段进行注释,字段的值将在请求中保持不变,如果在请求期间更改了值,则在下次访问时将反映该字段。 Apache Tapestry提供了五种类型的策略来实现@Persist概念。 它们如下 -

  • Session Strategy - 使用会话持久保存数据,这是一种默认策略。

  • Flash Strategy - 数据也使用Session持久化,但它是一个非常短暂的数据。 数据仅在一个后续请求中可用。

@Persist(PersistenceConstants.FLASH) 
private int age;
  • Client Strategy - 数据在客户端持久化,例如URL查询字符串,表单中的隐藏字段等。

@Persist(PersistenceConstants.FLASH) 
private int age; 
  • Hibernate Entity Strategy - 使用Hibernate模块作为Entity持久保存数据。 该实体将存储在Hibernate中,其引用(Java类名及其主键)将作为令牌保存在HttpSession 。 将使用HttpSession中可用的令牌恢复该实体。

@Persist(HibernatePersistenceConstants.ENTITY) 
private Category category;
  • JPA Entity Strategy - 使用JPA模块持久保存数据。 它只能存储实体。

@Persist(JpaPersistenceConstants.ENTITY) 
private User user; 

会话存储

会话存储是一种高级概念,用于存储需要跨页面的数据,如多页向导中的数据,登录的用户详细信息等。会话存储提供两个选项,一个用于存储复杂对象,另一个用于存储简单值

  • Session Store Object - 用于存储复杂对象。

  • Session Attributes - 用于存储简单值。

Session Store Object (SSO)

可以使用@SessionStore注释创建SSO。 SSO将使用对象的类型存储对象。 例如, Cart Object将使用Cart类名作为标记存储。 因此,任何复杂对象都可以在应用程序中存储一次(每个用户一个)。

public class MySSOPage { 
   @SessionState 
   private ShoppingCart cart; 
}

SSO是一个专门的商店,应该只用于存储复杂/特殊对象。 也可以使用SSO存储简单数据类型,但是存储像String这样的简单数据类型使得它只在应用程序中存储一个“String”值。 在应用程序中使用单个“String”值根本不可能。 您可以使用简单的数据类型,因为Apache Tapestry提供了会话属性。

会话属性

会话属性使数据能够按名称而不是其类型存储。

public class MyPage { 
   @SessionAttribute  
   private String loggedInUsername; 
}

默认情况下,会话属性使用字段名称来引用会话中的数据。 我们可以通过注释参数更改引用名称,如下所示 -

public class MyPage { 
   @SessionAttribute("loggedInUserName") 
   private String userName; 
}

使用name作为会话引用的主要问题之一是我们可能会在多个类/页面中意外使用相同的名称。 在这种情况下,存储的数据可能会意外更改。 要解决此问题,最好使用名称以及类/页面名称和包名称,如com.myapp.pages.register.email ,其中com.myapp.pages是包名称,register是页面/类名称,最后电子邮件是变量(待存储)名称。

Apache Tapestry - Advanced Features

在本章中,我们将详细讨论Apache Tapestry的一些高级功能。

控制反转

Tapestry提供内置的Inversion of Control库。 Tapestry与IoC深度集成,并使用IoC实现其所有功能。 Tapestry IoC配置基于Java本身而不是像许多其他IoC容器一样基于XML。 基于Tapestry IoC的模块打包到JAR文件中,只是在没有配置的情况下放入类路径中。 Tapestry IoC的使用基于轻盈,这意味着 -

  • 两个或三个方法的小接口。

  • 带有两个或三个参数的小方法。

  • 通过事件进行匿名通信,而不是显式方法调用。

单元 (Modules)

模块是一种扩展Tapestry应用程序功能的方法。 Tapestry具有内置模块和大量第三方模块。 Hibernate是Tapestry提供的热门且非常有用的模块之一。 它还有集成JMX,JPA,Spring Framework,JSR 303 Bean Validation,JSON等的模块。一些着名的第三方模块是 -

  • Tapestry-Cayenne
  • Tapestry5-googleanalytics
  • 挂毯5 - Tapestry5-HighCharts
  • 挂毯5 - Tapestry5-jqPlot
  • 挂毯5 - Tapestry5-Jquery
  • 挂毯5 - Tapestry5-Jquery-mobile
  • 挂毯5 - Tapestry5-Portlet

运行时异常

挂毯的最佳功能之一是Detailed Error Reporting 。 Tapestry通过提供最先进的异常报告来帮助开发人员。 Tapestry异常报告是带有详细信息的简单HTML。 任何人都可以轻松理解报告。 Tapestry显示HTML中的错误,并将异常保存在发生异常的日期和时间的纯文本中。 这将有助于开发人员检查生产环境中的异常。 开发人员可以自信地修复任何问题,例如损坏的模板,意外的空值,无法匹配的请求等,

直播课和模板重新加载

Tapestry将在修改后自动重新加载模板和类。 此功能可以立即反映应用程序更改,而无需经过构建和测试周期。 此外,此功能大大提高了应用程序开发的生产率。

考虑应用程序的根包是org.example.myfirstapp 。 然后,扫描以下路径中的类以进行重新加载。

  • org.example.myfirstapp.pages
  • org.example.myfirstapp.components
  • org.example.myfirstapp.mixins
  • org.example.myfirstapp.base
  • org.example.myfirstapp.services

可以通过在AppModule.java生产模式设置为true来禁用实时类重新加载。

configuration.add(SymbolicConstants.PRODUCTION_MODE,”false”);

单元测试 (Unit Testing)

单元测试是一种测试单个页面和组件的技术。 Tapestry为单元测试页面和组件提供了简便的选项。

单元测试页面:Tapestry提供了一个类PageTester来测试应用程序。 它充当浏览器和servlet容器。 它在服务器端本身呈现没有浏览器的页面,并且可以检查生成的文档以获得正确的呈现。 考虑一个简单的页面Hello ,它呈现hello,hello文本包含在一个id为hello_id的html元素中。 要测试此功能,我们可以使用PageTester,如下所示 -

public class PageTest extends Assert { 
   @Test 
   public void test1() { 
      Sring appPackage = "org.example.myfirstapp"; // package name 
      String appName = "App1"; // app name 
      PageTester tester = new PageTester(appPackage, appName, "src/main/webapp"); 
      Document doc = tester.renderPage("Hello"); 
      assertEquals(doc.getElementById("hello_id").getChildText(), "hello"); 
   } 
}

除了呈现页面之外,PageTester还提供包括上下文信息,表单提交,链接导航等的选项。

综合测试

集成测试有助于将应用程序作为模块进行测试,而不是像单元测试那样检查单个页面。 在集成测试中,可以将多个模块作为一个单元一起进行测试。 Tapestry提供了一个名为Tapestry Test Utilities的小型库来进行集成测试。 该库与Selenium测试工具集成以执行测试。 该库提供了一个基类SeleniumTestCase ,它启动和管理Selenium服务器,Selenium客户端和Jetty实例。

集成测试的一个例子如下 -

import org.apache.tapestry5.test.SeleniumTestCase; 
import org.testng.annotations.Test;  
public class IntegrationTest extends SeleniumTestCase { 
   @Test 
   public void persist_entities() {  
      open("/persistitem"); 
      assertEquals(getText("//span[@id='name']").length(), 0); 
      clickAndWait("link = create item"); 
      assertText("//span[@id = 'name']", "name"); 
   } 
}

开发仪表板

开发仪表板是默认页面,用于识别/解决应用程序中的问题。 可以通过URL http://localhost:8080/myfirstapp/core/t5dashboard访问仪表板。 仪表板显示应用程序中可用的所有页面,服务和组件库。

响应压缩

Tapestry使用GZIP compression自动压缩响应并将其流式传输到客户端。 此功能将减少网络流量并有助于更快地传送页面。 可以使用AppModule.java中的符号tapestry.min-gzip-size配置压缩。 默认值为100个字节。 一旦响应的大小超过100个字节,Tapestry将压缩响应。

安全 (Security)

Tapestry提供了许多选项来保护应用程序免受Web应用程序中已知的安全漏洞的影响。 下面列出了其中一些选项 -

  • HTTPS - Tapestry页面可以使用@Secure进行注释,使其成为安全页面,并且只能通过https protocol访问。

  • Page access control - 仅控制某个用户访问的页面。

  • White-Listed Page @WhitelistAccessOnly White-Listed Page - Tapestry页面可以使用@WhitelistAccessOnly进行注释,以使其只能通过localhost访问。

  • Asset Security - 在挂毯下,只能访问某些类型的文件。 只有在提供文件的MD5 hash时才能访问其他文件。

  • Serialized Object Date - Tapestry将HMAC集成到序列化Java对象数据中,并将其发送到客户端以避免消息篡改。

  • Cross Site Request Forgery - Tapestry提供了一个名为tapestry-csrf-protection的第三方模块,以防止任何CSRF攻击。

  • Security Framework integration - Tapestry不会锁定到单个身份验证/授权实现中。 Tapestry可以与任何流行的身份验证框架集成。

日志记录 (Logging)

Tapestry为日志记录提供了广泛的支持,可以在应用程序运行时自动记录应用程序的进度。 Tapestry使用事实上的Java日志库SLF4J 。 注释@Log可以在任何组件方法中发出方法的入口和出口以及可能的异常。 此外,Tapestry提供的记录器对象可以使用@Inject注释注入任何组件,如下所示 -

public class MyPage { 
   @Inject 
   private Logger logger; 
   // . . . 
   void onSuccessFromForm() { 
      logger.info("Changes saved successfully"); 
   } 
   @Log 
   void onValidateFromForm() { 
      // logic 
   } 
}

最后,我们现在可以说Apache Tapestry带来了构建简洁,可扩展,可维护,强大且支持Ajax的应用程序的最佳方法。 Tapestry可以与任何第三方Java应用程序集成。 它还可以帮助创建大型Web应用程序,因为它非常简单快速。

↑回到顶部↑
WIKI教程 @2018