1) Foreach组件:
basin.page
<component id="messageloop" type="Foreach">
<binding name="source" value="MessageList" />
<binding name="value" value="Ig" />
<binding name="element" value="literal:tr" />
</component>
Basin.html
<span jwcid="messageloop">
<table border="1" cellpadding="0" cellspacing="0">
<tr>
<td width="500" height="20">
<span jwcid="uname"></span>
</td>
</tr>
<tr align="left">
<td width="500" height="100">
<span jwcid="displaymessage"></span>
</td>
</tr>
</table>
Basin.java
public List getMessageList(){
return Iformation.getInmegList();
}
对html中所使用显示方式所调用的Messageloop,对应到page页面的组件则为Foreach。这是个循环组件。对于page页面里所绑定的参数有source、value、element.
1. source:将其MessageList所储存的对象、对象组、集合或者List表等存储于source参数里。
2. value:根据每次循环所得到的绑定于source上的一个值,对应的将其赋值到Ig里。
3. element:这个就对每次循环进行重复的输出tr这个html的tag.以达到循环一次,就多显示一次表格行。
根据Tapestry框架,在对应的java文件里需要定义getMessageList的方法,以提供MessageList变量能够获取一个数据集,并绑定在source参数上。
NOTE:Foreach与For组件一样是循环组件,后面For组件将详细记录两者的区别
2)Insert组件
Basin.page
<component id="displaymessage" type="Insert">
<binding name="value" value="Ig.mg" />
</component>
<component id="uname" type="Insert">
<binding name="value" value="Ig.ne" />
</component>
根据Foreach组件里的html代码中使用了2个jwcid.而对应的page页面则使用的是Insert组件。按照Foreach的value每次就绑定于source的数据集进行装载的结果,Insert的参数value则取出Ig的某一个属性进行显示。
NOTE:对于1)和2) 则需要说明一下<property name="Ig" />.property标签在page页面中使用,类似于在class页面里创建一个属性。属性并没有定义类型,其根据所装载的值的类型进行匹配。例,Ig对应所取得的是一个拥有2个属性—mg和ne的对象类型。
另外:如果需要对page中的property初始化特殊的值,可以:
<property name="Ig" initial-value="literal:name"/>
在页面类里可以直接声明get/set的抽象方法。
等同于使用annotation的:
@InitialValue("literal:name")
public abstract String getUsername();
在page页面中定义页面属性的同时,在页面类中Tapestry框架会配置对应的页面属性方法:
<property name="username">
Tapestry框架会在程序运行时,自动在页面类中完成以下代码:
private String username;
@Override
protected void initialize() {
this.username= null;
}
public abstract String getUsername() {
return username;
}
public void setUsername(String s) {
username = s;
}
3) Form组件
Basin.html
<form jwcid="referform">
<table border="1" cellpadding="0" cellspacing="0">
<tr>
<td colspan="3" width="500" height="100" jwcid="message">输入留言</td>
</tr>
<tr>
<td>用户名</td>
<td><input jwcid="une" type="text" value="basin_leaf"/></td>
<td><input align="right" type="submit" value="发表"/></td>
</tr>
</table>
</form>
Basin.page
<component id="referform" type="Form">
<binding name="listener" value="listener:onClick" />
</component>
Basin.java
public ILink onClick(){
Iformation.fun(this.getinf(),this.getgne());
//return getPageService().getLink(false, getPageName());
return getPageLink(getPageName());
//cycle.activate("/magoa/basin");
}
方法的类型并不需要在page页面中定义,而是根据需要在java页面进行操作。
Jwcid所调用的Form组件,其中使用了listener参数,其默认的value如上所写:listener:noClick。也就是为对应的java页面声明了一个noClick的方法,并要在java页面里实现,也就是当且仅当表单提交后,而又没有其他监听方法,则运行此方法。
4) TextArea和TextField组件
在Form组件里的basin.html里有jwcid为message和une的引用,对应的page里则为TextArea和TextField组件。
<component id="message" type="TextArea">
<binding name="value" value="inf" />
<binding name="validators" value="validators:maxLength=50,minLength=2,required" />
</component>
<component id="une" type="TextField">
<binding name="value" value="gne" />
<binding name="validators" value="validators:required" />
</component>
两者并不存在大的区别,只是在显示的文本输入框体的height的区别。对应在page里的组件参数value与validators.value参数对应所声明的变量inf和gne,并对应进行绑定,当在文本框或者区域里输入时,则数据通过变量装载到value参数里,而validators对数据进行校验,根据validators:required,MaxLength=10
在这里绑定了2个校验属性,即必须输入不能为空和长度最大为10
对于TextField和TextArea组件中的value参数所定义的变量,在java页面类中必须声明抽象的get或set方法。例如
public abstract String getinf();
public abstract String getgne();
Note:对于TextField组件,参数hidden的value如果值为true,则对应的html里标签为type=”password”.TextField组件在添加校验后,必须运行在Body组件中。也就是说在Form组件中添加了<binding name="clientValidationEnabled" value="true" />之后,必须使用Body组件。并且在对应的TextField或者TextArea中使用displayName参数,设置组件对应的名称。
5) 页面刷新导致的表单重复提交
Basin.page
<property name="message" persist="flash"/>
定义一个名字为message的页面属性.当然这个涉及到页面的生命周期。此使用了flash持久化,即声明property元素时,定义其persist属性值。
对于之前的<property name="Ig" />则为页面的瞬间状态,为页面类与页面之间提供一个数据的装载体,以方便之间的联系。
Basin.java
public abstract class MyPage extends BasePage
{
@Persist("flash")
public abstract String getMessage();
public abstract void setMessage(String message);
@InjectObject("engine-service:page")
public abstract IEngineService getPageService();
public ILink onClick()
{
Iformation.fun(this.getinf(),this.getgne());
setMessage("Your changes have been saved.");
return getPageService().getLink(false, getPageName());
}
}
@Persist(“flash”) //Annotation方式
Persist注释给抽象的方法注入持久化的属性值. 其默认为"session"。
<property name=” ” persist=” ” /> //普通方式
@InjectObject("engine-service:page")
注入提供对象实例。也分为普通与Annotation方式
普通:<inject property=”” object=”” />
Annotation:@InjextObject(“ ”)
页面跳转:
1.
@InjectPage("Result") //注入页面对象Result
abstract public Result getResultPage();
public IPage onClick(IRequestCycle cycle) {
Result resultPage = getResultPage();//跳到Result页面
Return resultPage;
}
或者不使用Annotation,如下:
Cycle.getPate(“ResultPage”); //获取页面实例
2
Public void onClick(IRequestCycle cycle)
{
Cycle.activate(“page”); //跳转到page页面
}
注册页面:
1. DatePicker组件:
Login.page
<component id="birthday" type="DatePicker">
<binding name="value" value="loginvo.birthday"/>
<binding name="translator" value="translator:date,pattern=yyyy-MM-dd HH:mm:ss"/><!—- 日期格式 -->
<binding name="validators" value="validators:required,minDate= 1/1/2007 ,maxDate=6/31/2007"/>
<!—- 校验 -->
<binding name="includeWeek" value="true"/> <!-- 等于true,表示在日历板中显示周的数 -->
</component>
组件参数value并将其获得的输入框中日期绑定在loginvo.birehday
NOTE:在html的body里要加入Body组件,才能使用。
2.RadioGrou与Radio组件
隐式调用:
Login.html
<span jwcid="@RadioGroup" selected="ognl:loginvo.sex">
<input type="radio" jwcid="@Radio" value="男" />
<span jwcid="@Insert" value="男" />
<input type="radio" jwcid="@Radio" value="女" />
<span jwcid="@Insert" value="女"></span>
</span>
或者
显式:
Login.html
<span jwcid=”RG” >
<input type="radio" jwcid="R1" />
<span jwcid="@Insert" value="男" />
<input type="radio" jwcid="R2" />
<span jwcid="@Insert" value="女"></span>
</span>
Login.page
<component id=”RG” type=”RadioGroup”>
<binding name=”selected” value=”loginvo.sex” />
</component>
<component id=”R 1” type=”Radio”>
<binding name=”value” value=”男” />
</component>
<component id=”R 2” type=”Radio”>
<binding name=”value” value=”女” />
</component>
通过对参数value的数据装载,传到RadioGroup组件的selected参数并与loginvo.sex绑定。
3.PropertySelection组件
Login.html
<select jwcid="stId">
<option value="0">T1</option>
<option value="1">T2</option>
<option value="2">T3</option>
<option value="3">T4</option>
</select>
Login.page
<component id="stId" type="PropertySelection">
<binding name="model" value="funId" />
<binding name="value" value="stId" />
</component>
Login.java
abstract public String getstId()
public IPropertySelectionModel getfunId(){
return new StringPropertySelectionModel(new String[]{"11","22","33"});
}
返回的下拉菜单初始以11,22,33赋值。根据page页面所声明的两个变量,则对应的类方法的实现:funId对应的get方法为参数model绑定初始值。stId对应的抽象get方法以提供程序在客户端提交表单后,取出其组件选中的值。
4.DirectLink与ExternalLink
DirectLink组件为html页面打印<a>标签
Login.page
<component id="dlink" type="DirectLink">
<binding name="listener" value="listener:dk" />
<binding name="parameters" value="x"/>
</component>
绑定x到参数parameters,并且在监听方法dk中可以获取此参数,并将其编码到URL中
Login.html
<a jwcid="dlink">123123</a>
Login.java
Public void dk(IRequestCycle cycle){
Object[] nn=cycle.getListenerParameters();
cycle.active("pagename");
}
连接跳转到pagename页面,
ExternalLink组件把page和paramters参数绑定的值编码到URL中,(接口IExternalPage)其必须实现方法:
Public void activateExternalPage(Object[] parameters, IRequestCycle cycle){
}
例如:
Html页面
<a href="#" jwcid="@ExternalLink" page="ViewArticle" parameters="ognl:{articleId, 'de'}" disabled="ognl:languageCode=='de'"></a>
<div jwcid="@Insert" value="ognl:content">content of the article</div>
Page页面
package com.myexample;
import org.apache.tapestry.IExternalPage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.html.BasePage;
public abstract class ViewArticle extends BasePage implements IExternalPage {
public abstract Integer getArticleId();
public abstract void setArticleId(Integer articleId);
public abstract String getLanguageCode();
public abstract void setLanguageCode(String language);
public void activateExternalPage(Object[] params, IRequestCycle cycle) {
setArticleId((Integer) params[0]);
setLanguageCode((String) params[1]);
}
public String getContent() {
// retrieve the content of the article for the selected language
}
}
DrectLink与ExternalLink区别
1.DirectLink涉及session,它有一个布尔型参数stateful来选择stateful 和 stateless,默认为true即stateful,而ExternalLink仅仅是stateless,不能选择
2.DirectLink通过Listener监听方法将参数“扔”给下一个页面,只要定义了跳转页面就OK,参数自动扔到跳转页面里。而ExternalLink通过下一个页面实现IExternalPage接口及activateExternalPage方法接收参数 DirectLink接收参数时要注意,返回值是Void,要符合监听方法规则
3.DirectLink用DirectService,ExternalLink用ExternalService。另外Form提交用的是DirectService。
5.Image
Login.page
<component id="photo" type="Image">
<binding name="image" value="ognl:getAsset('test')" />
</component>
<asset name="test" path="路径" />
或者
Login.html
<img jwcid=”@Image” image=”ognl:getAsset(‘name’+photonum)” />
Login.page
<asset name=”name 1” path=”路径” />
<asset name=”name 2” path=”路径” />
<asset name=”name 3” path=”路径” />
Asset:用Shell组件加载CSS文件。
.page
<comoponent id=”shell” type=”Shell”>
<binding name=”title” value=”title” />
<binding name=”stylesheet” value=”asset:stylename” />
</component>
<asset name=”stylename” path=”CSS/*.CSS” />
或者
@Asset(“CSS/*.css”)
Public abstract IAsset getstylename();
6. For、Checkbox
For:
Login.html
<span jwcid="customlist">
<input type="checkbox" jwcid="checkbox" />
<span jwcid="@Insert" value="ognl:loginvo.item"/>
</span>
Login.page
<component id="customlist" type="For">
<binding name="source" value="loginvo.customlist"/>
<binding name="value" value="loginvo.item"/>
<binding name="element" value="literal:span"/>
</component>
Login.java
abstract public void setLoginvo(Loginvo vo);
protected void initialize() {
Loginvo vo = new Loginvo();
List<String> list=new ArrayList<String>();
list.add("音乐");
list.add("运动");
list.add("看书");
list.add("电影");
vo.setCustomlist(list);
this.setLoginvo(vo);
}
通过对业务逻辑类Loginvo的使用,并传回一个list表,将初始方法initialize中的值进行储存,使得页面属性loginvo获得了一个数据集。For组件的source参数装载了loginvo的一个属性customlist的数据,由value参数通过For组件每次对数据集的遍历,取出值并装载到loginvo.item中,<span jwcid="@Insert" value="ognl:loginvo.item"/>
则插入数据。
Checkbox:
Login.page
<component id="checkbox" type="Checkbox">
<binding name="value" value="checked"/>
</component>
Login.java
Public abstract Boolean ischecked();
If(this.ischecked())
{ }
7.Upload、FieldLabel、If、Else
*.html
<form jwcid="@Form" listener="listener:formSubmit">
<span jwcid="@FieldLabel" field="component:upload"/>
<input jwcid="upload@Upload" file="ognl:uploadFile" type="file" displayName="File" validators="validators:required"/>
<input type= "submit" value="Upload"/>
<span jwcid="@If" condition="ognl: uploadFile && serverFile">
<ul>
<li>Filename: <span jwcid="@Insert" value="ognl:uploadFile.fileName"/></li>
<li>Client path: <span jwcid="@Insert" value="ognl:uploadFile.filePath"/></li>
<li>Server Path: <span jwcid="@Insert" value="ognl:serverFile.absolutePath"/></li>
<li>File Size: <span jwcid="@Insert" value="ognl:serverFile.length()" format="ognl:numberFormat"/> bytes</li>
</ul>
</span>
</form>
Upload文件大小设置:在hivemind里配置:
<implementation service-id="tapestry.multipart.ServletMultipartDecoder">
<create-instance class="org.apache.tapestry.multipart.MultipartDecoderImpl,maxSize=-1" model="threaded" />
</implementation>
If与Else:
判断是否显示组件所包含的模版或其他组件。
<span jwcid="@If" condition="ognl: uploadFile && serverFile">
<ul>
<li>Filename: <span jwcid="@Insert" value="ognl:uploadFile.fileName"/></li>
<li>Client path: <span jwcid="@Insert" value="ognl:uploadFile.filePath"/></li>
<li>Server Path: <span jwcid="@Insert" value="ognl:serverFile.absolutePath"/></li>
<li>File Size: <span jwcid="@Insert" value="ognl:serverFile.length()" format="ognl:numberFormat"/> bytes</li>
</ul>
</span>
判断两个参变量的与关系以判断是否显示。
<span jwcid=”@Else”><span jwcid=”@PageLink” page=” ” />.
FieldLabel: <span jwcid="@FieldLabel" field="component:upload"/>
生成<label>标签,将组件Upload的displayName参数的值打印到客户端页面上。
*.java
public abstract class UploadPage extends BasePage {
public abstract IUploadFile getUploadFile();
public abstract File getServerFile();
public abstract void setServerFile(File file);
public Format getNumberFormat() {
return NumberFormat.getNumberInstance();
}
public void formSubmit(IRequestCycle cycle) {
if (getUploadFile() == null) {
return;
}
InputStream fis = getUploadFile().getStream();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(getUploadFile().getFileName()));
byte[] buffer = new byte[1024];
while (true) {
int length = fis.read(buffer);
if (length < 0) {
break;
}
fos.write(buffer, 0, length);
}
fis.close();
fos.close();
setServerFile(new File(getUploadFile().getFileName()));
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (fis != null) {
try { fis.close(); } catch (IOException ioe) {}
}
if (fos != null) {
try { fos.close(); } catch (IOException ioe) {}
}
}
}
}
Tapestry属性注入:
Tapestry的property属性注入大多数使用的是单域的方式。(使用这种方式Tapestry的异常提示将不会那么详细)
InjectPage
@InjectPage("Shop")
public abstract Shop getShopPage();
这里通过声明@InjectPage的annotation,Tapestry在反射到getShopPage()抽象方法的时候,就会将一个页面名称为"Shop"的页面类实例注入进去。
因此,下面两种写法具有等同的效果:
@InjectPage("Shop")
public abstract Shop getShopPage();
//登陆表单的监听方法
public IPage loginSubmit(IRequestCycle cycle) {
System.out.println(this.getUsername());
System.out.println(this.getPassword());
return this.getShopPage();
}
或者
//登陆表单的监听方法
public IPage loginSubmit(IRequestCycle cycle) {
Shop page = (Shop)cycle.getPage("Shop");
System.out.println(this.getUsername());
System.out.println(this.getPassword());
return page;
}
8.页面表单提交过程
整个表单提交的详细处理过程如下:
1) initialize():页面初始化
如果还没有创建这个页面的池,那它会创建这个页面,并响应请求,然后放入池中,那创建时会调用initialize()方法。
2) pageBeginRender() ("rewind"):getRequestCycle().isRewinding()为true
3) rewind of the form / setting of properties:所有表单组件调用rewindFormComponent来取值赋值
4) Deferred listeners (for Submit components):调用Submit组件的listener
5) Form's listener:调用Form组件的listener
6) pageEndRender() ("rewind"): getRequestCycle().isRewinding()为true
7) pageBeginRender() (normal): getRequestCycle().isRewinding()为false
8) pageEndRender() (normal): getRequestCycle().isRewinding()为false
9.数字与string的转换
<component id=” ” type=” ”>
<binding name=”value” value=”xx” />
<binding name=”translator” value=”translator:number,pattern=#.#” />
</component>
Number转换组件所取得的值(这里就是xx的值)为int,double,或者String.当加入pattern时可为float值。