Appfuse里面带的Ant任务列表

    使用Appfuse开发应用程序经常需要使用开发包中定义好的Ant 任务,这里是Ant 任务的详细说明:
 

任务名

说明

bin 

创建war程序包,jdbc驱动,和XML文件

checkstyle  

检查代码是否符合代码规范要求

clean 清除制作好的各种产品
compile compile-web的别名
compile-dao 编译dao模块
compile-service  编译service模块
compile-web 编译web模块
copy-resources 从原程序目录中拷贝.properties和.xml文件
copy-web-files       拷贝静态文件
db-create  创建 ${database.type}类型的数据库
db-drop  删除数据库表
db-export 导出当前数据库中的数据
db-load  把示例数据加载到数据库中
db-prepare 创建数据库表
deploy 把war程序包解包部署到应用服务器的目录中去
deploy-test-reports 把JUnit测试报告发布到服务器上
deploy-war 发布'${webapp.name}.war'到本地Tomcat服务器上
deploy-web 仅仅发布web的classes文件到servlet容器中去
tory  
dist 创建的一个压缩tar.gz文件,包含了全部路径和分发用的文件
docs 运行javadoc, todo, checkstyle和pmd tasks
ftp 通过FTPs上传分类文件到指定的服务器中
gen-tests-dao 为dao模块产生测试类
gen-tests-service 为模块产生测试程序
gen-tests-web  为web模块产生测试程序
hibernatedoclet  产生Hibernate映射文件
init  加入自定义任务
install  Tomcat安装应用
install-ibatis 安装iBATIS
install-springmvc 安装Spring's MVC,删除Struts
install-webwork 安装WebWork,删除Struts
java2html   创建HTML页面以便在线察看代码
javadoc  产生JavaDoc API文档
jsp-2 转换JSP 1.2 Tags (i.e. JSTL) 到JSP 2.0标准
list 列出所有Tomcat应用
new 创建一个新的用户命名的project
package-dao DAO打成一个单独的JAR包
package-web 应用程序打WAR包
ping-tomcat  pings tomcat确定tomcat还在运行
pmd  定位没有无用的imports语句,无用的variables,等等。
prepare  创建目标目录
refresh 清除原来的程序并重新发布
reload  在Tomcat重新加载应用程序
remove 移除Tomcat中的应用程序
setup 创建数据库,设置tomcat环境,发布解包应用程序
setup-db 创建数据库并且填充数据,会被许多其他任务调用
setup-tomcat 拷贝jdbc driver和context.xml到tomcat对应的目录下
stage-web  调用所有的其他任务搜集静态资源
start 启动Tomcat应用
start.tomcat  在当前控制台窗口下启动tomcat
stop 停止以一个Tomcat应用
test-all 运行一个POJO所有的测试包括dao, service, web和jsp
test-all-running 运行所有的DAOs, Services, Controllers和JSPs测试
test-canoo  运行Canoo WebTests 以在 Tomcat中测试JSP程序
test-dao  测试dao模块
test-jsp  使用Cargo运行Canoo WebTests
test-reports 产生测试报告
test-service 测试service模块
test-web 测试web模块
todo  创建代码中的todo任务报告
undeploy 删除、反安装一个发布好的 war文件
war package-web的别名
webdoclet 产生web开发描述
wiki 从wiki下载文件产生文档


 

Posted on July 14, 2006 12:32 PM | | Comments (0) | TrackBacks (0)

