Tapestry 登录应用
你在Pig latin翻译器应用中看到了Tapestry的一些基本特性。与其用一个复杂的应用展示Tapestry所有的特性以致于压得你揣不过气来,还不如通过一些简单的应用让你找到一点对Tapestry的感觉。下面这个应用展示Tapestry如何处理页面导航,区域化,验证和其他一些特性。
这里有一个Home页的屏幕抓图,下面跟着它的页面模板。
Home.html
<html>
<head>
<title>Welcome to the Tapestry Login Application</title>
</head>
<body>
<h1>Welcome to the Tapestry Login Application</h1>
<span jwcid="@PageLink"① page="Login">Login</span>
</body>
</html>
这个Home页的页面模板除了一个jwcid属性定义使用一个Tapestry PageLink①控件以外都是标准的HTML。
PageLink控件生成了一个指向Login页的超链接。既然Home页没有任何动态的行为所以它不需要页面规范和页面对应的Java类。
这里是Login页的屏幕抓图,后面跟着是它的页面模板。
Login.html
<html>
<head>
<title>
<span key="title">①Login</span>
</title>
</head>
<body jwcid="@Body">②
<span jwcid="@Conditional" condition="ognl:beans.delegate.hasErrors">③
<div style="color: red">
<span jwcid="@Delegator" delegate="ognl:beans.delegate.firstError">④
Error Message
</span>
</div>
</span>
<p style="font-weight: bold" >
<span key="hint">Hint: Your password is your username spelled backwards.</span>
</p>
<form jwcid="@Form" listener="ognl:listeners.login" delegate="ognl:beans.delegate">
⑤
<table>
<tr>
<td align="right">
<span jwcid="@FieldLabel" field="ognl:components.inputUsername"⑥>
Username:
</span>
</td>
<td>
<input type="text" jwcid="inputUsername"⑦ value="simpson_h"
size="30"/>
</td>
</tr>
<tr>
<td align="right">
<span jwcid="@FieldLabel" field="ognl:components.inputPassword">
Password:
</span>
</td>
<td>
<input type="text" jwcid="inputPassword" hidden="true" value=""
size="30"/>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" jwcid="@Submit" value="message:login"/>
</td>
</tr>
</table>
</form>
</body>
</html>
这个页面模板大多数是通常的HTML。我们从页面模板中可以看到Tapestry的区域化特性:它使用一个span元素,这个span元素带有一个叫key的属性,key的值映射到Login.properties文件里一个属性。一个Body控件被声明使用,因为它对客户端的JavaScript校验是必需的。
为Form component⑤设定delegate属性激活表单输入验证。delegate属性是我们在页面规范里声明的org.apache.tapestry.valid.IvalidationDelegate的实现类。如果验证错误发生了,我们用Conditional component③控件判断delegate是否有任何错误,如果有就把第一个错误④显示给用户。如果ognl 表达式ognl:beans.delegate.hasErrors 为true,Conditional控件将显示它的内容实体。所有的页面类和控件类都从AbstractComponent继承来一个叫beans的属性。这个beans属性是一个org.apache.tapestry.IbeanProvider的实例,利用它可以通过名字取得在页面规范文件里定义的beans.FieldLabel⑥被用于为inputuserName validField控件显示标签,这个FieldLabel控件也被用来与表单的验证代理协作,指出包含错误的输入域。
InputUserName⑦控件是一个显示控件的例子。显式控件是指在页面规范文件声明的控件。InputUsername和inputPassword控件都是显式的,它们与FieldLabel联合显示它们的displayName属性。
下面的是Login页的资源文件。Login.properties跟页面规范一并存放在WEB-INF目录。
Login.properties
title = Login to the Application
hint = Hint: Your password is your username spelled backwards.
login = Login
username = Username:
password = Password:
invalidpassword = Invalid Password
Here is the page specification for the Login page.
Login.page
<?xml version="1.0"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
" http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>;
<page-specification class="com.ociweb.tapestry.Login">
<bean name="delegate" class="org.apache.tapestry.valid.ValidationDelegate"/>①
<bean name="requiredValidator"②
class="org.apache.tapestry.valid.StringValidator">
<set-property name="required" expression="true"/>
<set-property name="clientScriptingEnabled" expression="true"/>
</bean>
<property-specification name="username" type="java.lang.String"/>
<property-specification name="password" type="java.lang.String"/>
<component id="inputUsername" type="ValidField"> ③
<message-binding name="displayName" key="username"/> ④
<binding name="validator" expression="beans.requiredValidator"/> ⑤
<binding name="value" expression="username"/> ⑥
</component>
<component id="inputPassword" type="ValidField"> ⑦
<message-binding name="displayName" key="password"/>
<binding name="validator" expression="beans.requiredValidator"/>
<binding name="value" expression="password"/>
</component>
</page-specification>
Page-specification元素的class属性和两个property-specification元素与Pig Latin翻译器应用是相似的。
你会发现第一个新东西-bean元素①,bean元素把一个org.apache.tapestry.valid.ValidationDelegate
的实例指定了名称"delegate"。页面HTML模板里的Form控件把它的参数delegate设定为
ognl:beans.delegate,就是指向了这个org.apache.tapestry.valid.ValidationDelegate实例。
Bean元素②把一个org.apache.tapestry.valid.StringValidator的实例指定了名称"
requiredValidator",以用于验证。这个bean的required属性被设为true表明使用这个bean的域是必须被验证的。这个bean的clientScriptingEnabled属性被设定为ture,表明使用这个bean的域客户端的JavaScript验证功能是激活的。RequiredValidator bean被用于验证inputUsername和inputPassword的内容。
控件inputUsername③被控件规范声明为ValidField,ValidField是一种用于Tapestry验证子系统的特殊版本的TextField控件。Message-binding元素被用于指定inputUsername控件的displayName参数的值,这个值是用"username"为关键字从login.properties④文件里得到。InputUsername控件的validator参数被设定为requiredValidator bean,这是我们在页面规范里声明过的⑤。控件的value参数跟页面Java类的username属性绑定在一起⑥。控件inputPassword的控件规范跟控件inputUsername几乎相似,除了用于取得displayName的关键字和绑定的页面Java类的属性不同。
通过使用ValidField控件和为表单(form)提供一个ValidationDelegate, 我们激活了Login表单的验证功能。除了服务器端的验证,Tapestry也提供了客户端的验证(利用JavaScript)。下面就是当用户提交一个表单而没有为UserName域提供值时,一个JavaScript错误对话框弹出时的屏幕抓图。
下面就是当用户提交一个表单而没有为Password域提供值时,一个JavaScript错误对话框弹出时的屏幕抓图。
下面就是Login页对应的Java 类。
Login.java
package com.ociweb.tapestry;
import org.apache.tapestry.html.BasePage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.valid.ValidationConstraint;
import org.apache.tapestry.valid.IValidationDelegate;
public abstract class Login extends BasePage {
public abstract String getUsername();
public abstract void setUsername(String username);
public abstract String getPassword();
public abstract void setPassword(String password);
public void login(IRequestCycle cycle) {
String username = getUsername();
String password = getPassword();
StringBuffer sb = new StringBuffer(username);
String validPassword = sb.reverse().toString();
if (password.equals(validPassword)) {
cycle.activate("Success");①
} else {
String errorMessage = getMessage("invalidpassword");②
IValidationDelegate validationDelegate =
(IValidationDelegate) getBeans().getBean("delegate");③
validationDelegate.record(errorMessage,
ValidationConstraint.CONSISTENCY);④
}
}
}
跟Pig Latin翻译器应用一样,我们的页面类也是抽象的,它有抽象方法访问在页面规范里定义的属性(properties)。Tapestry会在运行时刻创建username和password属性。Login方法只是简单的验证一下用户输入的密码值是否刚好是用户名的反向。如果密码通过验证,用户将被引领导Success page①。
如果密码输入有误,我们用关键字"invalidPassword"通过从org.apache.tapestry.AbstractComponent里继承来的getMessage()方法从Login.properties②里查找对应的资源。我们需要把密码错误信息纪录到我们在页面规范中定义的页面validation delegate中去。我们可以利用我们在页面规范中指定的名称,从页面的beans属性中找回validationDelegate③。最后,我们调用org.apache.tapestry.valid.IvalidationDelegate的record方法把将要显示给用户看的错误信息保存起来。下面就是当用户输入错误密码的提交后的屏幕抓图。
下面就是Success页的页面模板。Success页的页面模板仅仅包含HTML标识,所以它不需要页面规范和页面
Java类。
Success.html
<html>
<head>
<title>Successful Login</title>
</head>
<body>
<p>
Congratulations! You have successfully logged on.
</p>
</body>
</html>
总结
我希望这篇文章已经向你展示了Tapestry框架在构建Web应用的是多么简单,然而优雅。Tapestry与大多数主流Web应用框架最大不同在于它让你用基于控件的方式开发,而非以操作为中心的方式开发。如果这篇文章激起了你的兴趣,我建议你把它下载下来利用它你自己的简单的Web应用。通过感受简单的应用,这是你了解这个框架的优点的唯一途径。如果你想在你的下一个项目里使用Tapestry,我强烈建议你购买
Tapestry In Action 这本书。我拥有这本书,对它我感到很满意。
References
1 Zip file with all source code and war files from the article. (12K)
http://www.ociweb.com/jnb/jnb2004_05.zip
2 Tapestry Home Page http://jakarta.apache.org/tapestry/
3 Tapestry In Action Page http://www.manning.com/lewisship/
4 Tapestry Wiki http://jakarta.apache.org/tapestry/wiki_frame.html
5 OGNL page http://www.ognl.org/
6 Tapestry Component Reference
http://jakarta.apache.org/tapestry/doc/ComponentReference/index.html
7 Tapestry Component Workbench http://www.t-deli.com/app
8 Designing Tapestry Mega-Components
http://www.onjava.com/pub/a/onjava/2001/11/21/tapestry.html
你在Pig latin翻译器应用中看到了Tapestry的一些基本特性。与其用一个复杂的应用展示Tapestry所有的特性以致于压得你揣不过气来,还不如通过一些简单的应用让你找到一点对Tapestry的感觉。下面这个应用展示Tapestry如何处理页面导航,区域化,验证和其他一些特性。
这里有一个Home页的屏幕抓图,下面跟着它的页面模板。
Home.html
<html>
<head>
<title>Welcome to the Tapestry Login Application</title>
</head>
<body>
<h1>Welcome to the Tapestry Login Application</h1>
<span jwcid="@PageLink"① page="Login">Login</span>
</body>
</html>
这个Home页的页面模板除了一个jwcid属性定义使用一个Tapestry PageLink①控件以外都是标准的HTML。
PageLink控件生成了一个指向Login页的超链接。既然Home页没有任何动态的行为所以它不需要页面规范和页面对应的Java类。
这里是Login页的屏幕抓图,后面跟着是它的页面模板。
Login.html
<html>
<head>
<title>
<span key="title">①Login</span>
</title>
</head>
<body jwcid="@Body">②
<span jwcid="@Conditional" condition="ognl:beans.delegate.hasErrors">③
<div style="color: red">
<span jwcid="@Delegator" delegate="ognl:beans.delegate.firstError">④
Error Message
</span>
</div>
</span>
<p style="font-weight: bold" >
<span key="hint">Hint: Your password is your username spelled backwards.</span>
</p>
<form jwcid="@Form" listener="ognl:listeners.login" delegate="ognl:beans.delegate">
⑤
<table>
<tr>
<td align="right">
<span jwcid="@FieldLabel" field="ognl:components.inputUsername"⑥>
Username:
</span>
</td>
<td>
<input type="text" jwcid="inputUsername"⑦ value="simpson_h"
size="30"/>
</td>
</tr>
<tr>
<td align="right">
<span jwcid="@FieldLabel" field="ognl:components.inputPassword">
Password:
</span>
</td>
<td>
<input type="text" jwcid="inputPassword" hidden="true" value=""
size="30"/>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" jwcid="@Submit" value="message:login"/>
</td>
</tr>
</table>
</form>
</body>
</html>
这个页面模板大多数是通常的HTML。我们从页面模板中可以看到Tapestry的区域化特性:它使用一个span元素,这个span元素带有一个叫key的属性,key的值映射到Login.properties文件里一个属性。一个Body控件被声明使用,因为它对客户端的JavaScript校验是必需的。
为Form component⑤设定delegate属性激活表单输入验证。delegate属性是我们在页面规范里声明的org.apache.tapestry.valid.IvalidationDelegate的实现类。如果验证错误发生了,我们用Conditional component③控件判断delegate是否有任何错误,如果有就把第一个错误④显示给用户。如果ognl 表达式ognl:beans.delegate.hasErrors 为true,Conditional控件将显示它的内容实体。所有的页面类和控件类都从AbstractComponent继承来一个叫beans的属性。这个beans属性是一个org.apache.tapestry.IbeanProvider的实例,利用它可以通过名字取得在页面规范文件里定义的beans.FieldLabel⑥被用于为inputuserName validField控件显示标签,这个FieldLabel控件也被用来与表单的验证代理协作,指出包含错误的输入域。
InputUserName⑦控件是一个显示控件的例子。显式控件是指在页面规范文件声明的控件。InputUsername和inputPassword控件都是显式的,它们与FieldLabel联合显示它们的displayName属性。
下面的是Login页的资源文件。Login.properties跟页面规范一并存放在WEB-INF目录。
Login.properties
title = Login to the Application
hint = Hint: Your password is your username spelled backwards.
login = Login
username = Username:
password = Password:
invalidpassword = Invalid Password
Here is the page specification for the Login page.
Login.page
<?xml version="1.0"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
" http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>;
<page-specification class="com.ociweb.tapestry.Login">
<bean name="delegate" class="org.apache.tapestry.valid.ValidationDelegate"/>①
<bean name="requiredValidator"②
class="org.apache.tapestry.valid.StringValidator">
<set-property name="required" expression="true"/>
<set-property name="clientScriptingEnabled" expression="true"/>
</bean>
<property-specification name="username" type="java.lang.String"/>
<property-specification name="password" type="java.lang.String"/>
<component id="inputUsername" type="ValidField"> ③
<message-binding name="displayName" key="username"/> ④
<binding name="validator" expression="beans.requiredValidator"/> ⑤
<binding name="value" expression="username"/> ⑥
</component>
<component id="inputPassword" type="ValidField"> ⑦
<message-binding name="displayName" key="password"/>
<binding name="validator" expression="beans.requiredValidator"/>
<binding name="value" expression="password"/>
</component>
</page-specification>
Page-specification元素的class属性和两个property-specification元素与Pig Latin翻译器应用是相似的。
你会发现第一个新东西-bean元素①,bean元素把一个org.apache.tapestry.valid.ValidationDelegate
的实例指定了名称"delegate"。页面HTML模板里的Form控件把它的参数delegate设定为
ognl:beans.delegate,就是指向了这个org.apache.tapestry.valid.ValidationDelegate实例。
Bean元素②把一个org.apache.tapestry.valid.StringValidator的实例指定了名称"
requiredValidator",以用于验证。这个bean的required属性被设为true表明使用这个bean的域是必须被验证的。这个bean的clientScriptingEnabled属性被设定为ture,表明使用这个bean的域客户端的JavaScript验证功能是激活的。RequiredValidator bean被用于验证inputUsername和inputPassword的内容。
控件inputUsername③被控件规范声明为ValidField,ValidField是一种用于Tapestry验证子系统的特殊版本的TextField控件。Message-binding元素被用于指定inputUsername控件的displayName参数的值,这个值是用"username"为关键字从login.properties④文件里得到。InputUsername控件的validator参数被设定为requiredValidator bean,这是我们在页面规范里声明过的⑤。控件的value参数跟页面Java类的username属性绑定在一起⑥。控件inputPassword的控件规范跟控件inputUsername几乎相似,除了用于取得displayName的关键字和绑定的页面Java类的属性不同。
通过使用ValidField控件和为表单(form)提供一个ValidationDelegate, 我们激活了Login表单的验证功能。除了服务器端的验证,Tapestry也提供了客户端的验证(利用JavaScript)。下面就是当用户提交一个表单而没有为UserName域提供值时,一个JavaScript错误对话框弹出时的屏幕抓图。
下面就是当用户提交一个表单而没有为Password域提供值时,一个JavaScript错误对话框弹出时的屏幕抓图。
下面就是Login页对应的Java 类。
Login.java
package com.ociweb.tapestry;
import org.apache.tapestry.html.BasePage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.valid.ValidationConstraint;
import org.apache.tapestry.valid.IValidationDelegate;
public abstract class Login extends BasePage {
public abstract String getUsername();
public abstract void setUsername(String username);
public abstract String getPassword();
public abstract void setPassword(String password);
public void login(IRequestCycle cycle) {
String username = getUsername();
String password = getPassword();
StringBuffer sb = new StringBuffer(username);
String validPassword = sb.reverse().toString();
if (password.equals(validPassword)) {
cycle.activate("Success");①
} else {
String errorMessage = getMessage("invalidpassword");②
IValidationDelegate validationDelegate =
(IValidationDelegate) getBeans().getBean("delegate");③
validationDelegate.record(errorMessage,
ValidationConstraint.CONSISTENCY);④
}
}
}
跟Pig Latin翻译器应用一样,我们的页面类也是抽象的,它有抽象方法访问在页面规范里定义的属性(properties)。Tapestry会在运行时刻创建username和password属性。Login方法只是简单的验证一下用户输入的密码值是否刚好是用户名的反向。如果密码通过验证,用户将被引领导Success page①。
如果密码输入有误,我们用关键字"invalidPassword"通过从org.apache.tapestry.AbstractComponent里继承来的getMessage()方法从Login.properties②里查找对应的资源。我们需要把密码错误信息纪录到我们在页面规范中定义的页面validation delegate中去。我们可以利用我们在页面规范中指定的名称,从页面的beans属性中找回validationDelegate③。最后,我们调用org.apache.tapestry.valid.IvalidationDelegate的record方法把将要显示给用户看的错误信息保存起来。下面就是当用户输入错误密码的提交后的屏幕抓图。
下面就是Success页的页面模板。Success页的页面模板仅仅包含HTML标识,所以它不需要页面规范和页面
Java类。
Success.html
<html>
<head>
<title>Successful Login</title>
</head>
<body>
<p>
Congratulations! You have successfully logged on.
</p>
</body>
</html>
总结
我希望这篇文章已经向你展示了Tapestry框架在构建Web应用的是多么简单,然而优雅。Tapestry与大多数主流Web应用框架最大不同在于它让你用基于控件的方式开发,而非以操作为中心的方式开发。如果这篇文章激起了你的兴趣,我建议你把它下载下来利用它你自己的简单的Web应用。通过感受简单的应用,这是你了解这个框架的优点的唯一途径。如果你想在你的下一个项目里使用Tapestry,我强烈建议你购买
Tapestry In Action 这本书。我拥有这本书,对它我感到很满意。
References
1 Zip file with all source code and war files from the article. (12K)
http://www.ociweb.com/jnb/jnb2004_05.zip
2 Tapestry Home Page http://jakarta.apache.org/tapestry/
3 Tapestry In Action Page http://www.manning.com/lewisship/
4 Tapestry Wiki http://jakarta.apache.org/tapestry/wiki_frame.html
5 OGNL page http://www.ognl.org/
6 Tapestry Component Reference
http://jakarta.apache.org/tapestry/doc/ComponentReference/index.html
7 Tapestry Component Workbench http://www.t-deli.com/app
8 Designing Tapestry Mega-Components
http://www.onjava.com/pub/a/onjava/2001/11/21/tapestry.html