分享
 
 
 

appfuse文档(六)--添加校验和菜单

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

添加校验和菜单

本章将向你展示怎样为personForm添加校验逻辑,使得firstName和lastName在页面上变成必填field,并且添加一个屏幕列表来显示数据库中所有人的记录。

这部分内容依赖于Part III: 创建Action和JSP

关于本章

本章将向你展示怎样使用Struts的Validator 为你的PersonForm对象添加校验逻辑(客户端和服务器端)。我们也会使用Display Tag Library 创建一个屏幕列表来显示数据库中所有的people。

内容

· [1] 为Person.java 添加XDoclet Validator标签

· [2] 检查和测试添加了校验的JSP

· [3] 为 DAO和Manager Test添加testGetPeople方法

· [4] 为DAO和Manager添加getPeople()方法

· [5] 为Action Test 添加testSearch() 方法

· [6] 为Action添加search方法

· [7] 创建personList.jsp和Canoo test

· [8] 为菜单(Menu)添加链接(Link)

为Person.java 添加XDoclet Validator标签

正常情况下,如果你想使用Struts的Validator,你必须用手写validation.xml文件。如果你不使用AppFuse, 你也必须在ApplicationResources_en.properties文件中配置Validator Plugin和error key。如果你想获得更多的信息,请参见Validation Made Easy Tutorial

我们要感谢Xdoclet,它使得这一切都变得很简单 – 你只需要为Person类添加几个@struts.validator标签。打开它 (src/dao/**/model/Person.java),然后修改getFirstName()和getLastName() 方法的JavaDoc,使它们包含 @struts.validator type="required" 标签。

/**

* @struts.validator type="required"

* @hibernate.property column="first_name" length="50"

*/

public String getFirstName() {

return this.firstName;

}

/**

* @struts.validator type="required"

* @hibernate.property column="last_name" length="50"

*/

public String getLastName() {

return this.lastName;

}

你还可以在这个标签里添加一个msgkey属性( attribute),它用来覆盖错误的默认消息的key。

@struts.validator type="required" msgkey="errors.required"

type="required"的默认的Key已经是errors.required了,所以我经常保留它做为默认值。这个key被定义在web/WEB-INF/classes/ApplicationResources_*.properties中。 你也许注意到:虽然XDoclet的文档 说应该把这些标签放在Setter部分,但我们放到了getter部分,这是因为模板文件(metadata/template/struts_form.xdt) 会将这些标签放在产生的PersonForm.java的Setter部分。

现在如果你保存Person.java,然后运行ant clean webdoclet,将会在目录build/你的项目名称/WEB-INF/下产生一个validation.xml文件. 它应该有一个为"personForm"使用的入口:

<form name="personForm">

<field property="firstName"

depends="required">

<arg0 key="personForm.firstName"/>

</field>

<field property="lastName"

depends="required">

<arg0 key="personForm.lastName"/>

</field>

</form>

在我们的PersonForm.jsp中可以使用客户端校验,我们在PersonForm.jsp文件的底部添加一个<html:javascript>标签和一些脚本。下面的内容是已经存在的(感谢viewgen) – 你只需要将它们从注释中放开,它们被注释的原因是:如果指定了一个Form的名字并且校验规则不存在,Validator将会抛出一个异常。

我个人认为这是一个 a bug ,但Struts的提交者们并不这样认为.

<html:javascript formName="personForm" cdata="false"

dynamicJavascript="true" staticJavascript="false"/>

<script type="text/javascript"

src="<html:rewrite page="/scripts/validator.jsp"/>"></script>

检查和测试添加了校验的JSP

现在你已经为你的Form配置了Validation,当这个Form在action-mapping中被配置后,并且设置了validate="true",这些校验规则将会生效。在上一章中, 我们为PersonAction添加"savePerson" action-mapping。这个action-mapping 的Xdoclet标签应该是这样的:

* @struts.action name="personForm" path="/savePerson" scope="request"

* validate="true" parameter="method" input="edit"

这样,只要web/pages

/personForm.jsp有<html:form action="savePerson">,当我们保存窗体时,校验将会生效。运行ant db-load deploy,启动Tomcat,然后浏览http://localhost:8080/appfuse/editPerson.html?id=1 。如果你删除了firstName和lastName field的值,然后单击save按钮,你应该会看到下面的JavaScript提示的警告:

