创建Tapestry框架页面
第三部分: 创建 Tapestry page 和 HTML 模版 - 介绍如何在AppFuse 项目中创建 Tapestry页面和模版。
- 这个指南依赖于 第二部分: 创建新的 Managers 对象。
说明
这个指南将会告诉你如何创建 Tapestry 页面和 HTML 模版。同时也将说明如何编写 JUnit 测试以测试PersonForm页面。我们创建的这个JSP页面将会使用我们在”创建Managers类“ 指南创建的PersonManager类。在大多数的web框架(web frameworks)中,控制逻辑都写在一个类似"Action" 的类中。但是在Tapestry中,这些控制逻辑通常可以以类似"Page"的方式被引用。使用这些pages的方法被称为listeners。这份指南不会讲述关于Tapestry工作机制的问题,但是会知道你快速上手使用Taperstry框架。如果你希望跟深入的学习Taperstry的有关知识,我建议你阅读Howard Lewis Ship'的 Tapestry in Action一书。当我在把Tapersty集成到Appfuse的过程中就把这部书放在身边以便随时查阅。感谢Howard的帮助!
-
我将以斜体字说明在 实际过程 使用的经验。
现在让我们开始在Appfuse's的整体架构下创建新的页面和HTML模版。如果你此时还没有安装Tapestry模块,请马上运行ant install-tapestry。
内容提要
- [1] 使用XDoclet创建 pageForm.html
- [2] 创建 PersonFormTest 以测试 PersonForm
- [3] 创建 PersonForm
- [4] 运行 PersonFormTest
- [5] 在你的浏览器中参看刚创建的PersonForm
- [6] 创建 Canoo WebTests 以模拟测试 PesonForm 对浏览器中操作的响应
使用XDoclet创建 pageForm.html 模版[#1]
在这一步,你将自动生成一个HTML模版以显示Person对象的信息。这个模版将包含符合Taperstry语法规则的待填充表单元素 - 就是那些HTML文件中带有"jwcid" 的属性。用来自动生成HTML模版的AppGen工具是基于 StrutsGen工具实现的 - 这个工具最初是由Erik Hatcher开发的。基本上是由一对Java类和一组XDoclet模版组成。这些文件都可以在extras/appgen目录下找到。
下面给出产生这个HTML模版文件和一个包含了form的标签元素的properties文件的具体步骤:
- 在命令行环境下,切换到 "extras/appgen" 目录
- 执行 ant -Dmodel.name=Person -Dmodel.name.lowercase=person 将在extras/appgen/build/gen目录下产生这组文件。事实上,它将产生你在完成这个向导所用到的所有文件。不过,我们现在仅仅抓住那些你需要的那些文件。
- web/WEB-INF/classes/Person.properties (表单元素的标签[label]字符串)
- web/pages/PersonForm.html (显示一个Person对象信息的HTML 模版文件)
- web/pages/PersonForm.page (说明前一页面的Page)
- web/pages/PersonList.html (显示一个People列表的HTML 模版文件)
- web/pages/PersonList.page (说明前一页面的Page)
- 把Person.properties文件中的内容拷贝到web/WEB-INF/classes/ApplicationResources_en.properties文件中。这些都是你在JSP页面中用来显示的titles/headings 和form属性对应的具体键-值对。下面是你需要在ApplicationResources_en.properties文件中新增的内容示例:
# -- person form -- personForm.id=Id personForm.firstName=First Name personForm.lastName=Last Name person.added=Person has been added successfully. person.updated=Person has been updated successfully. person.deleted=Person has been deleted successfully. # -- person list page -- personList.title=Person List personList.heading=Persons # -- person detail page -- personDetail.title=Person Detail personDetail.heading=Person Information
- 拷贝PersonForm.html 和 PersonForm.page 文件 到 web/pages/personForm.jsp 和 web/pages/personForm.page文件。拷贝PersonList.html和PersonList.page文件到web/pages/personList.jsp和web/pages/personList.page。请注意目标文件名的第一个字符是小写。
- 在 "pages" 目录下的文件将被罚不到"WEB-INF/pages"目录下。因为容器会为WEB-INF目录下的文件提供安全性保护。这意味着直接来自客户端的请求,而不是由 Tapestry's ApplicationServlet 发送的 forward请求,将无法访问对应的 JSP 页面。就是说把所有的 HTML 模版放在 WEB-INF 目录下将保证所有的 JSP 页面只能通过Taperstry的 Pages 来访问。这就允许把所有的安全性处理集中放到 Taperstry Page 中去,在那里可以得到更有效的处理,而不在需要在表示层中处理。
Appfsue的web应用程序安全性保证所有 *.html url-patterns 都是有保护的 (除了 /signup.html 和 /passwordHint.html), 这将保证客户端必须通过Page(Tperstry 框架页面条专逻辑控制器对应的 Page )来访问 template 文件。
body#pageName element.class { background-color: blue }
创建PersonFormTest以测试[#2]
要为PersonForm创建一个 Junit 测试,首先在 test/web/**/action 目录下创建一个 PersonFormTest.java 文件。
|
此时将不能通过编译因为你还没有创建被测试的 PersonForm 。
创建 PersonForm [#3]
在 src/web/**/action 目录下创建 PersonForm.java 文件,输入下面的内容:
|
你可能注意到在文件中使用了一组键(keys) - "person.deleted","person.added" 和 "person.updated"。所有的这些键值定义在你的 i18n 绑定文件(ApplicationResources_en.properties)中。你在这篇指南的开头应该已经添加了这部分内容。如果你希望在程序中改变这些基本信息,加入 person 的 name 或者其他内容,只需要在对应的信息内容中简单得添加一个 "{0}" 然后再程序中使用 setMessage(format(key, stringtoreplace)) 方法填充具体的内容。
你现在可能注意到了我们在这里调用 PersonManager 的代码和我们 PersonManagerTest 的相应代码是一样的。因为 PersonForm 和 PersonManagerTest 都是PersonManagerImpl 的客户 , 所以这是个优雅的结构。
现在你要告诉 Tapestry 这个 page 的存在了。你要做的是在 web/WEB-INF/tapestry.application 文件中加入 page 入口。
|
如果你把 HTML 模板文件保存在 WEB-INF 目录下,上面的步骤是不需要的。希望Taperstry未来的版本允许你设置全局路径。
- 这个从cancel(), delete() and save()方法 PersonForm 返回到 "MainMenu" 页面 。在下面的部分,你将把它改变成 PersonList 页面。
运行 PersonFormTest [#4]
你看 PersonFormTest 可以发现所有的测试依赖于数据库 person 表中一条 id=1 的纪录( testRemove 方法依赖于 id=2 的纪录 ),所以要在示例数据文件( metadata/sql/sample-data.xml )中加入这些纪录。我通常在文件的底部加入这些内容 - 这个顺序并不重要因为它和其他数据表没有任何关系。
<table name='person'> <column>id</column> <column>first_name</column> <column>last_name</column> <row> <value>1</value> <value>Matt</value> <value>Raible</value> </row> <row> <value>2</value> <value>James</value> <value>Davidson</value> </row> </table>
在运行所有的测试以前 DBUnit 会加载这些数据到数据库中,所以这些纪录对你的 Form 测试是可靠的。
保证你的项目中的文件都正确保存。那样你运行ant test-web -Dtestcase=PersonForm - 所有的事情就像你最初期望的那样。
Total time: 12 seconds
在浏览器中查看这个表单[#5]
现在执行 ant db-load deploy,启动 Tomcat 在浏览中输入 http://localhost:8080/appfuse/personForm.html ,你将看到如下的界面(略):
在 Tapestry 中,URLs 显得有点丑陋,不过他们包含了大量的信息。与其他的框架只需要你简单调用Action中的方法不一样, - 你需要调用 Page 类中的 listeners 。为了调用PrsonForm 对象中的 "edit" listener ,需要在 web/pages/mainMenu.html 文件中加入下面的代码。
<a jwcid="@DirectLink" listener="ognl:requestCycle.getPage('personForm').listeners.edit" parameters="ognl:new java.lang.Long(1)">Edit Person</a>
最后为了提高界面的用户友好性,你也许希望在表单的上方加入信息,这可以在 personForm.html 中前面使用 <span key="..."/> 加入所需要显示的信息。
[Optional] 创建一个Canoo WebTest 以模拟测试 PesonForm 对浏览器中操作的响应[#6]
最后一步(可选步骤)是创建一个 Canoo WebTest 测试这个 HTML 模板。
- 我之所以说着步骤是可选的,是因为你可以通过浏览器实现同样的操作。
你可以使用下面的步骤测试adding、editing 和 saving操作。
- Add - http://localhost:8080/appfuse/personForm.html.
- Edit - 使用你在 Main Menu 中创建的 URL ( 确保事先运行过 ant db-load )。
- Delete - 使用上面的 edit 链接点击 Delete 按钮。
- Save - 点击 Main Menu 中的 edit 链接 ( 如果你已经删除了纪录需要再次运行 ant db-load ) 然后点击 Save 按钮。
Canoo 测试相当灵活,只需要通过在一个XML文件中配置实现。为了增加 add, edit, save 和 delete 操作的测试,打开 test/web/web-tests.xml 文件并且加入下面的XML。你可以看到一个命名为 PersonTests 目标的片断可以运行所有相关的测试。
- 我使用 CamelCase 命名 target ( 不同于传统的小写字母中线分割的命名方法 ) 因为你测试时要输入-Dtestcase=Name ,我发现我习惯使用 CamelCase 命名我的单元测试。
|
完成了前面的操作后,你可以在Tomcat运行的状态下运行 ant test-canoo -Dtestcase=PersonTests; 也可以在没有 Tomcat 运行的情况下运行 ant test-html -Dtestcase=PersonTests , Ant 会启动启动/停止 Tomcat。为了在运行所有 Canoo 测试的时候能够包括 PersonTests, 在"run-all-tests" target. 中加入对应的dependency。
你可能注意到Canoo测试没有客户端的日志记录。如果你想看看它到底做了什么,你可以在 web/WEB-INF/classes/log4j.properties 中加入 tweak the log4j settings 。
Total time: 27 seconds
下面的内容: 第四部分: 加入校验和列表页面 - 说明如何增加校验逻辑来使得 firstName 和 lastName 是必填字段。也将展示如何增加一个列表页面显示数据库中所有的person纪录。