This is version 2.
It is not the current version, and thus it cannot be edited.
[Back to current version]
[Restore this version]
Part III: 创建Actions和JSPs - 在AppFuse架构下创建Struts 的Actions和JSPs。
- 本教程依赖于Part II: 创建管理器Manager。
关于本教程
本教程将向你展示如何创建一个Struts Action,一个JUnit Test(使用 StrutsTestCase ),和一个form的JSP,我们创建的这个Action将与教程创建管理器Manager创建的PersonManager交互。
通常情况下,AppFuse使用Struts 作为它的web框架,作为1.6+,你可以使用Spring 或者WebWork 作为web框架,在1.7, 增加了对JSF 和Tapestry 的支持。
如果希望安装struts以外的web框架,只需转到extras目录下你所期望安装的框架目录下,在相应目录下的README.txt文件会有进一步的说明,针对其他几个框架的教程列在下面。
让我们从创建一个新的Struts Action和JSP作为开始。
- 我在真实世界中实际操作的方式用蓝色斜体表示。
目录
- 为创建generate PersonForm对Person添加XDoclet Tags
- 使用XDoclet创建骨架JSPs
- 创建测试PersonAction的PersonActionTest
- 创建PersonAction
- 运行PersonActionTest
- 清理JSP来使它更好看
- 创建Canoo WebTests来测试模拟浏览器的actions
我们首先在web层为Struts创建PersonForm对象,为此,我们需要对Person.java添加标签来产生我们的Struts ActionForm,在Person.java的JavaDoc添加@struts.form标签(如果你需要一个实例,可以参考User.java):
* @struts.form include-all="true" extends="BaseForm"
|
- 我们扩展org.appfuse.webapp.form.BaseForm,因为它的方法toString()中会调用log.debug(formName)来打印易读的Form信息。
- 如果你没有把"org.appfuse"包换成你的"com.company"或者没有把你的模型类放到默认的包,你必须确认在@struts.form中的标签对org.appfuse.webapp.form.BaseForm使用完全的引用。
使用XDoclet创建骨架JSPs
在这一步,你将会创建来显示Person对象信息的JSP页面,它会包括Strut的JSP标签用来表现Person.java每一个属性,AppGen工具建立在一个StrutsGen工具上,用来做这件事,这个StrutsGen工具起初由Erik Hatcher 编写,它只是一些XDoclet模版和一些附加类,所有的这些文件在extras/appgen目录里。
以下是生成JSP和包含标签及表单元素属性文件的简单步骤
- 在命令行环境下,转到"extras/appgen"目录
- 执行ant -Dobject.name=Person -Dappgen.type=pojo会在extras/appgen/build/gen产生一些文件,事实上,它会产生本教程所需的所有文件,但是我们只获取我们所需要的那些。
- web/WEB-INF/classes/Person.properties (form元素的标签)
- web/personForm.jsp (察看单个文件的JSP文件)
- web/personList.jsp (察看People列表的JSP文件)
- 把Person.properties的内容拷贝到web/WEB-INF/classes/ApplicationResources_en.properties,这是所有form中需要的标题关键字,以下是你将要添加到ApplicationResources_en.properties的内容的例子:
# -- person form --
personForm.id=Id
personForm.firstName=First Name
personForm.lastName=Last Name
person.added=Information for <strong>{0}</strong> has been added successfully.
person.updated=Information for <strong>{0}</strong> has been updated successfully.
person.deleted=Information for <strong>{0}</strong> 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.jsp到web/pages/personForm.jsp,拷贝personList.jsp到web/pages/personList.jsp,注意,所有新建文件的第一个字母是小写的。
- "pages"目录中的文件在部署环境下会放到"WEB-INF/pages"目录下,容器会对所有WEB-INF目录下的文件提供安全保护,这种保护针对客户端的请求,而通过Struts ActionServlet的转发可以访问,把这些JSPs文件放到WEB-INF目录下确保它们只会被Actions访问,而不会被客户或者彼此直接访问,这允许安全保护转移到Action,这样可以保证保护更有效,脱离表示层这个基础。
AppFuse的web应用安全机制确认所有的*.html形式的访问是被保护的(除了/signup.html和/passwordHint.html),这保证了客户必须通过Action来访问JSP(或者至少pages中的一些)。
注意:如果你想为某一页定制CSS,你必须在文件的开头添加<body id="pageName"/>,这会被SiteMesh看到并且应用到最终的页面,然后你可以一页一页的定制你的CSS,就像如下的方式:
body#pageName element.class { background-color: blue }
- 在ApplicationResources_en.properties中添加JSP文件出现的标题和题头,在生成的JSPs里有两处标题(浏览器顶端显示)的关键字,这些字段提供了personDetail.title和personDetail.heading关键字名。
如上,我们在文件里添加"personForm.*"关键字,我们为什么使用personDetail而不是personForm作为标题呢?最好的一个原因是我们需要区分form的标签和页面上的文本,另一个原因是*Form.*的形式给你数据库里所有的字段更好的展现形式。
最近我有一个客户期望数据库里的所有字段是可查询的,这样作就会比较容易,我只需要查看ApplicationResources.properties中的保存的所有关键字来寻找"Form.",然后记录下来,在用户界面下,用户只需要输入想查找的项目和字段。我对能够在项目里区分对待Form和Detail感到高兴!
创建测试PersonAction的PersonActionTest
为了给PersonAction创建StrutsTestCase Test,首先要在test/web/**/action目录下创建PersonActionTest.java文件:
package org.appfuse.webapp.action;
import org.appfuse.Constants;
import org.appfuse.webapp.form.PersonForm;
public class PersonActionTest extends BaseStrutsTestCase {
public PersonActionTest(String name) {
super(name);
}
public void testEdit() throws Exception {
setRequestPathInfo("/editPerson");
addRequestParameter("method", "Edit");
addRequestParameter("id", "1");
actionPerform();
verifyForward("edit");
assertTrue(request.getAttribute(Constants.PERSON_KEY) != null);
verifyNoActionErrors();
}
public void testSave() throws Exception {
setRequestPathInfo("/editPerson");
addRequestParameter("method", "Edit");
addRequestParameter("id", "1");
actionPerform();
PersonForm personForm =
(PersonForm) request.getAttribute(Constants.PERSON_KEY);
assertTrue(personForm != null);
setRequestPathInfo("/savePerson");
addRequestParameter("method", "Save");
// update the form from the edit and add it back to the request
personForm.setLastName("Feltz");
request.setAttribute(Constants.PERSON_KEY, personForm);
actionPerform();
verifyForward("edit");
verifyNoActionErrors();
}
public void testRemove() throws Exception {
setRequestPathInfo("/editPerson");
addRequestParameter("method", "Delete");
addRequestParameter("id", "2");
actionPerform();
verifyForward("mainMenu");
verifyNoActionErrors();
}
}
|
Attachments:
|