如果你确定一切都真正的如同期望的那样工作后,你就可以关掉JavaScript以保证可以使用服务器端的校验可以正常使用。在 Mozilla Firebird (我喜欢的浏览器)中,这些很容易,只是到Tools → Options → Web Features,然后去掉"Enable JavaScript"。现在如果你清除field的值,然后保存,你会看到如下的界面:

如果你看不到上面的错误,那么可能你出现了下面的问题:

· 窗体显示保存成功,但firstName和lastName field是空的。

这是因为web/pages/personForm.jsp 中的<html:form>有 action="editPerson" – 你要改为action="savePerson"。

· 你单击了save,但出现了一个空白页面(blank page)。

你的"savePerson" forward的"input" attribute配置不正确,一定要保证它指向了一个local或者global action-forward。在这个例子中,它应该是 input="edit"(指向.personDetail tile的定义)。根据我的经验,input的值必须是一个forward,不能是一个指向action的path。

如果你只想使用服务器端校验(server-side validation(没有JavaScript)) ,你可以删除<html:form>的onsubmit属性(在 web/pages/personForm.jsp中) ,同时也要删除页面底部的Validator JavaScript标签:

<html:javascript formName="personForm" cdata="false"

dynamicJavascript="true" staticJavascript="false"/>

<script type="text/javascript"

src="<html:rewrite page="/scripts/validator.jsp"/>"></script>

为 DAO和Manager Test添加testGetPeople方法

为了创建一个List screen (也叫做master screen), 我们需要创建一个方法,这个方法将返回person 表中的所有记录,我们先为类PersonDAOTest和PersonManagerTest添加测试方法。我通常将这个方法命名为getEntities (如: getUsers),但你也可以使用getAll或者search这样的名字 – 这只是个人喜好问题。

打开test/dao/**/dao/PersonDAOTest.java然后添加testGetPeople方法:

public void testGetPeople() {

person = new Person();

List results = dao.getPeople(person);

assertTrue(results.size() > 0);

}

我把一个person对象传入getPeople的原因是将来可以使用person的某个(些)属性进行过滤。 是否在getPeople()方法中添加这个参数是可选的,但本篇文章在剩余部分都假设你已经这样做了。

现在打开 test/service/**/service/PersonManagerTest.java,然后添加 testGetPeople 方法:

public void testGetPeople() {

List results = mgr.getPeople(new Person());

assertTrue(results.size() > 0);

}

为了使这些测试类能够被编译通过, 你需要为类PersonDAO和接口PersonManager添加getPeople()方法,然后实现它们。

为DAO和Manager添加getPeople()方法

打开src/dao/**/dao/PersonDAO.java,然后添加getPeople()方法声明(method signature):

public List getPeople(Person person);

现在为src/service/**/service/PersonManager.java添加同样的方法声明。保存你的文件,然后为你的测试文件添加必要的import。下一步我们需要在我们的实现类中实现getPeople() 方法。 打开 src/dao/**/dao/hibernate/PersonDAOHibernate.java,然后添加下面的方法:

public List getPeople(Person person) {

return getHibernateTemplate().find("from Person");

}

你可能注意到这里没有用person参数做任何事情. 现在它只是一个占位符 – 将来你可能需要使用Hibernate's Query Language (HQL) or using Criteria Queries 来过滤它的属性值。

下面是一个使用 Criteria Query的例子:

Example example = Example.create(person)

.excludeZeroes() // exclude zero valued properties

.ignoreCase(); // perform case insensitive string comparisons

try {

return getSession().createCriteria(Person.class)

.add(example)

.list();

} catch (Exception e) {

throw new DataAccessException(e.getMessage());

}

return new ArrayList();

现在我们在src/service/**/impl/PersonManagerImpl.java 中实现getPeople() 方法:

public List getPeople(Person person) {

return dao.getPeople(person);

}

保存你的修改,下面的命令应该都可以执行:

· ant test-dao -Dtestcase=PersonDAO

· ant test-service -Dtestcase=PersonManager

如果一切都工作正常 – 那真是漂亮的工作! 现在你需要为Web层添加这个retrieve all 功能。

为Action Test 添加testSearch() 方法

打开test/web/**/action/PersonActionTest.java,然后添加如下方法:

public void testSearch() {

setRequestPathInfo("/editPerson");

addRequestParameter("method", "Search");

actionPerform();

verifyForward("list");

assertNotNull(getRequest().getAttribute(Constants.PERSON_LIST));

verifyNoActionErrors();

}

