Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences

Edit this page


Referenced by
Articles_zh
WebWorkActions_zh




JSPWiki v2.2.33

[RSS]


Hide Menu

ValidationAndListWebWork_zh


第四部分: 增加校验和列表页面 - 增加Person对象的校验逻辑保证firstName和lastName是必填字段并且加入列表页面显示数据库中所有的person纪录。

阅读这部分指南请先阅读 第三部分: 创建Webwork Action和JSP.

内容提要

这部分指南将向你展示如何使用Webwork的校验框架加入校验逻辑。并且将使用Display Tag Library标签库(Tag Library)创建列表页面显示数据库中的所有Person。
我会用这种格式说明我在 实际过程 中的操作。

目录

  • [1] 创建包含了校验规则了Person-validation.xml文件
  • [2] 查看加入了校验的JSP页面并且进行测试
  • [3] 在DAO、ManagerTest类中加入testGetPeople方法
  • [4] 在PersonDao和Manager类中增加 getPeople 方法
  • [5] 在Action Test中加入testSearch方法
  • [6] 在Action中加入search 方法
  • [7] 创建personList.jsp和Canoo test
  • [8] 在菜单中加入链接

创建包含了校验规则了Person-validation.xml文件 [#1]

为了利用WebWork校验框架实现数据校验有两件事情要做,第一是创建一个validation.xml文件,第二是在需要进行校验的action中加入一个校验interceptor引用。

WebWork允许两种类型的校验 —— per-action和model-based。因为所有的Action对Person引用都要使用相同的校验规则,所以本文将使用model-based类型的校验。

在src/dao/**/model目录下创建Person-validation.xml文件并加入下列内容:


<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN" 
  "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
<validators>
    <field name="person.firstName">
        <field-validator type="requiredstring">
            <message key="errors.required"/>
        </field-validator>
    </field>
    <field name="person.lastName">
        <field-validator type="requiredstring">
            <message key="errors.required"/>
        </field-validator>
    </field>
</validators>

在ApplicationResources_*.properties文件中的"errors.message" 键值使用字段的"name"属性以实现国际化。如果不需要提供对i18n的支持可以直接对<message>元素中指定显示内容。


errors.required=${getText(fieldName)} is a required field.

现在可以配置PersonAction使用visitor validation。为了实现这个目标,在PersonAction目录下创建一个PersonAction-validation.xml文件。加入下面的内容:


<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0//EN"     
    "http://www.opensymphony.com/xwork/xwork-validator-1.0.dtd">
<validators>
    <field name="person">
        <field-validator type="visitor">
            <param name="appendPrefix">false</param>
            <message/>
        </field-validator>
    </field>
</validators>

糟糕的是,WebWork没有提供一个透明机制读取Person-validation.xml文件并且标记在UI上标记哪个字段时必须的。AppFuse的Struts和Spring版本使用LabelTag实现了这个目标,不过他们也只是实现了一个普通的校验。我希望有人能够为WebWork提供相同的功能实现。同时JSP tags "required" 属性实际上没有对你所指定的校验规则作任何事情,仅仅是在加入对应的字段后面加入了一个星号而已。

注意: 在AppFuse里面提供的SpringObjectFactory的客户端model-based校验规则无法工作。并且我认为Webwork提供的客户端校验需要增加一些特性,例如:允许取消在一个对话框中显示所有的错误信息。因为这些原因在AppFuse+webwork环境中只使用了服务器端校验。如果你希望使用,你可以了解在这里了解更多 我使用客户端校验遇到的问题

当然,也可以使用per-action校验。只需要拷贝Person-validation.xml文件到"webapp.action"包中并且把它重命名为PersonAction-validation.xml。

为了使在"savePerson" 操作中我们新加入的校验规则发挥作用,我们要把原来在"validator"属性上的注释去掉。确定最后在web/WEB-INF/classes/xwork.xml文件的"savePerson" 部分包含以下内容:


<interceptor-ref name="validationStack"/>

说明:在Appfuse中使用的validationStack和WebWork自带的有些不同,更多的信息可以在WebWork's JIRA中查找。

查看加入了校验的JSP页面并且进行测试 [#2]

现在保存所有的文件。为了测试加入了校验后的JSP,运行ant db-load deploy,启动Tomcat并且在浏览器中输入 http://localhost:8080/appfuse/editPerson.html?id=1

如果删掉了firstName或者lastName字段的值并点击save按钮,你将看到错误提示信息:

ValidationAndList/validation-required-nojs.png

在DAO、ManagerTest类中加入testGetPeople方法 [#3]

为了创建一个List页面(或者说是master页面),我们需要穿件一个方法返回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);
    }

我在getPeople方法中传入一个person对象是想在以后方便加入过滤(filtering)处理 (基于person对象中的属性值)。在getPeople()方法中应该说明这个参数是可选的。

现在打来test/service/**/service/PersonManagerTest.java文件加入 testGetPeople 方法。


    public void testGetPeople() throws Exception {
        List results = new ArrayList();
        person = new Person();
        results.add(person);

        // set expected behavior on dao
        personDao.expects(once()).method("getPeople")
            .will(returnValue(results));

        List people = personManager.getPeople(null);
        assertTrue(people.size() == 1);
        personDao.verify();
    }

为了这两个类能够通过编译,需要在PersonDao和PersonManager接口中加入getPeople()方法并且加入实现。

在PersonDao和Manager类中增加 getPeople 方法 [#4]

打开src/dao/**/dao/PersonDao.java文件并且加入getPeople()方法说明:


    public List getPeople(Person person);

现在在src/service/**/service/PersonManager.java文件中加入同样的方法。保存所有的文件并且在tests类中调整imports类。接下来在实现类中实现getPeople()方法。打开src/dao/**/dao/hibernate/PersonManager.java文件加入下面的代码:


    public List getPeople(Person person) {
        return getHibernateTemplate().find("from Person");
    }

你可以注意到现在没有对person参数作任何处理。仅仅是占了个位置 —— 在以后你可以依靠它的属性值使用Hibernate's查询语言 (HQL) 或者使用 Criteria Queries加入filter。 一个使用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层加入读取所有人员信息的功能实现了。

在Action Test中加入testSearch方法 [#5]

打开test/web/**/action/PersonActionTest.java文件加入下面的方法:


    public void testSearch() throws Exception {
        assertNull(action.getPeople());
        assertEquals(action.list()"success");
        assertNotNull(action.getPeople());
        assertFalse(action.hasActionErrors());
    }

只有在PersonAction中加入 getPeople()list() 方法这个类才能通过编译。

在Action中加入list()和getPeople()方法 [#6]

打开src/web/**/action/PersonAction.java 加入list() 方法。在此之前加入"people"变量和 getPeople() 方法。
我使用 UserAction.search() 作为模板编写这个方法的代码。


    private List people;

    public List getPeople() {
        return people;
    }
    
    public String list() {
        people = personManager.getPeople(new Person());

        return SUCCESS;
    }

运行 ant test-web -Dtestcase=PersonAction 进行测试。 好!
BUILD SUCCESSFUL
Total time: 10 seconds

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

打开web/pages目录下的personList.jsp文件进行编辑。在文件顶部有一个<ww:set>标签用来展示 "people" 信息。你需要把这个引用的值从"persons" 改成 "people"。


<ww:set name="personList" value="people" scope="request"/>

另一个你需要改变的地方是表单上的人的复数形式单词。示例程序产生的名字是 "persons" 这个正确的表示方法是 "people"。在大约30行的位置,你可以找到下面这一行

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

改变成:

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

最后在to web/WEB-INF/classes/ApplicationResources_en.properties文件中加入title和heading 键值 (personList.title和 personList.heading) :

# -- person list page --
personList.title=Person List
personList.heading=All People
需要注意的是,personList.title将会出现在浏览器的标题栏中,而personList.heading将会显示在页面中作为标题:

还要在在web/WEB-INF/classes/xwork.xml文件中加入一个新的"people" action 一边能够在URL中调用list()方法:


    <action name="people" class="personAction" method="list"
        <result name="success">/WEB-INF/pages/personList.jsp</result> 
    </action>

这时可以运行ant clean deploy, 启动Tomcat把浏览器转到http://localhost:8080/appfuse/people.html查看这个显示列表的页面了 At this point, you should be able to run ant clean deploy, start Tomcat and view this page in your browser at http://localhost:8080/appfuse/people.html.

现在有了一个列表显示页面,让我们改变在新增和删除了一个Person后显示这个页面。在web/WEB-INF/classes/xwork.xml文件中,改变 savePersons的 "input" 和 "success" 结果指向"people.html"。 你还需要改变Canoo tests "AddPerson" 和 "DeletePerson" 任务脚本 。打开 test/web/web-tests.xml 文件定位到 "AddPerson" 任务中下面这一行:

<verifytitle description="Main Menu appears if save successful" 
    text=".*${mainMenu.title}.*" regex="true"/>

修改成:

<verifytitle description="Person List appears if save successful" 
    text=".*${personList.title}.*" regex="true"/>

然后定位到 "DeletePerson" 任务的下面这一行:

<verifytitle description="display Main Menu" 
    text=".*$(mainMenu.title}.*" regex="true"/>

修改成:

<verifytitle description="display Person List" text=".*${personList.title}.*" regex="true"/>

为了测试列表页面的工作,在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">
        <webtest name="searchPeople">
            &config;
            <steps>
                &login;
                <invoke description="click View People link" url="/people.html"/>
                <verifytitle description="we should see the personList title" 
                    text=".*${personList.title}.*" regex="true"/>
            </steps>
        </webtest>
    </target>

你也许希望加入 "SearchPeople" 测试任务到 "PersonTests" 测试任务中去,以便能够和其他相关测试对象一起被测试。


    <!-- 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 (或者运行 ant test-jsp 如果Tomcat没有运行)。如果结果是"BUILD SUCCESSFUL"就大功告成了!

在菜单中加入链接 [#8]

最后一步把list, add, edit和delete功能显示给用户访问最简单的办法是在web/pages/mainMenu.jsp文件中加入新的链接:


    <li>
        <a href="<c:url value="/people.html"/>"><fmt:message key="menu.viewPeople"/></a>
    </li>

menu.viewPeople是定义在web/WEB-INF/classes/ApplicationResources_en.properties中的一个键。

menu.viewPeople=View People

另一个办法是改变web/WEB-INF/menu-config.xml加入下面的内容:


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

确定上面的XML在 <Menus> 标签内,但是没有在另外一个<Menu>里面。然后在web/common/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 ,你可以看到下面的界面

ValidationAndList/new-menu-item.png

注意在页面左边有一个新的链接(由 mainMenu.jsp产生) ,同时在右边的菜单上也有一个新链接(由 menu.jsp产生)。

就是这样

现在已经完成了一个完整的master-detail的页面开发过程!现在可以运行所有的测试而看不到任何错误了!可以进行全面的测试, 停止tomcat并且运行 ant clean test-all。 这个命令会运行工程里面所有的单元测试。需要提醒注意的是,应该可以正常的利用ant setup-db setup-tomcat test-all 来完成AppFuse程序的环境设置和全面测试。此时你可以参考一些更复杂的示例程序 - Struts Resume.

多么美好的一天!

BUILD SUCCESSFUL
Total time: 4 minutes 15 seconds


Go to top   Edit this page   More info...   Attach file...
This page last changed on 06-Nov-2006 13:52:59 MST by MichaelDuan.