Apache Tapestry 简介
1.概述
如今,从社交网络到银行业务,从医疗保健到政府服务,所有活动都可以在线进行。因此,他们严重依赖 Web 应用程序。
Web 应用程序使用户能够消费/享受公司提供的在线服务。同时,它充当后端软件的接口。
在这个介绍性教程中,我们将探索 Apache Tapestry Web 框架并使用它提供的基本功能创建一个简单的 Web 应用程序。
2. Apache Tapestry
Apache Tapestry 是一个基于组件的框架,用于构建可扩展的 Web 应用程序。
它遵循约定优于配置的范式,并使用注释和命名约定进行配置。
所有组件都是简单的 POJO。同时,它们是从零开始开发的,不依赖于其他库。
除了 Ajax 支持之外,Tapestry 还具有出色的异常报告功能。它还提供了一个广泛的内置通用组件库。
在其他重要功能中,一个突出的特点是代码的热重载。因此,使用此功能,我们可以立即看到开发环境中的变化。
3. 设置
Apache Tapestry 需要一组简单的工具来创建 Web 应用程序:
- Java 1.6 或更高版本
- 构建工具(Maven 或 Gradle)
- IDE(Eclipse 或 IntelliJ)
- 应用服务器(Tomcat 或 Jetty)
在本教程中,我们将结合使用 Java 8、Maven、Eclipse 和 Jetty Server。
要设置最新 的Apache Tapestry 项目,我们将使用Maven 原型 并按照官方文档提供的说明 进行操作:
$ mvn archetype:generate -DarchetypeCatalog=http://tapestry.apache.org
或者,如果我们有一个现有项目,我们可以简单地将Tapestry-core Maven 依赖项添加到pom.xml:
<dependency>
<groupId>org.apache.tapestry</groupId>
<artifactId>tapestry-core</artifactId>
<version>5.4.5</version>
</dependency>
一旦我们准备好设置,我们可以通过以下 Maven 命令启动应用程序apache-tapestry :
$ mvn jetty:run
默认情况下,可以通过localhost:8080/apache-tapestry 访问该应用程序:
4. 项目结构
让我们探索一下 Apache Tapestry 创建的项目布局:
我们可以看到一个类似 Maven 的项目结构,以及一些基于约定的包。
Java 类被放置在src/main/java并被分类为components、pages和services 。
同样,src/main/resources包含我们的模板(类似于 HTML 文件)——它们具有*.tml*扩展名。
对于放置在components和pages目录下的每个 Java 类,都应该创建一个同名的模板文件。
src/main/webapp目录包含图像、样式表和 JavaScript 文件等资源。同样,测试文件放在src/test中。
最后,src/site将包含文档文件。
为了更好的理解,我们来看看在 Eclipse IDE 中打开的项目结构:
5. 注释
让我们讨论Apache Tapestry 为日常使用提供的一些方便的注释 。展望未来,我们将在我们的实现中使用这些注释。
5.1.@Inject
@Inject 注解在org.apache.tapestry5.ioc.annotations包中可用,它提供了一种在 Java 类中注入依赖项的简单方法。
这个注解对于注入资产、块、资源和服务非常方便。
5.2. @InjectPage
在org.apache.tapestry5.annotations包中可用,@InjectPage 注释允许我们将页面注入另一个组件。此外,注入的页面始终是只读属性。
5.3. @InjectComponent
类似地,@InjectComponent 注解允许我们注入模板中定义的组件。
5.4. @Log
@Log 注释在org.apache.tapestry5.annotations包中可用,并且可以方便地在任何方法上启用 DEBUG 级别的日志记录。它记录方法的进入和退出,以及参数值。
5.5. @Property
在org.apache.tapestry5.annotations包中可用, @Property 注释将字段标记为属性。同时,它会自动为属性创建 getter 和 setter。
5.6. @Parameter
类似地,*@Parameter *注解表示一个字段是一个组件参数。
6. 页面
因此,我们都准备好探索框架的基本功能。让我们在我们的应用程序中创建一个新的Home。
首先,我们将在src/main/java的pages目录中定义一个 Java 类Home:
public class Home {
}
6.1.模板
然后,我们将在src/main/resources下的pages目录中创建一个对应的Home.tml模板 。
扩展名为*.tml*(Tapestry 标记语言)的文件类似于 Apache Tapestry 提供的具有 XML 标记的 HTML/XHTML 文件。
例如,让我们看一下Home.tml模板:
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<head>
<title>apache-tapestry Home</title>
</head>
<body>
<h1>Home</h1>
</body>
</html>
瞧!只需重启 Jetty 服务器,我们就可以在localhost:8080/apache-tapestry/home访问主页:
6.2. 属性
让我们探索如何在Home上呈现属性。
为此,我们将在Home类中添加一个属性和一个 getter 方法:
@Property
private String appName = "apache-tapestry";
public Date getCurrentTime() {
return new Date();
}
要在主页上呈现appName属性,我们可以简单地使用*${appName}*。
同样,我们可以编写*${currentTime}从页面访问getCurrentTime*方法。
6.3. 本土化
Apache Tapestry 提供集成的本地化 支持。按照惯例,页面名称属性文件保存要在页面上呈现的所有本地消息的列表。
例如,我们将在主页的pages目录中创建一个带有本地消息的home.properties文件:
introMsg=Welcome to the Apache Tapestry Tutorial
消息属性不同于 Java 属性。
出于同样的原因,带有消息前缀的键名用于呈现消息属性——例如,${message:introMsg}。
6.4. 布局组件
让我们通过创建Layout.java类来定义一个基本的布局组件。我们将文件保存在src/main/java的components目录中:
public class Layout {
@Property
@Parameter(required = true, defaultPrefix = BindingConstants.LITERAL)
private String title;
}
在这里,title属性被标记为必需,并且绑定的默认前缀设置为文字String。
然后,我们会在src/main/resources的components目录下编写一个对应的模板文件Layout.tml:
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<head>
<title>${title}</title>
</head>
<body>
<div class="container">
<t:body />
<hr/>
<footer>
<p>© Your Company</p>
</footer>
</div>
</body>
</html>
现在,让我们使用主页上的layout:
<html t:type="layout" title="apache-tapestry Home"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd">
<h1>Home! ${appName}</h1>
<h2>${message:introMsg}</h2>
<h3>${currentTime}</h3>
</html>
请注意,命名空间 用于标识Apache Tapestry 提供的元素( t:type和t:body )。同时,命名空间还提供了组件和属性。
在这里,t:type将设置主页上的layout。并且,t:body元素将插入页面的内容。
让我们看一下带有布局的主页:
7. 表格
让我们创建一个带有表单的登录页面,以允许用户登录。
如前所述,我们将首先创建一个 Java 类Login:
public class Login {
// ...
@InjectComponent
private Form login;
@Property
private String email;
@Property
private String password;
}
在这里,我们定义了两个属性—— email和password。此外,我们还为登录注入了一个Form组件。
然后,让我们创建一个对应的模板login.tml:
<html t:type="layout" title="apache-tapestry com.example"
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"
xmlns:p="tapestry:parameter">
<t:form t:id="login">
<h2>Please sign in</h2>
<t:textfield t:id="email" placeholder="Email address"/>
<t:passwordfield t:id="password" placeholder="Password"/>
<t:submit class="btn btn-large btn-primary" value="Sign in"/>
</t:form>
</html>
现在,我们可以在localhost:8080/apache-tapestry/login 访问登录页面:
8. 验证
Apache Tapestry 提供了一些用于表单验证 的内置方法。它还提供了处理表单提交成功或失败的方法。
内置方法遵循事件和组件名称的约定。例如,方法onValidationFromLogin将验证Login组件。
同样,像onSuccessFromLogin和onFailureFromLogin这样的方法分别用于成功和失败事件。
因此,让我们将这些内置方法添加到Login类中:
public class Login {
// ...
void onValidateFromLogin() {
if (email == null)
System.out.println("Email is null);
if (password == null)
System.out.println("Password is null);
}
Object onSuccessFromLogin() {
System.out.println("Welcome! Login Successful");
return Home.class;
}
void onFailureFromLogin() {
System.out.println("Please try again with correct credentials");
}
}
9. 警报
如果没有适当的警报,表单验证是不完整的。更不用说,该框架还内置了对警报消息的支持。
为此,我们将首先在Login类中注入AlertManager 的实例来管理警报。然后,将现有方法中的println语句替换为警告消息:
public class Login {
// ...
@Inject
private AlertManager alertManager;
void onValidateFromLogin() {
if(email == null || password == null) {
alertManager.error("Email/Password is null");
login.recordError("Validation failed"); //submission failure on the form
}
}
Object onSuccessFromLogin() {
alertManager.success("Welcome! Login Successful");
return Home.class;
}
void onFailureFromLogin() {
alertManager.error("Please try again with correct credentials");
}
}
让我们看看登录失败时的警报:
10. Ajax
到目前为止,我们已经探索了使用表单创建一个简单的主页。同时,我们看到了对警报消息的验证和支持。
接下来,让我们探索一下 Apache Tapestry 对 Ajax 的内置支持。
首先,我们将在Home类中注入AjaxResponseRenderer 和Block 组件的实例。然后,我们将创建一个onCallAjax方法来处理 Ajax 调用:
public class Home {
// ....
@Inject
private AjaxResponseRenderer ajaxResponseRenderer;
@Inject
private Block ajaxBlock;
@Log
void onCallAjax() {
ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock);
}
}
此外,我们需要在Home.tml中进行一些更改。
首先,我们将添加eventLink 以调用onCallAjax方法。然后,我们将添加一个id 为ajaxZone的zone 元素来呈现 Ajax 响应。
最后,我们需要一个块组件,该组件将被注入Home类并呈现为 Ajax 响应:
<p><t:eventlink event="callAjax" zone="ajaxZone" class="btn btn-default">Call Ajax</t:eventlink></p>
<t:zone t:id="ajaxZone"></t:zone>
<t:block t:id="ajaxBlock">
<hr/>
<h2>Rendered through Ajax</h2>
<p>The current time is: <strong>${currentTime}</strong></p>
</t:block>
我们来看看更新后的主页:
然后,我们可以单击 Call Ajax 按钮并查看ajaxResponseRenderer的运行情况:
11. 日志
要启用内置的日志记录功能,需要注入Logger 的实例。然后,我们可以使用它来记录任何级别的日志,例如 TRACE、DEBUG 和 INFO。
因此,让我们在Home类中进行必要的更改:
public class Home {
// ...
@Inject
private Logger logger;
void onCallAjax() {
logger.info("Ajax call");
ajaxResponseRenderer.addRender("ajaxZone", ajaxBlock);
}
}
现在,当我们单击 Call Ajax 按钮时,Logger将在 INFO 级别记录:
[INFO] pages.Home Ajax call