只有你在src/dao/**/Constants.java 文件中添加了PERSON_LIST变量后,这个类才能编译通过。

我一般会复制一个已经存在的类似的变量 – 如:USER_LIST.

/**

* The request scope attribute that holds the person list

*/

public static final String PERSON_LIST = "personList";

保存你修改的文件,因为PersonAction.search() 方法不存在,

所以你还不能运行ant test-web -Dtestcase=PersonAction。

为Action添加search方法

打开src/web/**/action/PersonAction.java,然后在文件顶部添加Xdoclet标签- 为list screen添加forward。

* @struts.action-forward name="list" path="/WEB-INF/pages/PersonFormList.jsp"

现在在PersonAction类的主题部分添加search方法。

我使用UserAction.search()作为这个方法的模板。

public ActionForward search(ActionMapping mapping, ActionForm form,

HttpServletRequest request,

HttpServletResponse response)

throws Exception {

if (log.isDebugEnabled()) {

log.debug("Entering 'search' method");

}

PersonManager mgr = (PersonManager) getBean("personManager");

List people = mgr.getPeople(null);

request.setAttribute(Constants.PERSON_LIST, people);

// return a forward to the person list definition

return mapping.findForward("list");

}

运行ant test-web -Dtestcase=PersonAction.

多漂亮啊!

BUILD SUCCESSFUL

Total time: 1 minute 26 seconds

创建personFormList.jsp(PersonList。jsp)和Canoo test

在目录web/pages 下应该已经有一个PersonFormList.jsp(PersonList.Jsp)文件了,如果没有你可以使用viewgen创建它。使用命令行,进入到目录extras/viewgen下,运行ant -Dform.name=PersonForm。这将会在目录extras/viewgen/build下产生一个PersonFormList.jsp(PersonList.Jsp)文件。

在目录web/pages下找到PersonFormList.jsp(PersonList.Jsp),打开。

这个文件的头部是一个 <bean:struts>标签,它将edit screen的 forward作为一个page范围的变量。这个"editPerson"应该已经有一个值了。(This should already have a value of "editPerson")

<%-- For linking to edit screen --%>

<bean:struts id="editURL" forward="editPerson"/>

将下面内容添加到metadata/web/global-forwards.xml,也是一个列表的视图。这样,它们就可以被包含到struts-config.xml文件中了。

(Add this to the metadata/web/global-forwards.xml, as well as one for viewing the list. This way, they will get included in our struts-config.xml file.)

<forward name="editPerson" path="/editPerson.html"/>

<forward name="viewPeople" path="/editPerson.html?method=Search"/>

你用来创建这个JSP的模板应该有一个对应硬编码的id属性的列。所以Xdoclet会把它添加2次。从PersonFormList.jsp(PersonList.Jsp)文件中删除下面的内容。

<display:column property="id" sort="true" headerClass="sortable"

titleKey="personForm.id"/>

如果你知道更改 extras/viewgen/src/List_jsp.xdt文件能够不包含这个列标签的办法,请告诉我。

你可能想去改变的另一件事情是:这个例子中产生的名字是"persons" ,它可能是people,在第31行附近,你应该可以看到下面的内容:

<display:setProperty name="paging.banner.items_name" value="persons"/>

更改为:

<display:setProperty name="paging.banner.items_name" value="people"/>

最后,在web/WEB-INF/classes/ApplicationResources_en.properties 文件中添加title 和heading的key (personList.title和personList.heading)。打开这个文件,然后添加下面的内容:

# -- person list page --

personList.title=Person List

personList.heading=All People

此时,你应该可以执行ant clean deploy,启动Tomcat,查看这个页面: http://localhost:8080/appfuse/editPerson.html?method=Search

现在我们已经有一个List Screen, 我们来修改这个添加或者删除了一个新Person后显示的页面。打开 src/web/**/action

/PersonAction.java,在save, delete和cancel方法中改变mapping.findForward("mainMenu")为下面这样:

return mapping.findForward("viewPeople");

你也需要改变test/web/**/action/PersonActionTest.java的testRemove方法的 verifyForward("mainMenu") 为verifyForward("viewPeople") 。最后,Canoo test的 "AddPerson"和"DeletePerson"需要被修改。打开test/web/web-tests.xml,然后在"AddPerson" target 部分更改如下内容:

<verifytitle stepid="Main Menu appears if save successful"

