一、 开发环境设置
1、下载
1) 从http://java.sun.com下载稳定版本的JDK。
2) 从http://java.sun.com下载稳定版本的J2EESDK。
3) 从http://ant.apache.org 下载1.6版本的ant工具。
4) 从 http://www.mysql.com 下载MySQL数据库。
2、安装
创建 Tools 和 SDKs 目录在windows下如:c:\Tools c:\SDKs。在*nix下,如:/opt/dev/tools opt/dev/sdks
1) 创建环境变量 SDKS_HOME 和TOOLS_HOME。
2) 安装tomcat 到Tools目录
3) 安装ant到Tools目录
4) 安装MySQL到Tools目录
5) 创建Source目录,用来放置工程源码。如果在*nix系统下,则创建/dev到你的/home下
一般如下图:
SDKs -
- j2sdk-1.4.2_05
Tools -
- apache-ant-1.6.2
- jakarta-tomcat-5.0.28
- mysql
Source
3、配置
设置一下环境变量
l HOME = c:\Source
l SDKS_HOME = c:\SDKs
l TOOLS_HOME = c:\Tools
l JAVA_HOME = %SDKS_HOME%\j2sdk-1.4.2_05
l ANT_HOME = %TOOLS_HOME%\apache-ant-1.6.2
l CATALINA_HOME = %TOOLS_HOME%\jakarta-tomcat-5.0.28
l MYSQL_HOME = %TOOLS_HOME%\mysql
l PATH: %JAVA_HOME%\bin;%ANT_HOME%\bin;%CATALINA_HOME%\bin;%MYSQL_HOME%\bin
一、 开发流程
1、创建DAO和数据映射对象
主要任务:
[1] 创建一个新对象并且加入XDoclet标签
[2] 利用ant从该对象建立一个数据库表
[3] 创建一个DAOTest,运行JUnit来测试DAO
[4] 创建一个DAO,实现对该对象的CRUD(添加、删除、更新)操作
[5] 在Spring中配置Person object 和 PersonDAO
[6] 运行DAOTest
首先我们需要创建一个Person对象。
package org.appfuse.model;
public class Person extends BaseObject { private Long id; private String firstName; private String lastName;
/* Generate your getters and setters using your favorite IDE: In Eclipse: Right-click -> Source -> Generate Getters and Setters */ }
|
这个类扩展基类BaseObject。基类具备equals(), hashCode() ,toString() 三个方法,hibernate组件需要使用这些方法。
创建以后,我们需要添加XDoclet标签来生成Hibernate Map File。Hibernate map object – tables -- columns
增加@hibernate.class 到代码
/** * @hibernate.class table="person" */ public class Person extends BaseObject {
|
增加XDoclet标签来生成主键
/** * @return Returns the id. * @hibernate.id column="id" * generator-class="increment" unsaved-value="null" */
public Long getId() { return this.id; }
|
利用ant从object建立数据库表
利用命令 ant setup-db来建立数据库表。这个命令可以建立Person.hbm.xml文件和数据库表Person。
[schemaexport] create table person (
[schemaexport] id bigint not null,
[schemaexport] primary key (id)
[schemaexport] );
Person.hbm.xml文件在build/dao/gen/**/hibernate 目录下可以找到。你可以在那里发现该文件内容为:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping> <class name="org.appfuse.model.Person" table="person" dynamic-update="false" dynamic-insert="false" >
<id name="id" column="id" type="java.lang.Long" unsaved-value="null" > <generator class="increment"> </generator> </id>
<!-- To add non XDoclet property mappings, create a file named hibernate-properties-Person.xml containing the additional properties and place it in your merge dir. -->
</class>
</hibernate-mapping>
|
现在我们加入@hibernate.property属性,来生成数据表的列。
/** * @hibernate.property column="first_name" length="50" */ public String getFirstName() { return this.firstName; }
/** * @hibernate.property column="last_name" length="50" */ public String getLastName() { return this.lastName; }
|
运行 ant setup-db 命令来生成数据库
[schemaexport] create table person (
[schemaexport] id bigint not null,
[schemaexport] first_name varchar(50),
[schemaexport] last_name varchar(50),
[schemaexport] primary key (id)
[schemaexport] );
你可以通过修改property 的其他属性来订制列。
由于采用测试驱动开发方法,所有下面首先建立 DAOTest。该测试类建立在test/dao/**/dao目录下。我们采用Spring框架来组装DAO。
package org.appfuse.dao;
import org.appfuse.model.Person; import org.springframework.dao.DataAccessException;
public class PersonDAOTest extends BaseDAOTestCase { private Person person = null; private PersonDAO dao = null;
protected void setUp() throws Exception { super.setUp(); dao = (PersonDAO) ctx.getBean("personDAO"); }
protected void tearDown() throws Exception { super.tearDown(); dao = null; } }
|
该测试类扩展了BaseDAOTestCase类,具备了初始化方法。并且从Spring的ApplicationContext中得到类实例。
下面给这个测试类添加CRUD(create, retrieve, update, delete)方法。代码如下:
public void testGetPerson() throws Exception { person = new Person(); person.setFirstName("Matt"); person.setLastName("Raible");
dao.savePerson(person); assertNotNull(person.getId());
person = dao.getPerson(person.getId()); assertEquals(person.getFirstName(), "Matt"); }
public void testSavePerson() throws Exception { person = dao.getPerson(new Long(1)); person.setFirstName("Matt");
person.setLastName("Last Name Updated");
dao.savePerson(person);
if (log.isDebugEnabled()) { log.debug("updated Person: " + person); }
assertEquals(person.getLastName(), "Last Name Updated"); }
public void testAddAndRemovePerson() throws Exception { person = new Person(); person.setFirstName("Bill"); person.setLastName("Joy");
dao.savePerson(person);
assertEquals(person.getFirstName(), "Bill"); assertNotNull(person.getId());
if (log.isDebugEnabled()) { log.debug("removing person..."); }
dao.removePerson(person.getId());
try { person = dao.getPerson(person.getId()); fail("Person found in database"); } catch (DataAccessException dae) { log.debug("Expected exception: " + dae.getMessage()); assertNotNull(dae); } }
|
在测试时,有时会需要一些初始数据,这些初始数据可以在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>
</table>
建立DAO接口
package org.appfuse.dao;
import org.appfuse.model.Person;
public interface PersonDAO extends DAO { public Person getPerson(Long personId); public void savePerson(Person person); public void removePerson(Long personId); }
|
建立Hibernate的DAO实现类
package org.appfuse.dao.hibernate;
import org.appfuse.model.Person; import org.appfuse.dao.PersonDAO; import org.springframework.orm.ObjectRetrievalFailureException;
public class PersonDAOHibernate extends BaseDAOHibernate implements PersonDAO {
public Person getPerson(Long id) { Person person = (Person) getHibernateTemplate().get(Person.class, id);
if (person == null) { throw new ObjectRetrievalFailureException(Person.class, id); }
return person; }
public void savePerson(Person person) { getHibernateTemplate().saveOrUpdate(person); }
public void removePerson(Long id) { // object must be loaded before it can be deleted getHibernateTemplate().delete(getPerson(id)); } }
|
使用ant compile-dao来编译DAO类,使用ant test-dao –Dtestcase=PersonDAO来进行DAO的测试。DAO接口建立在src/dao目录下,DAOHibernate实现类建立在src/dao/hibernate目录下。
在Spring框架中配置Person类和PersonDAO。
在src/dao/**/dao/hibernate/applicationContext-hibernate.xml文件中进行如下配置:
<property name="mappingResources"> <list> <value>org/appfuse/model/Person.hbm.xml</value> <value>org/appfuse/model/Role.hbm.xml</value> <value>org/appfuse/model/User.hbm.xml</value> <value>org/appfuse/model/UserCookie.hbm.xml</value> </list> </property>
|
然后加入下列代码邦定Person.hbm.xml到PersonDAO对象。
<!-- PersonDAO: Hibernate implementation --> <bean id="personDAO" class="org.appfuse.dao.hibernate.PersonDAOHibernate"> <property name="sessionFactory"><ref local="sessionFactory"/></property> </bean>
|
如果为了简单你可以直接使用autowrie=”ByName”来直接生成xml文件中的内容。
现在运行测试可以得到正确的结果,那么你的DAO和Person对象创建成功!
2、创建服务
[1]创建一个新的ManagerTest
[2]创建一个新的Manager来调用DAO,处理业务逻辑
[3]在Spring中配置服务和事物管理
[4]运行服务测试
在上面我们已经创建了Person和PersonDAO,现在我们需要在test/service/**/service目录下创建ManagerTest。PersonManagerTest扩展BaseManagerTestCase类,在这个基类中实现了Spring配置文件的载入。
PersonManagerTest代码如下:
package org.appfuse.service;
import org.appfuse.model.Person; import org.springframework.dao.DataAccessException;
public class PersonManagerTest extends BaseManagerTestCase {
private Person person = null; private PersonManager mgr = null;
protected void setUp() throws Exception { super.setUp(); mgr = (PersonManager) ctx.getBean("personManager"); }
protected void tearDown() throws Exception { super.tearDown(); mgr = null; } }
|
然后加入具体的测试方法到PersonManagerTest类中:
public void testGetPerson() throws Exception { person = mgr.getPerson("1");
assertNotNull(person.getFirstName()); }
public void testSavePerson() throws Exception { person = mgr.getPerson("1"); person.setFirstName("test");
mgr.savePerson(person); assertEquals(person.getFirstName(), "test"); }
public void testAddAndRemovePerson() throws Exception { person = new Person(); person = (Person) populate(person);
mgr.savePerson(person); assertEquals(person.getFirstName(), "Bill"); assertNotNull(person.getId());
log.debug("removing person, personId: " + person.getId());
mgr.removePerson(person.getId().toString());
try { person = mgr.getPerson(person.getId().toString()); fail("Person found in database"); } catch (DataAccessException dae) { log.debug("Expected exception: " + dae.getMessage()); assertNotNull(dae); } }
|
下面创建一个PersonManager接口到src/service/**/service目录下。
package org.appfuse.service;
import org.appfuse.model.Person;
public interface PersonManager { public Person getPerson(String id); public void savePerson(Person person); public void removePerson(String id); }
|
接着创建一个PersonManager的实现类PersonManagerImpl到src/service/**/service/impl目录下:
package org.appfuse.service.impl;
import org.appfuse.model.Person; import org.appfuse.dao.PersonDAO; import org.appfuse.service.PersonManager;
public class PersonManagerImpl extends BaseManager implements PersonManager { private PersonDAO dao;
public void setPersonDAO(PersonDAO dao) { this.dao = dao; }
public Person getPerson(String id) { return dao.getPerson(Long.valueOf(id)); }
public Person savePerson(Person person) { dao.savePerson(person); }
public void removePerson(String id) { dao.removePerson(Long.valueOf(id)); } }
|
在上面代码中PersonDAO通过Spring框架中的配置来实例化。现在可以使用ant compile-service命令来编译服务对象。
在Spring中配置服务和事务管理
在src/service/**/service/applicationContext-service.xml文件中加入以下代码来注册服务:
<bean id="personManager" parent="txProxyTemplate"> <property name="target"> <bean class="org.appfuse.service.impl.PersonManagerImpl" autowire="byName"/> </property> </bean>
|
Parent属性的定义参考TransactionProxyFactoryBean。
3、创建Action和JSP页面
在这里我们使用Struts作为WEB框架,当然可以使用Spring MVC以及WebWork2来作为WEB层框架。
主要任务:
[1]加XDoclet标签到Person类中,这样可以方便的生成PersonForm
[2]使用XDoclet来创建JSP页面的主要代码。
[3]创建Action的测试以及Action类
[4]运行Action测试
[5]修改JSP页面,使其可以运行
我们现在通过在Person对象的代码中添加XDoclet来方便的生成PersonForm对象,以便在Struts当中使用。
* @struts.form include-all="true" extends="BaseForm"
|
在这里我们让PersonForm对象扩展BaseForm对象。
下面我们生成主要的JSP页面代码。
利用ant compile命令来编译Person类。这样就可以生成PersonForm类。
进入extras/viewgen目录下,运行命令 ant –Dform.name=PersonForm来生成主要的JSP代码。这是你可以在extras/viewgen/build目录下看到如下文件:
PersonForm.property(主要元素的Label)
PersonForm.jsp(表单页面)
PersonFormList.jsp(列表页面)
Copy PersonForm.property到web/WEB-INF/classes/ApplicationResources_zh.property文件中。
Copy PersonForm.jsp和PersonFormList.jsp到web/pages/目录下。
创建Action测试类:
我们利用StrutsTestCase可以创建Action的测试类。
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(); } }
|
我们添加PERSON_KEY到src/dao/**/Constants.java中,这个常量用来匹配form在Struts配置文件中的名称。
/** * The request scope attribute that holds the person form. */ public static final String PERSON_KEY = "personForm";
|
接下来,我们在src/web/**/action目录中创建Action
package org.appfuse.webapp.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.appfuse.model.Person;
import org.appfuse.service.PersonManager;
import org.appfuse.webapp.form.PersonForm;
/**
* @struts.action name="personForm" path="/editPerson" scope="request"
* validate="false" parameter="method" input="mainMenu"
*/
public final class PersonAction extends BaseAction {
public ActionForward cancel(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return mapping.findForward("mainMenu");
}
public ActionForward delete(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
if (log.isDebugEnabled()) {
log.debug("Entering 'delete' method");
}
ActionMessages messages = new ActionMessages();
PersonForm personForm = (PersonForm) form;
// Exceptions are caught by ActionExceptionHandler
PersonManager mgr = (PersonManager) getBean("personManager");
mgr.removePerson(personForm.getId());
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("person.deleted",
personForm.getFirstName() + ' ' +
personForm.getLastName()));
// save messages in session, so they'll survive the redirect
saveMessages(request.getSession(), messages);
return mapping.findForward("mainMenu");
}
public ActionForward edit(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
if (log.isDebugEnabled()) {
log.debug("Entering 'edit' method");
}
PersonForm personForm = (PersonForm) form;
// if an id is passed in, look up the user - otherwise
// don't do anything - user is doing an add
if (personForm.getId() != null) {
PersonManager mgr = (PersonManager) getBean("personManager");
Person person = mgr.getPerson(personForm.getId());
personForm = (PersonForm) convert(person);
updateFormBean(mapping, request, personForm);
}
return mapping.findForward("edit");
}
public ActionForward save(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
if (log.isDebugEnabled()) {
log.debug("Entering 'save' method");
}
// Extract attributes and parameters we will need
ActionMessages messages = new ActionMessages();
PersonForm personForm = (PersonForm) form;
boolean isNew = ("".equals(personForm.getId()));
if (log.isDebugEnabled()) {
log.debug("saving person: " + personForm);
}
PersonManager mgr = (PersonManager) getBean("personManager");
Person person = (Person) convert(personForm);
mgr.savePerson(person);
// add success messages
if (isNew) {
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("person.added",
personForm.getFirstName() + " " +
personForm.getLastName()));
// save messages in session to survive a redirect
saveMessages(request.getSession(), messages);
return mapping.findForward("mainMenu");
} else {
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("person.updated",
personForm.getFirstName() + " " +
personForm.getLastName()));
saveMessages(request, messages);
return mapping.findForward("edit");
}
}
}
在这里有时需要进行Person和PersonForm的转换,你可以使用ConvertUtil.convert() 或者 BeanUtils.copyProperties。
现在我们在Action文件的头部加入XDoclet标签,这样可以自动的生成Struts配置文件。
/** * @struts.action name="personForm" path="/editPerson" scope="request" * validate="false" parameter="method" input="mainMenu" * * @struts.action name="personForm" path="/savePerson" scope="request" * validate="true" parameter="method" input="edit" * * @struts.action-forward name="edit" path="/WEB-INF/pages/personForm.jsp" */ public final class PersonAction extends BaseAction {
|
在程序中可能还会需要在页面上显示其他的文字信息,那么这些信息应该加入到资源文件当中,例如:
person.added=Information for <strong>{0}</strong> has been added successfully.
person.deleted=Information for <strong>{0}</strong> has been deleted successfully.
person.updated=Information for <strong>{0}</strong> has been updated successfully.
现在可以运行Action的测试了。
如果Action测试运行成功,那么你可以修改JSP页面,使它符合你对界面的要求。
4、添加验证和列表页面
主要任务:
[1]添加验证标记到Person类中
[2]查看添加验证后的JSP页面,并且测试
[3]添加testGetPeople方法到DAO、Manager测试中
[4]添加testSerach方法到Action测试中
[5]在Action中添加Serach方法
[6]创建personFormList.jsp页面
[7]在菜单中添加链接
在Struts当中使用验证通常是将验证写到vaildtion.xml文件中,但是这样配置比较麻烦。我们现在使用XDoclet来自动生成这个验证配置文件。
在Person对象当中需要验证的字段的GET方法前加入验证标签,如下:
/** * @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。
@struts.validator type="required" msgkey="errors.required"
|
现在,你可以保存Person.java文件,然后运行 ant clean webdoclet命令来生成验证文件。
生成后的验证文件如下:
<form name="personForm"> <field property="firstName" depends="required">
<arg0 key="personForm.firstName"/> </field> <field property="lastName" depends="required">
<arg0 key="personForm.lastName"/> </field> </form>
|
而在jsp文件中,你可以看到如下的客户端验证代码:
<html:javascript formName="personForm" cdata="false"
dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript"
src="<html:rewrite page="/scripts/validator.jsp"/>"></script>
如果你希望使用服务器端验证方法,那么可以将上面的代码删除掉。
使用客户端验证的效果:
使用服务器端验证的效果:
加testGetPeople方法到PersonDAO和PersonManager测试方法当中。
打开PersonDAOTest.java文件,加入以下代码:
public void testGetPeople() { person = new Person(); List results = dao.getPeople(person); assertTrue(results.size() > 0); }
|
打开PersonManagerTest.java文件,加入以下代码:
public void testGetPeople() { List results = mgr.getPeople(new Person()); assertTrue(results.size() > 0); }
|
现在需要在DAO当中实现这样的方法:
public List getPeople(Person person);
|
在PersonManager中实现这样的方法:
public List getPeople(Person person) { return getHibernateTemplate().find("from Person"); }
|
在这里你可以看到区别。如果直接使用Hibernate的话,那么实现这样的一个功能至少需要有以下的代码:
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();
|
而现在代码的数量减少了很多。只有下面的一句就可以。
public List getPeople(Person person) { return dao.getPeople(person); }
|
在完成上述操作之后,我们可以运行下面的语言来进行编译和测试:
ant test-dao -Dtestcase=PersonDAO
ant test-service -Dtestcase=PersonManager
添加testSerach方法到Action的测试类中。
打开personActionTest.java加入下列代码:
public void testSearch() { setRequestPathInfo("/editPerson"); addRequestParameter("method", "Search"); actionPerform();
verifyForward("list");
assertNotNull(getRequest().getAttribute(Constants.PERSON_LIST)); verifyNoActionErrors(); }
|
现在这个类还无法被编译,因为你没有将PERSON_LIST加入到Constants.java文件中。
/** * The request scope attribute that holds the person list */ public static final String PERSON_LIST = "personList";
|
下面在Action中加入Serach方法。
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来进行测试。
建立列表页面。
将原来已经生成的PersonFormList.jsp拷贝到web/pages/目录下,修改其中的代码以便使其适合你的要求。
现在需要在metadata/web/global-forwards.xml文件中注册一个全局转向,以便能找到你的Action。
<forward name="editPerson" path="/editPerson.html"/> <forward name="viewPeople" path="/editPerson.html?action=Search"/>
|
完成以后,我们将这个功能加到菜单链接里面。
打开web/pages/mainMenu.jsp文件,加入下列代码:
<li>
<html:link forward=
"viewPeople"
>
<fmt:message key=
"menu.viewPeople"
/>
</html:link>
</li>
在上面代码中的menu.viewPeople是菜单项的名称,你需要在资源文件中加入这个名称的本地语言。
然后打开web/WEB-INF/menu-config.xml文件,加入这个菜单的配置。
<Menu name="PeopleMenu" title="menu.viewPeople" forward="viewPeople"/>
|
在页面上加入这个新的菜单。打开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并且部署应用程序,这样你可以运行该程序。
4、添加验证和列表页面
主要任务:
[1]添加验证标记到Person类中
[2]查看添加验证后的JSP页面,并且测试
[3]添加testGetPeople方法到DAO、Manager测试中
[4]添加testSerach方法到Action测试中
[5]在Action中添加Serach方法
[6]创建personFormList.jsp页面
[7]在菜单中添加链接
在Struts当中使用验证通常是将验证写到vaildtion.xml文件中,但是这样配置比较麻烦。我们现在使用XDoclet来自动生成这个验证配置文件。
在Person对象当中需要验证的字段的GET方法前加入验证标签,如下:
/** * @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。
@struts.validator type="required" msgkey="errors.required"
|
现在,你可以保存Person.java文件,然后运行 ant clean webdoclet命令来生成验证文件。
生成后的验证文件如下:
<form name="personForm"> <field property="firstName" depends="required">
<arg0 key="personForm.firstName"/> </field> <field property="lastName" depends="required">
<arg0 key="personForm.lastName"/> </field> </form>
|
而在jsp文件中,你可以看到如下的客户端验证代码:
<html:javascript formName="personForm" cdata="false"
dynamicJavascript="true" staticJavascript="false"/>
<script type="text/javascript"
src="<html:rewrite page="/scripts/validator.jsp"/>"></script>
如果你希望使用服务器端验证方法,那么可以将上面的代码删除掉。
使用客户端验证的效果:
使用服务器端验证的效果:
加testGetPeople方法到PersonDAO和PersonManager测试方法当中。
打开PersonDAOTest.java文件,加入以下代码:
public void testGetPeople() { person = new Person(); List results = dao.getPeople(person); assertTrue(results.size() > 0); }
|
打开PersonManagerTest.java文件,加入以下代码:
public void testGetPeople() { List results = mgr.getPeople(new Person()); assertTrue(results.size() > 0); }
|
现在需要在DAO当中实现这样的方法:
public List getPeople(Person person);
|
在PersonManager中实现这样的方法:
public List getPeople(Person person) { return getHibernateTemplate().find("from Person"); }
|
在这里你可以看到区别。如果直接使用Hibernate的话,那么实现这样的一个功能至少需要有以下的代码:
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();
|
而现在代码的数量减少了很多。只有下面的一句就可以。
public List getPeople(Person person) { return dao.getPeople(person); }
|
在完成上述操作之后,我们可以运行下面的语言来进行编译和测试:
ant test-dao -Dtestcase=PersonDAO
ant test-service -Dtestcase=PersonManager
添加testSerach方法到Action的测试类中。
打开personActionTest.java加入下列代码:
public void testSearch() { setRequestPathInfo("/editPerson"); addRequestParameter("method", "Search"); actionPerform();
verifyForward("list");
assertNotNull(getRequest().getAttribute(Constants.PERSON_LIST)); verifyNoActionErrors(); }
|
现在这个类还无法被编译,因为你没有将PERSON_LIST加入到Constants.java文件中。
/** * The request scope attribute that holds the person list */ public static final String PERSON_LIST = "personList";
|
下面在Action中加入Serach方法。
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来进行测试。
建立列表页面。
将原来已经生成的PersonFormList.jsp拷贝到web/pages/目录下,修改其中的代码以便使其适合你的要求。
现在需要在metadata/web/global-forwards.xml文件中注册一个全局转向,以便能找到你的Action。
<forward name="editPerson" path="/editPerson.html"/> <forward name="viewPeople" path="/editPerson.html?action=Search"/>
|
完成以后,我们将这个功能加到菜单链接里面。
打开web/pages/mainMenu.jsp文件,加入下列代码:
<li>
<html:link forward=
"viewPeople"
>
<fmt:message key=
"menu.viewPeople"
/>
</html:link>
</li>
在上面代码中的menu.viewPeople是菜单项的名称,你需要在资源文件中加入这个名称的本地语言。
然后打开web/WEB-INF/menu-config.xml文件,加入这个菜单的配置。
<Menu name="PeopleMenu" title="menu.viewPeople" forward="viewPeople"/>
|
在页面上加入这个新的菜单。打开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并且部署应用程序,这样你可以运行该程序。