q里有这个页面屏q抓图:
面模板由标准的HTML标签和一些额外的属性和标签构成Q这些额外的属性和标签是ؓ了告诉Tapestry框架q个面的那些部分是由Tapestry控gl成。页面模板存攑֜Web应用的根context目录下。通常QTapestry在启动时会寻扑֒呈现一个名?Home"的页。虽然我们可以改变这U行为,但依照Tapestry的惯例会更简单?br />
Home.html
<html>
<head>
<title>Tapestry Pig Latin Translator</title>
</head>
<body>
<h1>Pig Latin Translator</h1>
<form jwcid="@Form"?listener="ognl:listeners.submit"?gt;
<table border="1">
<tr>
<td>Value to Translate:</td>
<td>
<input type="text" jwcid="@TextField"?value="ognl:inputValue"/>
</td>
</tr>
<tr>
<td>Pig Latin:</td>
<td>
<jwcid="@Insert"?value="ognl:pigLatinValue"/>
</td>
</tr>
</table>
<input type="submit" jwcid="@Submit"?value="Translate"/>
</form>
</body>
</html>
面模板的绝大部分是普通的HTML,只有部分TapestryҎ的属性和标签。这U模板机制的优势是Tapestry面模板可以在一个可见即所得的~辑器里创徏和预览。描qTapestry控g部分的标识是有限的和H出的?br />
标识里的jwcid所指是被应用的Tapestry控g的Java Web Component ID.在上面代码断里,我们是隐式地使用控g。隐式的控g是指直接在页面模杉K声明使用的控Ӟ。jwcid的前~ '@ 'W号是通知Tapestryq里声明使用了一个隐式控件?br />
在上面的Pig Latin Translator面模板里用了四个控ӞForm? TextField? Insert?和Submit⑤。它们只是Tapestry框架提供的包含超q?0个控件的控g库里的四个。在后面的范例中Q我们将会看到如何用显式控件。显式控件是指控件在面规范文g里声明后再用的控g?br />
在前面的HTML模板里,使用控g的同Ӟ也ؓ控g指定了参数。例如控件Form①有一个listener②参数它指定了当表单提交时对应的面c调用的Ҏ名称。那个ognl:前缀的用诏IK面的HTML模板Q指向的?a >Object Graph Navigation Language (OGNL)。OGNL是一个强大的开源的表达式语aQ用于将面内控件的属性绑定到面cȝ属性?br />
现在我们看看面规范文g。页面规范文件是一个扩展名为page的XML文gQ这个文件有许多职责Q在众多职责中最基本是指定页面对应的JavacR页面规范文件存攑֜webapp的WEB_INF目录?br />
Home.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="Home">
<property-specification name="inputValue" type="java.lang.String"/>
<property-specification name="pigLatinValue" type="java.lang.String"/>
</page-specification>
面规范文g的根元素有一个class的属性,它指定了q个对应的JavacR这个类必须要实现org.apache.tapestry.Ipage接口。页面规范同旉定义了两个属?property)元素Q以便Tapestry在页面类里创建新的属性?br />
Tapestry框架提供了org.apache.tapestry.html.BasePage class,它实CIpage接口。页面类被存攑֜Web-INF/classes目录下,跟你的Web应用的所需要的其他cL在一赗?br />
Home.java
import org.apache.tapestry.html.BasePage;
import org.apache.tapestry.IRequestCycle;
public abstract class Home extends BasePage {
public abstract String getInputValue();
public abstract void setInputValue(String inputValue);
public abstract String getPigLatinValue();
public abstract void setPigLatinValue(String pigLatinValue);
public void submit(IRequestCycle cycle) {
String inputValue = getInputValue();
String pigLatinValue = new PigLatinTranslator().translate(inputValue);
setPigLatinValue(pigLatinValue);
}
}
你要提醒的第一件事或许是这个类Z么是抽象cR它q有几个抽象Ҏ讉KinputValueQpigLatinValue属性。这里利用了Tapestry会在q行时刻创徏子类的功能,q个子类会创Z在页面规范里声明的属性和生成相应的访问方法?br />
在表单提交时面cȝsubmitҎ会被调用。ؓ什么会q样Q因为我们在面模板里将Form控g的listener属性指定ؓQognl:listeners.submit。这意味着一个名叫submit的listener会通过面cȝlisteners被访问?br />
所有的面cd控gc都从org.apache.tapestry.AbstractComponentq个cȝ承来一个叫listeners的属性。当submitҎ完成后,面会显C译好的词?br />
最后讲讲Web.xmlq个Web发布描述文g。Tapestry,像许多其他的行的Web应用框架一P׃个Servlet构成Q但是还需要一个发布描q文件。那个发布描q文件应该被存放在WEB-INF目录?br />
web.xml
<?xml version="1.0"?>
<!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>Tapestry Pig Latin Translator</display-name>
<servlet>
<servlet-name>tapestry</servlet-name>
<servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>tapestry</servlet-name>
<url-pattern>/app</url-pattern>
</servlet-mapping>
</web-app>
虽然Pig Latin译应用非常单,但是它会让你对在Tapestry应用中一个页面的3个组成部分有了基本的了解。它也展CZ创徏一个Tapestry应用的一个页面只需写多么少的代码?br />
表单输入验证
Tapestry 提供了一些控件以便校验用L输入。校验子pȝ是ValidField控g的核心。在下面的登录应用中我们用ValidField控g。ValidField控g位于表单内,对用户在客户端的校验提供了有用的反馈和视觉上的错误提C?br />
区域?br />
在Tapestry中,区域化是相当单的。Tapestry允许文字和图形的区域化。ؓ了区域化面的内容,你可以ؓ每一个添加一个properties文gQ或者提供一个区域化的模ѝؓ每个面提供一个资源文件的方式q比理和维护一个巨大的全局的应用范围的资源文g单。如果页面的区域化ƈ不仅仅只是文字信息的区域化,例如面的布局不同或者组成的控g不同Q这h冉|供区域化的页面模板就能派上用Z。我们会在下面的d应用的用Tapestry区域化?br />
创徏控g
Tapestry发布时提供了40多个自带的控件。如果你想知道更多的关于Tapestry自带控g的信息,请参?a >Tapestry Component Reference.想看看Tapestry的控件的应用范例可访?a >Tapestry Component Workbench.如果你发C需要一个Tapestry本n没提供的控gQ你可以自己创徏一个。创Z自己的Tapestry控g跟创Z个页面是怼的。一个典型的Tapestry控g׃个控件规范文ӞXML文档Q,一个HTML控g模板Q一个实Corg.apache.tapestry.Icomponent接口的JavacR这个议题有点超出本文的范围Q但是如果你有兴学习如何创Z自己的Tapestry控gQ你可以参考Tapestry的原创hQ?a >Tapestry In Action 一书的作?-Howard Lewis Ship写的 Designing Tapestry Mega-Components ?br />
Tapestry d应用
你在Pig latin译器应用中看到了Tapestry的一些基本特性。与其用一个复杂的应用展示Tapestry所有的Ҏ以致于压得你揣不过气来Q还不如通过一些简单的应用让你扑ֈ一点对Tapestry的感觉。下面这个应用展CTapestry如何处理面DQ区域化Q验证和其他一些特性?/p>
q里有一个Home늚屏幕抓图Q下面跟着它的面模板?br />
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>
q个Home늚面模板除了一个jwcid属性定义用一个Tapestry PageLink①控件以外都是标准的HTML?br />
PageLink控g生成了一个指向Login늚链接。既然Home|有Q何动态的行ؓ所以它不需要页面规范和面对应的JavacR?br />
q里是Login늚屏幕抓图Q后面跟着是它的页面模ѝ?br />
Login.html
<html>
<head>
<title>
<span key="title">①Login</span>
</title>
</head>
<body jwcid="@Body">?br /> <span jwcid="@Conditional" condition="ognl:beans.delegate.hasErrors">?br /> <div style="color: red">
<span jwcid="@Delegator" delegate="ognl:beans.delegate.firstError">?br /> 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">
?br /> <table>
<tr>
<td align="right">
<span jwcid="@FieldLabel" field="ognl:components.inputUsername"?gt;
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>
q个面模板大多数是通常的HTML。我们从面模板中可以看到Tapestry的区域化Ҏ:它用一个span元素Q这个span元素带有一个叫key的属性,key的值映到Login.properties文g里一个属性。一个Body控g被声明用,因ؓ它对客户端的JavaScript校验是必需的?br />
为Form component⑤设定delegate属性激z表单输入验证。delegate属性是我们在页面规范里声明的org.apache.tapestry.valid.IvalidationDelegate的实现类。如果验证错误发生了Q我们用Conditional component③控件判断delegate是否有Q何错误,如果有就把第一个错误④昄l用戗如果ognl 表达式ognl:beans.delegate.hasErrors 为true,Conditional控g显C它的内容实体。所有的面cd控gc都从AbstractComponentl承来一个叫beans的属性。这个beans属性是一个org.apache.tapestry.IbeanProvider的实例,利用它可以通过名字取得在页面规范文仉定义的beans.FieldLabel⑥被用于为inputuserName validField控g昄标签Q这个FieldLabel控g也被用来与表单的验证代理协作Q指出包含错误的输入域?br />InputUserName⑦控件是一个显C控件的例子。显式控件是指在面规范文g声明的控件。InputUsername和inputPassword控g都是昑ּ的,它们与FieldLabel联合昄它们的displayName属性?br />
下面的是Login늚资源文g。Login.properties跟页面规范一q存攑֜WEB-INF目录?br />
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"/>?br />
<bean name="requiredValidator"?br /> 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"> ?br /> <message-binding name="displayName" key="username"/> ?br /> <binding name="validator" expression="beans.requiredValidator"/> ?br /> <binding name="value" expression="username"/> ?br /> </component>
<component id="inputPassword" type="ValidField"> ?br /> <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译器应用是怼的?br />
你会发现W一个新东西-bean元素①,bean元素把一个org.apache.tapestry.valid.ValidationDelegate
的实例指定了名称"delegate"。页面HTML模板里的Form控g把它的参数delegate讑֮?br />ognl:beans.delegate,是指向了这个org.apache.tapestry.valid.ValidationDelegate实例?br />Bean元素②把一个org.apache.tapestry.valid.StringValidator的实例指定了名称"
requiredValidator",以用于验证。这个bean的required属性被设ؓtrue表明使用q个bean的域是必被验证的。这个bean的clientScriptingEnabled属性被讑֮为ture,表明使用q个bean的域客户端的JavaScript验证功能是激zȝ。RequiredValidator bean被用于验证inputUsername和inputPassword的内宏V?br />
控ginputUsername③被控g规范声明为ValidFieldQValidField是一U用于Tapestry验证子系l的Ҏ版本的TextField控g。Message-binding元素被用于指定inputUsername控g的displayName参数的|q个值是?username"为关键字从login.properties④文仉得到。InputUsername控g的validator参数被设定ؓrequiredValidator bean,q是我们在页面规范里声明q的⑤。控件的value参数跟页面Javacȝusername属性绑定在一起⑥。控件inputPassword的控件规范跟控ginputUsername几乎怼Q除了用于取得displayName的关键字和绑定的面Javacȝ属性不同?br />
通过使用ValidField控g和ؓ表单(form)提供一个ValidationDelegate, 我们ȀzMLogin表单的验证功能。除了服务器端的验证QTapestry也提供了客户端的验证Q利用JavaScriptQ。下面就是当用户提交一个表单而没有ؓUserName域提供值时Q一个JavaScript错误对话框弹出时的屏q抓图?br />
下面是当用h交一个表单而没有ؓPassword域提供值时Q一个JavaScript错误对话框弹出时的屏q抓图?br />
下面是Login对应的Java cR?br />
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");?br /> } else {
String errorMessage = getMessage("invalidpassword");?br /> IValidationDelegate validationDelegate =
(IValidationDelegate) getBeans().getBean("delegate");?br /> validationDelegate.record(errorMessage,
ValidationConstraint.CONSISTENCY);?br /> }
}
}
跟Pig Latin译器应用一P我们的页面类也是抽象的,它有抽象Ҏ讉K在页面规范里定义的属?properties)。Tapestry会在q行时刻创徏username和password属性。LoginҎ只是单的验证一下用戯入的密码值是否刚好是用户名的反向。如果密码通过验证Q用户将被引领导Success page①?br />
如果密码输入有误Q我们用关键?invalidPassword"通过从org.apache.tapestry.AbstractComponent里承来的getMessage()Ҏ从Login.properties②里查找对应的资源。我们需要把密码错误信息U录到我们在面规范中定义的面validation delegate中去。我们可以利用我们在面规范中指定的名称Q从面的beans属性中扑֛validationDelegate③。最后,我们调用org.apache.tapestry.valid.IvalidationDelegate的recordҎ把将要显C给用户看的错误信息保存h。下面就是当用户输入错误密码的提交后的屏q抓图?br />
下面是Success늚面模板。Success늚面模板仅仅包含HTML标识Q所以它不需要页面规范和面
JavacR?br />
Success.html
<html>
<head>
<title>Successful Login</title>
</head>
<body>
<p>
Congratulations! You have successfully logged on.
</p>
</body>
</html>
ȝ
我希望这文章已l向你展CZTapestry框架在构建Web应用的是多么单,然而优雅。Tapestry与大多数LWeb应用框架最大不同在于它让你用基于控件的方式开发,而非以操作ؓ中心的方式开发。如果这文章激起了你的兴趣Q我你把它下载下来利用它你自q单的Web应用。通过感受单的应用Q这是你了解q个框架的优点的唯一途径。如果你惛_你的下一个项目里使用Tapestry,我强烈徏议你购买
Tapestry In Action q本书。我拥有q本书,对它我感到很满意?br />
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
注:原文地址Q?a >http://www.inspiresky.com/Article/java/2006-02-14/412.html