text="${webapp.prefix}${mainMenu.title}"/>

改为:

<verifytitle stepid="Person List appears if save successful"

text="${webapp.prefix}${personList.title}"/>

然后,在"DeletePerson" target部分,将下面的内容:

<verifytitle stepid="display Main Menu"

text="${webapp.prefix}$(mainMenu.title)"/>

更改为:

<verifytitle stepid="display Person List" text="${webapp.prefix}${personList.title}"/>

我们使用"viewPeople"代替"list",这样search方法将会被执行。这比使用指向PersonForm.jsp的简单的list (它是一个forward)要好。

我们要测试这个显示页是否工作,在test/web/web-tests.xml中创建一个新的JSP测试:

<!-- Verify the people list screen displays without errors -->

<target name="SearchPeople"

description="Tests search for and displaying all people">

<canoo name="searchPeople">

&config;

<steps>

&login;

<invoke stepid="click View People link" url="/editPerson.html?method=Search"/>

<verifytitle stepid="we should see the personList title"

text="${webapp.prefix}${personList.title}"/>

</steps>

</canoo>

</target>

我们在"PersonTests" target 中添加"SearchPeople" target,这样它将和其他与person相关的测试用例一起执行。

<!-- runs person-related tests -->

<target name="PersonTests"

depends="SearchPeople,EditPerson,SavePerson,AddPerson,DeletePerson"

description="Call and executes all person test cases (targets)">

<echo>Successfully ran all Person JSP tests!</echo>

</target>

现在我们可以运行ant test-canoo -Dtestcase=SearchPeople (或者:Tomcat没有运行时,我们执行ant test-jsp) 。

为菜单(Menu)添加链接(Link)

对于这个list的最后一步: 使用户可以看到add, edit和delete功能。最简单的办法是在web/pages/mainMenu.jsp文件中添加一个链接的列表:

NOTE: 不要使用mainMenu.jsp 中的其他的链接,这样可以保证JSP能够被其他的Web框架使用(如:Spring MVC、WebWork)。

[The other links in mainMenu.jsp don't use so this JSP can be shared among the various web framework implementations in AppFuse (如:Spring MVC and WebWork).]

<li>

<html:link forward="viewPeople">

<fmt:message key="menu.viewPeople"/>

</html:link>

</li>

在web/WEB-INF/classes/ApplicationResources_en.properties 中有一个条目: menu.viewPeople

menu.viewPeople=View People

另一种办法是:添加下面的内容到web/WEB-INF/menu-config.xml中:

[The other (more likely) alternative is that you'll want to add it to the menu. To do this, add the following to web/WEB-INF/menu-config.xml:]

<Menu name="PeopleMenu" title="menu.viewPeople" forward="viewPeople"/>

要保证<Menus> tag中有上面的XML代码,而不是在另一个<Menu>中。 然后添加这个心菜单到web/pages/menu.jsp – 现在它看起来应该是这样的:

<%@ include file="/common/taglibs.jsp"%>

<div id="menu">

<menu:useMenuDisplayer name="ListMenu" permissions="rolesAdapter">

<menu:displayMenu name="AdminMenu"/>

<menu:displayMenu name="UserMenu"/>

<menu:displayMenu name="PeopleMenu"/>

<menu:displayMenu name="FileUpload"/>

<menu:displayMenu name="FlushCache"/>

<menu:displayMenu name="Clickstream"/>

</menu:useMenuDisplayer>

</div>

现在你运行ant clean deploy,启动Tomcat,然后查看 http://localhost:8080/appfuse/mainMenu.html ,你应该可以看到下面的内容:

需要注意的是左边多了一个新的链接,它从mainMenu.jsp中获取,在右边的菜单中也多了一个新的链接,它从menu.jsp中获取。

这就是它!

恭喜你,至此,你已经完成了全部的使用AppFuse进行开发的流程!如果你成功的运行了上面的所有的测试用例,那我们现在开始真正的测试。停止Tomcat,运行ant clean test-all. 这将运行所有的工程中的单元测试. 提示:使用ant setup-db、 setup-tomcat、 test-all 可以很容易的对我们的系统雏形进行测试。另外,如果你正在寻找稳定性和健壮性的例子 - checkout Struts Resume.

多好的一天!

BUILD SUCCESSFUL

Total time: 2 minutes 31 seconds

如果你喜欢,你可以在这里下载我们这个指南中创建的文件。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有