AppfuseMatt Raible 开发的一个指导性的入门级J2EE框架,它继承了流行的SpringHibernateibatisstrutsXdcoletjunit等基础框架,最新的1.7版更是提供了对TaperstryJSF的支持。在持久层,AppFuse采用了Hibernate O/R映射工具(http://www.hibernate.org);在容器方面,它采用了Spring Frameworkhttp://www.springframework.org)。用户可以自由选择StrutsSpring/MVCWebworkTaperstryJSF这几个web框架。采用TDD的开发方式,使用JUnit测试各层,甚至测试 jsp 输出的 w/o 错误。为了简化开发,预定义好了一套目录结构、基类、用来创建数据库、配置Tomcat、测试部署应用的 Ant 任务,帮助快速自动生成源程序和自动维护部分配置文件。

参考资料: 
      
在https://appfuse.dev.java.net/下载Appfuse
      Appfuse
的参考资料和文档可以在http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse查看。


Posted on July 14, 2006 12:30 PM | | Comments (0) | TrackBacks (0)

Appfuse开发实践(五)—— 增加校验和列表页面

      
      

 


内容提要

      本文将展示如何使用Webwork的校验框架加入校验逻辑。并且将使用Display标签库(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文件


       为了利用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" 属性实际上没有对你所指定的校验规则作任何事情,仅仅是在加入对应的字段后面加入了一个星号而已。

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

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


<interceptor-ref name="validationStack"/>

  

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


二、查看加入了校验的JSP并进行测试


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

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

 


三、在DAO和Manager Test中加入testGetPeople方法


        为了创建一个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() {
        List results 
= mgr.getPeople(new Person());
        assertTrue(results.size() 
> 0);
    }
  


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


四、在DAO和Manager加入getPeople()方法

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


     

public List getPeople(Person person);  

    

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


     

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

    
      你可以注意到现在没有对person 参数作任何处理。仅仅是占了个位置 —— 在以后你可以依靠它的属性值使用Hibernate's查询语言或者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()方法

      打开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()方法


      打开src/web/**/action/PersonAction.java 加入list() 方法。在此之前加入"people"变量和getPeople() 方法。

 

    

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测试


       现在在 web/pages目录下应该有了一个personList.jsp文件. If not, you can create it using viewgen. From the command-line, navigate to extras/viewgen and run ant -Dform.name=Person. This will generate a PersonList.jsp in extras/viewgen/build.

       打开web/pages目录下的personList.jsp文件进行编辑。

       在文件顶部有一个<ww:set>标签用来展示 "people" 信息。你需要把这个引用的值从"persons" 改成 "people"。


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

 

      用来创建JSP的模版针对id的属性列使用了硬编码,所以XDoclet加了两次。为了在personList.jsp移出它,在文件中删除下面的部分:


    

<display:column property="id" sort="true" headerClass="sortable"
        titleKey
="personForm.id"/>  


      如果有人知道办法修改extras/viewgen/src/List_jsp.xdt不再包括这个列的标签,请通知我。

      为了前后一致,可以把自动产生的"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:


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

 

      这时可以运行ant clean deploy, 启动Tomcat察看这个显示列表的页面了http://localhost:8080/myApp/people.html

      现在有了一个列表显示页面,让我们改变在新增和删除了一个Person后显示这个页面。在web/WEB-INF/classes/xwork.xml文件中,改变 savePersons的 "input" 和 "success" 结果指向"people.html"。

      同时需要改变 Canoo 测试中的 "AddPerson"和"DeletePerson"部分。打开test/web/web-tests.xml文件改变"AddPerson"目标中下面的行:

 

<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"目标中下面行的内容:

 

<verifytitle stepid="display Main Menu" 
    text
="${webapp.prefix}$(mainMenu.title}"/>

 

改变成:

 

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

 

     为了测试列表页面的工作,在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="/people.html"/>
                
<verifytitle stepid="we should see the personList title" 
                    text
="${webapp.prefix}${personList.title}"/>
            
</steps>
        
</canoo>
    
</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"就大功告成了!


八、在菜单上加入链接


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


    

<li>
        
<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> tag内,但是没有另外一个<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/myApp/mainMenu.html ,你可以看到下面的界面(图片略)。

 


现在已经完成了一个完整的master-detail的页面开发过程!现在可以运行所有的测试而看不到任何错误了!

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


       看这个部分的指南参考上一部分的指南:创建Webwork 框架的 Actions和JSP

Posted on July 14, 2006 12:29 PM | | Comments (0) | TrackBacks (0)

Appfuse开发实践(四)—— 创建Webwork 框架的 Actions和JSP



 

 

 

 


[1] 使用XDoclet创建JSP
[2] 创建PersonActionTest以便测试PersonAction
[3] 创建PersonAction对象
[4] 运行PersonActionTest
[5]  清理JSP文件并进行发布
[6] 创建Canoo WebTests模拟测试浏览器行为


一、使用XDoclet创建JSP

      在这一步,我们要创建JSP文件显示Person对象的信息。这个JSP将使用Webwork的JSP Tag来把Person.java中的每个属性填充到表格的行中。我们使用的这个工具是由Erik Hatcher开发的。他由一个类(FormTagsHandler.java) 和一对XDoclet模版(FormKeys.xdt and Form_jsp.xdt组成)。这些文件都在extras/viewgen目录下。

      产生一个表单元素和对应的标签属性文件只需经过下面几个基本步骤:

      命令行下面切换到"extras/viewgen"目录下 
      执行ant -Dform.name=Person任务 在extras/viewgen/build 目录下产生下面三个文件:

Person.properties (表单元素的标签)
PersonForm.jsp (显示一个Person信息的JSP文件)
PersonList.jsp (显示People列表的JSP文件)


     把Person.properties文件中的内容拷贝到web/WEB-INF/classes/ApplicationResources_en.properties文件中。下面是一个具体的Person.properties文件例子:


 

# -- person form --
person.firstName=First Name
person.id=Id
person.lastName=Last Name

 

      由于我们使用的是中文,需要把对应的信息填入web/WEB-INF/classes/ApplicationResources_cn.properties文件中,还要转化为Unicode编码。

      把PersonForm.jsp文件拷贝到web/pages/personForm.jsp目录下。把PersonList.jsp拷贝到web/pages/personList.jsp目录下。注意每个文件名的名字第一个字符是小写字符。


      "pages"目录下的文件在发布时将发布到"WEB-INF/pages"目录下。容器提供了WEB_INF目录下的所有文件的安全控制。这意味着来自客户端的请求,而不是由发过来的请求将不被相应。把所有的JSP文件放到WEB-INF目录下可以保证用户只能通过Actions来访问这些页面。这样就把系统安全性要求全部转移到Actions上,那里可以得到更高效的处理并且在基本的表示层外面。

AppFuse架构的web应用程序安全性保证了所有*.html文件得到了保护(除了/signup.html和/passwordHint.html文件)。这就保证了客户端必须通过Action才能访问JSP文件。


     说明: 如果自定义了CSS特殊页面,那么需要在文件的最上面加上<body id="pageName"/>。这样就可以被 SiteMesh 识别并且放到最终的页面中去。你也可以使用下面的语句一个一个页面的用CSS来定义页面的格式:

 

 

 

      在ApplicationResources_en.properties文件中加入对应JSP文件的titles和headings键值。

      在自动产生的JSP文件中,有两个键表示title (浏览器的顶端)和header (页面的头上)。我们需要在ApplicationResources_en.properties文件中说明这两个键的值(personDetail.title and personDetail.heading),具体内容如下所示:


 

# -- person detail page --
personDetail.title=Person Detail
personDetail.heading=Person Information

 


      在这上面我们要在文件中加入"personForm.*"键,为什么我们要使用personForm和personDetail这样的表示形式?最主要的原因是在页面的标签和文本信息有个明显的区别。另外一个原因是因为*Form.*这种形式可以很好的表示数据库中的字段信息。

      最近我有个客户希望所有数据库中的字段都可以查询。这个相当容易实现。我在ApplicationResources.properties 检查所有的包含"Form."的键并且把它放到下拉列表框中。在用户界面上,用户可以输入查询项并且选择想要查询的列。


二、创建PersonActionTest类测试PersonAction类

       为PersonAction创建一个JUnit测试类, 首先在test/web/**/action目录下创建PersonActionTest.java文件。


package org.myApp.webapp.action;

import org.springframework.mock.web.MockHttpServletRequest;

import com.opensymphony.webwork.ServletActionContext;

public class PersonActionTest extends BaseActionTestCase {
    
private PersonAction action;

    
protected void setUp() throws Exception {    
        super.setUp();
        action 
= (PersonAction) ctx.getBean("personAction");
    }

    
    
protected void tearDown() throws Exception {
        super.tearDown();
        action 
= null;
    }

    
    
public void testEdit() throws Exception {
        log.debug(
"testing edit");
        action.setId(
"1");
        assertNull(action.getPerson());
        assertEquals(action.edit(), 
"success");
        assertNotNull(action.getPerson());
        assertFalse(action.hasActionErrors());
    }


    
public void testSave() throws Exception {
        MockHttpServletRequest request 
= new MockHttpServletRequest();
        ServletActionContext.setRequest(request);
        action.setId(
"1");
        assertEquals(action.edit(), 
"success");
        assertNotNull(action.getPerson());
        
        
// update last name and save
        action.getPerson().setLastName("Updated Last Name");
        assertEquals(action.save(), 
"input");
        assertEquals(action.getPerson().getLastName(), 
"Updated Last Name");
        assertFalse(action.hasActionErrors());
        assertFalse(action.hasFieldErrors());