看看代码:
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<title>Celebrity Collector: All Celebrities</title>
</head>
<body>
<h1>All Celebrities in Collection</h1>
<table width="100%">
<tr t:type="loop" t:source="allCelebrities"
t:value="celebrity">
<td>
<a href="#" t:type="ActionLink"
t:context="celebrity.id"
t:id="detailsLink">${celebrity.lastName}</a>
</td>
<td>${celebrity.firstName}</td>
<td>
<t:output t:format="dateFormat"
t:value="celebrity.dateOfBirth"/>
</td>
<td>${celebrity.occupation}</td>
</tr>
</table>
<br/>
<a href="#" t:type="PageLink" t:page="Start">
Back to the Start Page</a>
</body>
</html>
<tr t:type="loop" t:source="allCelebrities" t:value="celebrity">
</tr>
t:type="loop"告诉我们这是一个Loop组件,它要干三件事:
1、它通过source属性来接受许多的对象。在我们的例子里是t:source="allCelebrities"属性,Tapestry将会在类文件中寻找getAllCelebrities方法,一般返回的是个集合。
2、它去通过这个集合反复的渲染Loop之间的内容,在这里就是一个<tr>。
3、每一次遍历这个集合,Loop利用value提供的参数通过这个页面的类去创建一个类。在我们的例子中我们用t:value="celebrity"属性,Tapestry就会到页面类中去调用setCelebrity,然后把当前遍历到的类用参数传给利用Loop传进去。然后页面利用这个属性在页面中取值。
关于那些表达式没什么好说的。${celebrity.occupation}
看看这个新组件:
<t:output t:format="dateFormat" t:value="celebrity.dateOfBirth"/>
我们也可以用${celebrity. dateOfBirth }来代替这个组件,但是这样就会显示默认的格式,也许不是日期的格式,我们无法控制它的显示格式。OutPut提供给我们一个很好的机会—我们可以用任何我们想用的形式去格式化将要显示的信息。将要显示的信息由value参数提供,显示的格式由format参数提供,你或许已经想到在接下来我们要做的事情之一就是要在ShowAll.java中创建一个getDateFormat的方法。
最后看看我们在HTML的超链接中隐藏了一个ActionLink的组件,
<a href="#" t:type="ActionLink" t:context="celebrity.id"
t:id="detailsLink">
${celebrity.lastName}
</a>
ACtionLick可以作为一个基本的连接,结合Action使用,换句话说,是相当与处理事件的方式。PageLink的主要目标是跳转到另一个页面;而ActionLink的主要目的是通过用户点击这个链接去运行一段处理事件的代码,我们可以跳转到另一个页面,但是通常情况我们没有必要这样做。
ACtionLick在以前的版本中就是DirectLink,在一些显示实体的table中,这几乎成了很自然的选择,通过点击这个链接去显示一个条目的详细信息。ActionLink的t:id属性可以让我们和事件处理关联,大多数情况下它还有个t:context属性,可以提供一个参数给事件处理的方法,这我们的例子中是个名人的ID。
ShowAll.java的所有代码:
package com.packtpub.celebrities.pages;
import com.packtpub.celebrities.data.MockDataSource;
import com.packtpub.celebrities.model.Celebrity;
import com.packtpub.celebrities.util.Formats;
import com.packtpub.celebrities.model.User;
import java.text.Format;
import java.util.List;
import org.apache.tapestry.annotations.ApplicationState;
import org.apache.tapestry.annotations.InjectPage;
import org.apache.tapestry.annotations.OnEvent;
public class ShowAll
{
@ApplicationState
private User user;
private boolean userExists;
@ApplicationState
private MockDataSource dataSource;
@InjectPage
private Details detailsPage;
private Celebrity celebrity;
String onActivate()
{
if (!userExists) return "Start";
return null;
}
@OnEvent(component="detailsLink")
Object onShowDetails(long id)
{
Celebrity celebrity = dataSource.getCelebrityById(id);
detailsPage.setCelebrity(celebrity);
return detailsPage;
}
public List<Celebrity> getAllCelebrities()
{
return dataSource.getAllCelebrities();
}
public Celebrity getCelebrity()
{
return celebrity;
}
public void setCelebrity(Celebrity celebrity)
{
this.celebrity = celebrity;
}
public Format getDateFormat()
{
return Formats.getDateFormat();
}
}
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<title>Celebrity Collector: ${celebrity.firstName} ${celebrity.lastName}</title>
</head>
<body>
<h1>Celebrity Details</h1>
<table>
<tr>
<td>First Name:</td>
<td>${celebrity.firstName}</td>
</tr>
<tr>
<td>Last Name:</td>
<td>${celebrity.lastName}</td>
</tr>
<tr>
<td>Date of Birth:</td>
<td><t:output t:value="celebrity.dateOfBirth" t:format="dateFormat"/></td>
</tr>
<tr>
<td>Occupation:</td>
<td>${celebrity.occupation}</td>
</tr>
<a href="#" t:type="PageLink" t:page="ShowAll">Back to All Celebrities</a>
</table>
</body>
</html>
类:
package com.packtpub.celebrities.pages; import com.packtpub.celebrities.model.Celebrity; import org.apache.tapestry.annotations.Persist; import java.text.Format; public class Details { @Persist private Celebrity celebrity; public void setCelebrity(Celebrity c) { this.celebrity = c; } public Celebrity getCelebrity() { return celebrity; } public Format getDateFormat() { return Formats.getDateFormat(); } }
现在运行这个应用,你发现一切都是正常的。
现在我觉得这个名人给我留下的印象太深刻了,我想把这个保存为书签,以后随时可以打开浏览。试一下~你会发现书签不能用,原因是个空指针错误,原因是pageclass的celebrity属性为空。为什么呢?原因大家都知道,persist是把这个属性放到了session中,当你以后通过书签打开的时候,这个session早就失效了。
ActionLink可以在生成的链接中记录你选择的名人的ID,但是这个ID在查找完名人后没有被保存下来。只是查到的名人类被保存在session中,当session失效时,自然就找不到了。
当用户存为书签登以后再看的时候,页面总是给他一个异常,这是很不合适的。为了防止这一点,我们可以使用anActivate方法来检查celebrity是否为空,如果是这样,我们给它重定向到其他的页面,但这不是一个优雅的解决方法,也是不友好的。有一种方法既显示详细信息页,并使它能保存书签。你已经猜到,我们可以使用page activation context?