下面来谈谈Tapestry的开发流程。
Tapestry的开发主要有两种:一种是控件的开发,一种是页面的开发,其实页面也可以被看成控件。
以我的工程为例,我的控件全放在com.ht.components下
以我的ToolBar为例,
我的ToolBar控件放在com.ht.components.toolbar下
下面有
IToolItemDescirption.java
IToolItemListener.java
SimpleToolItemDescription.java
ToolBar_en_US.properties
ToolBar_zh_CN.properties
ToolBar.html
ToolBar.jwc
ToolItem.html
ToolItem.java
ToolItem.jwc
因为我是这样设计的,一个ToolBar包括一些ToolItem项,每个ToolItem的数据由一个
IToolItemDescription来提供.
一个控件XXX的通常组成为
一个XXX.java文件
一个XXX.jwc文件
一个XXX.html文件(当然html也可以不要,一个控件的render完全交给XXX.java去实现也是可行的)
可选的为
XXX._en_US_properties(对应的美国英语字符资源文件)
XXX._zh_CN_properties(对应的中国大陆字符资源文件)
XXX.xxx_properties(你还可以添加其他的local字符资源文件,只要xxx是合法的locale)
我的例程实现:
package com.ht.components.toolbar;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author Hery Tang
* @version 1.0
*/
import org.apache.tapestry.IAsset;
public interface IToolItemDescription {
public IToolItemListener getToolItemListener();
public IAsset getAsset();
public IAsset getDisabledAsset();
public String getLabel();
public String getActionType();
public boolean isSeparator();
public boolean isEnable();
}
package com.ht.components.toolbar;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author Hery Tang
* @version 1.0
*/
import org.apache.tapestry.IPage;
public interface IToolItemListener {
public void actionPerformed();
}
package com.ht.components.toolbar;
/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author Hery Tang
* @version 1.0
*/
import org.apache.tapestry.IAsset;
public class SimpleToolItemDescription implements IToolItemDescription{
private IToolItemListener toolItemListener;
private IAsset enabledAsset;
private IAsset disabledAsset;
private String label;
private String actionType;
private boolean isSeparator;
private boolean isEnable;
public SimpleToolItemDescription() {
isEnable = true;
isSeparator = false;
}
public IToolItemListener getToolItemListener() {
return toolItemListener;
}
public void setToolItemListener(IToolItemListener listener) {
toolItemListener = listener;
}
public IAsset getAsset() {
return enabledAsset;
}
public void setAsset(IAsset asset) {
this.enabledAsset = asset;
}
public IAsset getDisabledAsset() {
return disabledAsset;
}
public void setDisabledAsset(IAsset asset) {
this.disabledAsset = asset;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public void setActionType(String actionType) {
this.actionType = actionType;
}
public String getActionType() {
return actionType;
}
public boolean isSeparator() {
return isSeparator;
}
public void setIsSeparator(boolean value) {
isSeparator = value;
}
public boolean isEnable() {
return isEnable;
}
public void setIsEnable(boolean value) {
isEnable = value;
}
}
ToolBar_en_US.properties
ToolBar_zh_CN.properties
暂时为空,我没有需要国际化的字符资源
ToolBar.html
<span jwcid="$content$">
<table width="100%" border="0" cellpadding="0" cellspacing="1">
<tr>
<span jwcid="@Conditional" condition="ognl:!isAlignLeft">
<td align="right">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<span jwcid="@Foreach" source="ognl:toolItemDescriptions" value="ognl:currentToolItemDesc">
<td>
<span jwcid="@ToolItem" description="ognl:currentToolItemDesc"/>
</td>
<td width="10">
</td>
</span>
</tr>
</table>
</td>
</span>
<span jwcid="@Conditional" condition="ognl:isAlignLeft">
<td align="left">
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<span jwcid="@Foreach" source="ognl:toolItemDescriptions" value="ognl:currentToolItemDesc">
<td>
<span jwcid="@ToolItem" description="ognl:currentToolItemDesc"/>
</td>
<td width="10">
</td>
</span>
</tr>
</table>
</td>
</span>
</tr>
</table>
</span>
ToolBar.java
package com.ht.components.toolbar;
import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IRequestCycle;
import java.util.List;
/**
* Simple ArrayViewer object, for the Component chapter of the Tutorial
* @author neil clayton
*/
public abstract class ToolBar extends BaseComponent {
private IToolItemDescription currentToolItemDesc;
private List toolItemDescriptions;
public IToolItemDescription getCurrentToolItemDesc() {
return currentToolItemDesc;
}
public void setCurrentToolItemDesc(IToolItemDescription itemDesc) {
this.currentToolItemDesc = itemDesc;
}
public List getToolItemDescriptions() {
return toolItemDescriptions;
}
public void setToolItemDescriptions(List descList) {
toolItemDescriptions = descList;
}
/**
* @see net.sf.tapestry.AbstractComponent#cleanupAfterRender(IRequestCycle)
*/
protected void cleanupAfterRender(IRequestCycle cycle) {
currentToolItemDesc = null;
toolItemDescriptions = null;
super.cleanupAfterRender(cycle);
}
public abstract boolean getIsAlignLeft();
}
ToolBar.jwc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<component-specification class="com.ht.components.toolbar.ToolBar" allow-body="no" allow-informal-parameters="yes">
<parameter
name="toolItemDescriptions"
type="java.util.List"
direction="in"
required="yes">
</parameter>
<parameter name="isAlignLeft"
type="boolean"
required="no"
direction="in"/>
</component-specification>
ToolItem.html
<span jwcid="$content$">
<span jwcid="@Conditional" condition="ognl:!isSeparator">
<span jwcid="@Conditional" condition="ognl:IsEnable">
<span jwcid="link"><img jwcid="enabledImage"/><font color="White"><span jwcid="@InsertText" value="ognl:label"/></font></span>
</span>
<span jwcid="@Conditional" condition="ognl:!IsEnable">
<img jwcid="disabledImage"/><font color="#A0A0A0"><span jwcid="@InsertText" value="ognl:label"/></font>
</span>
</span>
<span jwcid="@Conditional" condition="ognl:isSeparator">
<img jwcid="@Image" image="ognl:enabledImage"/>
</span>
</span>
ToolItem .java
package com.ht.components.toolbar;
import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.components.Foreach;
import org.apache.tapestry.IAsset;
public class ToolItem extends BaseComponent{
private IToolItemDescription desc;
/**
* @see net.sf.tapestry.AbstractComponent#cleanupAfterRender(IRequestCycle)
*/
protected void cleanupAfterRender(IRequestCycle cycle) {
desc = null;
super.cleanupAfterRender(cycle);
}
public IToolItemDescription getDescription() {
return desc;
}
public void setDescription(IToolItemDescription desc) {
this.desc = desc;
}
public void excuteCurrent(IRequestCycle cycle) {
if(desc != null) {
IToolItemListener listener = desc.getToolItemListener();
listener.actionPerformed();
}
}
public IAsset getEnabledAsset() {
return desc.getAsset();
}
public IAsset getDisabledAsset() {
return desc.getDisabledAsset();
}
public String getLabel() {
return desc.getLabel();
}
public boolean getIsSeparator() {
return desc.isSeparator();
}
public boolean getIsEnable() {
return desc.isEnable();
}
}
ToolItem.jwc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<component-specification class="com.ht.components.toolbar.ToolItem" allow-body="no" allow-informal-parameters="yes">
<parameter
name="description"
type="com.ht.components.toolbar.IToolItemDescription"
direction="in"
required="yes">
</parameter>
<component id="link" type="LinkSubmit">
<binding name="listener" expression="listeners.excuteCurrent"/>
</component>
<component id="enabledImage" type="Image">
<binding name="image" expression="enabledAsset"/>
</component>
<component id="disabledImage" type="Image">
<binding name="image" expression="disabledAsset"/>
</component>
</component-specification>
我就拿ToolBar这个控件讲:
先看ToolBar.jwc
<component-specification class="com.ht.components.toolbar.ToolBar" allow-body="no" allow-informal-parameters="yes">
这句是去说控件ToolBar对应的class为com.ht.components.toolbar.ToolBar
allow-body="no'是说这个控件不允许有body, allow-informal-parameters="yes"是说这个控件允许带非正式参数。
控件的参数有两种一种是在jwc文件里规定的,一种是没有规定,为什么会有非正式参数呢?大家知道Tapestry的控件,最后render到页面最终还是什么
<table width="100%" border="0" cellpadding="0" cellspacing="1">
<tr>
<td class="xxx"></td>
</tr>
</table>
HTML的元素如table, tr, td,span等等都是可以带很多参数,如果我们的控件输出一般会
对应于一个元素,这时非正式参数就会以元素的参数输出。
<parameter
name="toolItemDescriptions"
type="java.util.List"
direction="in"
required="yes">
</parameter>
这个说明ToolBar控件需要配制一个叫toolItemDescriptions的参数,参数类型为java.util.List,direction为in表示这个参数仅仅需要输入,不要输出,
required=yes表示这个参数是必须的,一定要提供。
<parameter name="isAlignLeft"
type="boolean"
required="no"
direction="in"/>
意义同上。
我们再来分析一下ToolBa.html
首先这个控件的模版被一个
<span jwcid="$content$">
</span>
包围,这个是说明,只有这个区域里的内容才是有意义的,区域外的全被忽略。
然后这个控件可分为两部分,根据isAlignLeft参数决定这个ToolBar显示时是否向左靠齐
我们分析这一句
<span jwcid="@Conditional" condition="ognl:!isAlignLeft">
</span>
首先讲讲怎么使用控件,Tapestry的控件有四种:
Tapestry自己提供的有三种:
可参考:
http://jakarta.apache.org/tapestry/doc/ComponentReference/index.html
其中包括:
1 Framework Library (基础控件)
2 Contrib Library (Contributores 开发的控件)
3 WML Library (应用在WML上的控件,主要用在移动设备,暂时不谈)
4 自己开发的控件
在Tapestry中控件是可以由别的控件组成的,而且控件的嵌套级数不受限制,要在一个页面或一个控件中应用已开发的控件或Tapestry的提供的控件有两种方式:
一种是在控件规范文件(*.jwc)或页面规范文件(*.page)声明后再在HTML模版里使用
一种直接在HTML模版里使用.
不过这两种情况有个共同点,你都会在HTML模版发现<span jwcid="***">的字样。
第一种情况:
你看那个ToolItem.jwc
里面含有
<component id="link" type="LinkSubmit">
<binding name="listener" expression="listeners.excuteCurrent"/>
</component>
<component id="enabledImage" type="Image">
<binding name="image" expression="enabledAsset"/>
</component>
<component id="disabledImage" type="Image">
<binding name="image" expression="disabledAsset"/>
</component>
这里就是声明里三个空间,我们就看第一个,
<component id="link" type="LinkSubmit">
<binding name="listener" expression="listeners.excuteCurrent"/>
</component>
这里声明一个控件 id为link,id要是唯一的(是在同一控件名字空间里),
type为LinkSubmit,就是指定这个控件的类型,当然如果是使用自己开发的控件,还要注意名字空间的问题,这个问题下面再谈。
<binding name="listener" expression="listeners.excuteCurrent"/>
这句是为这个控件listener参数绑定一个值,expression=listeners.excuteCurrent
这个表达式是一个OGNL表达式,它等同于expression=this.getListeners().getListener("excuteCurrent");这里的this当然是com.ht.components.toolbar.ToolItem
所以我们察看ToolItem,会发现这个listener绑定的方法是
public void excuteCurrent(IRequestCycle cycle) {
if(desc != null) {
IToolItemListener listener = desc.getToolItemListener();
listener.actionPerformed();
}
}
现在这个控件(id=link)声明配置好了,我们再看看ToolItem.html
会发现这一段
<span jwcid="link"><img jwcid="enabledImage"/><font color="White"><span jwcid="@InsertText" value="ognl:label"/></font></span>
注意<span jwcid="link">***</span>,里面的东西暂时不管
这个<span jwcid="link">就是引用的我们刚才那个叫link的LinkSubmit控件。
第二种是直接在HTML模版里使用:
再回到前面看ToolBa.html里的那一句
<span jwcid="@Conditional" condition="ognl:!isAlignLeft">
</span>
这里就是在HTML模版里直接使用控件的例子,这里意思是使用一个类型为Conditional的控件,id忽略,Tapestry会给它自动指定一个id,如果你写成
<span jwcid="xxx@Conditional" condition="ognl:!isAlignLeft">
那么你指定了这个控件的id为xxx.
这里的condition="ognl:!isAlignLeft"就跟我们规范文件(*.jwc,*.page)里写成的
<binding name="condition" expression="!isAlignLeft"/>是一个意义。
开发好控件的管理:
对于自己开发的控件,我们要把它管理起来,以便在以后的开发流程中使用,
我的在这里谈谈如何管理自己开发的控件的问题。具体的方法就是把它归档到一个library
里去。
比如我开发了一些控件,我就把它归档到一个叫Common.library的xml文档里去。
Common.library
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<library-specification>
<!-- Library Section-->
<library id="contrib" specification-path="/org/apache/tapestry/contrib/Contrib.library"/>
<library id="basic" specification-path="/com/ht/components/basic/Basic.library"/>
<!-- Add more libraries here.-->
<!-- End of Library Section-->
<component-type type="TabPanel" specification-path="tabpanel/TabPanel.jwc"/>
<component-type type="Border" specification-path="border/Border.jwc"/>
<component-type type="ToolItem" specification-path="toolbar/ToolItem.jwc"/>
<component-type type="ToolBar" specification-path="toolbar/ToolBar.jwc"/>
<component-type type="AnchorDirect" specification-path="tree/components/AnchorDirect.jwc"/>
<component-type type="TreeDataView" specification-path="tree/components/TreeDataView.jwc"/>
<component-type type="TreeHeaders" specification-path="tree/components/TreeHeaders.jwc"/>
<component-type type="TreeNodeView" specification-path="tree/components/TreeNodeView.jwc"/>
<component-type type="TreeView" specification-path="tree/components/TreeView.jwc"/>
<component-type type="FileList" specification-path="table/FileList.jwc"/>
<component-type type="WrapInsertText" specification-path="wraptext/WrapInsertText.jwc"/>
<component-type type="HighlightInsertText" specification-path="highlight/HighlightInsertText.jwc"/>
<component-type type="DefaultTableColumnComponent" specification-path="table/DefaultTableColumnComponent.jwc"/>
<component-type type="AlignRightTableColumnComponent" specification-path="table/AlignRightTableColumnComponent.jwc"/>
<component-type type="DefaultTableColumns" specification-path="table/DefaultTableColumns.jwc"/>
</library-specification>
<libray-specification>包含两种元素
一种是library<library id="contrib" specification-path="/org/apache/tapestry/contrib/Contrib.library"/>
因为如果被归档的控件还引用到其他的被归档的控件(控件库),就必须在这里包含进来。
例外一种是
<component-type type="ToolBar" specification-path="toolbar/ToolBar.jwc"/>
就是被归档的控件项定义,这句我们应该有印象,这个控件就是我们前面讨论的ToolBar
注意这个specification-path是相对路径。
比如我的Common.library位于com.ht.components包内,而那个ToolBar.jwc位于com.ht.components.toolbar包内。
页面的开发:
我的Web Application只支持英语和简体中文,以开发Home页为例,我所需要新建的文件
为:
Home.java
Home.page
Home.properties
Home_zh_CN.properties
它们都位于com.ht.home包内,对应的目录为F:/myproject/TapestryExmaple/src/
com/ht/home
Home.html
它位于context下home目录内,对应的目录为F:/myproject/TapestryExmaple/context/home
我的例程为:
Home.java
package com.ht.home;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.tapestry.engine.AbstractEngine;
import org.apache.tapestry.html.BasePage;
import com.ht.web.PatientRecordBasePage;
import com.ht.web.PatientRecordEngine;
import com.ht.components.tabpanel.*;
/**
* @author Hery Tang
*
* Creation Date 2003-9-22
* Version 1.0
*/
public class Home extends PatientRecordBasePage {
public void logout() {
PatientRecordEngine engine = (PatientRecordEngine) getEngine();
engine.logout();
}
}
Home.page
<?xml version="1.0" encoding="UTF-8"?>
<!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.ht.home.Home">
<component id="border" type="common:Border">
<message-binding name="title" key="title"/>
<binding name="styleSheet" expression="assets.test"/>
</component>
<context-asset name="$template" path="home/Home.html"/>
<context-asset name="menuIcon" path="home/images/homeIcon.gif"/>
<context-asset name="test" path="home/css/test.css"/>
</page-specification>
Home_zh_CN.properties
menuText=首页
title=首页
actionListener.logout.menuText=注销
welcome=欢迎
welcomeDetail=欢迎使用web病历管理系统,这是一套基于网络的B/S结构的病历管理服务系统,功能新颖,界面友好,欢迎使用。
Home.properties
title=Home
menuText=Home
actionListener.logout.menuText=Logout
welcome=Welcome
welcomeDetail=Welcome to use Web Document Manage System.This system based on B/S network structure, it provides internal documents' management for your company. It's document directory organized as that: a department as a unit, departments can share documents each other. Meanwhile, it provides detailed document version control.
Home.html
<span jwcid="border">
<table align="center" width="100%" height="100">
<tr>
<!-- ========================== START MID COL ======================= -->
<td VALIGN="TOP" width='100%'>
<table width='100%' cellpadding='0' cellspacing='0' border='0'>
<tr>
<td width='10'><img src='home/images/pixel.gif' width='10' height='1' alt='-'></td>
<td width='100%'><img src='home/images/welcome_head_icon.gif' ALIGN="BOTTOM" WIDTH="16" HEIGHT="16" ALT="Welcome!"> <font class='h2' style='color: #080c77;'><span key="welcome">Welcome</span></font></td>
<td width='10'><img src='home/images/pixel.gif' width='10' height='1' alt='-'></td>
</tr>
<tr>
<td height='5' colspan='3' valign='top'><img src='home/images/head_home_line.gif' width='254' height='5' alt='-'></td>
</tr>
<tr>
<td height='5' colspan='3' bgcolor='#ffffff'><img src='home/images/pixel.gif' width='1' height='5' alt='-'></td>
</tr>
<tr>
<td width='10' bgcolor='#ffffff'><img src='home/images/pixel.gif' width='10' height='1' alt='-'></td>
<td width='100%' bgcolor='#ffffff'>
<span key="welcomeDetail">Welcome to use Web Document Manage System.This system based on B/S network structure, it provides internal documents' management for your company. It's document directory organized as that: a department as a unit, departments can share documents each other. Meanwhile, it provides detailed document version control.</span>
</td>
<td width='10' bgcolor='#ffffff'><img src='home/images/pixel.gif' width='10' height='1' alt='-'></td>
</tr>
<tr>
<td height='5' colspan='3' bgcolor='#ffffff'><img src='home/images/pixel.gif' width='1' height='5' alt='-'></td>
</tr>
</table>
</td>
</tr>
</table>
</span>
对于页面的开发,有几个值得讨论的问题,
一 框架化的页面怎么实现
这个很简单,你只要开发一个控件,预先定义好一个显示框架,我就是这么做的,我开发了一个叫Border的控件,然后把变动的显示作为Border可变的内容输出。
你看我的 Home.html,它被<span jwcid="border">**</span>所包围,我的Border控件负责
显示每页确定的内容,变动的则只在Border的一个预定的区域显示。
二 国际化怎么办
Tapestry国际化非常简单,例如英文我要显示welcome,中文显示欢迎
只须这样就行:
<span key="welcome">Welcome</span>(中间的Welcome是预览hmtl用的没有
别的意义),然后你在home.properties设定key-value对为: welcome=Welcome
在Home_zh_CN.properties设定为: welcome=欢迎,不过最后打包时你要将你的
Home_zh_CN.properties用jdk的bin目录下的native2ascii命令转化一下,不然会
显示成乱码。
我们来分析一下Home.page
<page-specification class="com.ht.home.Home">
声明本页对应的class为com.ht.home.Home
<component id="border" type="common:Border">
<message-binding name="title" key="title"/>
<binding name="styleSheet" expression="assets.test"/>
</component>
声明并配置一个Border类型的控件
<message-binding name="title" key="title"/>
指定了本页的title
binding name="styleSheet" expression="assets.test"/>
指定了本页应用的StyleSheet资源
<context-asset name="$template" path="home/Home.html"/>
指定了Home页的模版为home/Home.html
<context-asset name="menuIcon" path="home/images/homeIcon.gif"/>
声明一个context-asset(图标)
<context-asset name="test" path="home/css/test.css"/>
声明一个context-asset(Stylesheet),被上面的Border控件引用
最后讲讲划分子模块的问题:
比如我的Web Application包含两个子模快home, patientrecord,
home对应的包为com.ht.home,绝对路径为F:/myproject/TapestryExmaple/src/
com/ht/home,对应的context目录为home,绝对路径为F:/myproject/
TapestryExmaple/context/home
patientrecord对应的包为com.ht.patientrecord,绝对路径为F:/myproject/TapestryExmaple/src/com/ht/patientrecord,
对应的context目录为patientrecord,绝对路径为F:/myproject/
TapestryExmaple/context/patientrecord
home模块下的页面有
Home,Register,Login,About,PaitentRecordException,SecurityException
patientrecord模块下的页面有
Browser,Create,AddTreatment,AddExamination,AddOperation,AddOperationVisit,AddOperationVisit,AddComment
我需要将这些页面归档,所以对应home子模块有Home.libray,对应于patientrecord
有PatientRecord.library
Home.library的位于com.ht.home包下,
PatientRecord.library位于com.ht.patientrecord包下
他们分别为
Home.library
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<library-specification>
<!-- Library Section-->
<library id="contrib" specification-path="/org/apache/tapestry/contrib/Contrib.library"/>
<library id="common" specification-path="/com/ht/components/Common.library"/>
<!-- Add more libraries here.-->
<!-- End of Library Section-->
<page name="Home" specification-path="Home.page"/>
<page name="Register" specification-path="Register.page"/>
<page name="Login" specification-path="Login.page"/>
<page name="About" specification-path="About.page"/>
<page name="PaitentRecordException" specification-path="PRException.page"/>
<page name="SecurityException" specification-path="SecurityExceptionPage.page"/>
</library-specification>
PatientRecord.library
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<library-specification>
<!-- Library Section-->
<library id="contrib" specification-path="/org/apache/tapestry/contrib/Contrib.library"/>
<library id="common" specification-path="/com/ht/components/Common.library"/>
<!-- Add more libraries here.-->
<!-- End of Library Section-->
<page name="Browser" specification-path="Browser.page"/>
<page name="Create" specification-path="Create.page"/>
<page name="AddTreatment" specification-path="AddTreatment.page"/>
<page name="AddExamination" specification-path="AddExamination.page"/>
<page name="AddOperation" specification-path="AddOperation.page"/>
<page name="AddOperationVisit" specification-path="AddOperationVisit.page"/>
<page name="AddComment" specification-path="AddComment.page"/>
</library-specification>
最后我们再看一下patientrecord.application这个Tapestry Web 应用核心配置文件:
patientrecord.application
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"
http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd>
<application name="Patient Record System" engine-class="com.ht.web.PatientRecordEngine">
<property name="org.apache.tapestry.visit-class" value="com.ht.web.VisitorState"/>
<property name="com.ht.home-page" value="home:Home"/>
<!--<property name="com.ht.exception-page" value="home:PaitentRecordException"/>-->
<property name="com.ht.security-exception-page" value="home:SecurityExceptionPage"/>
<!--Overrided the Home Service to let us to decide which page will be the home page-->
<service name="home" class="com.ht.web.HomeService"/>
<library id="home" specification-path="/com/ht/home/Home.library"/>
<library id="patientrecord" specification-path="/com/ht/patientrecord/PatientRecord.library"/>
</application>
看看最后两行
<library id="home" specification-path="/com/ht/home/Home.library"/>
<library id="patientrecord" specification-path="/com/ht/patientrecord/PatientRecord.library"/>
我们把那两个libary文件包含进来了,分别对应id为home, patientrecord
,我们要在程序里激活Home页,则只需
得一个IRequestCycle对象cycle
cycle.activate("home:Home");
注意“home:Home“,前一个home是library name,后一个是Page name.这是Tapestry
自定义的名字访问法则。
以上,是我开发Tapestry Web Application的一点心得体会,欢迎讨论批评.
msn:hery1977@hotmail.com
QQ:15520929