CreateManager_zh |
|
Your trail: |
Part II: 创建新的Manager - 创建与数据库端(DAOs)交互的业务Facades和事务处理。
- 本教程依赖于Part I:在AppFuse建立DAO和POJO .
关于本教程
本教程将会向你展示如何创建一个业务Facade类(和一个JUnit Test)与Part I里生成的DAO交互操作。
在AppFuse的语境下,这被称作一个Manager类,它的主要职责是持久户层(DAO)和web层之间的一个桥梁,它也很好的把展示层和数据库层(例如Swing应用)解耦,Managers必定是应用程序所有的业务逻辑所在的地方。
- 我在真实世界中实际操作的方式用蓝色斜体表示。
让我们从在AppFuse的框架下创建一个ManagerTest和Manager。
目录
- 创建一个新的运行JUnit测试的ManagerTest
- 创建一个新的与DAO通讯的Manager
- 为这个Manager和事务配置Spring
- 运行ManagerTest
创建一个新的运行JUnit测试的ManagerTest
在Part I,我们创建了一个Person对象和一个PersonDao对象 - 所以我们继续开发这个实体,首先,我们创建PersonManager的JUnit test,在test/service/**/service目录下创建PersonManagerTest,我们会希望在DAO对象同样的基本方法(get, save, remove) 测试。
- 这看起来是多余的(为什么全是测试!),但如果是一个6个月的过程这个测试是非常重要的。
这个类必须扩展service包下的BaseManagerTestCase,这个类(BaseManagerTestCase)的功能与BaseDaoTestCase类似。
- 我通常会修改(打开 → 另存为)存在的测试(如UserManagerTest.java),查找/替换[Uu]ser with [Pp]erson,或者其他任何我的对象的名字。
以下代码是一个基本的Manager的JUnit测试的要求,与DaoTest不同,这个测试使用jMock来将Manager和他的依赖隔离,使它成为一个真的"单元" 测试。这可以使你只关心业务逻辑而不必担心它的依赖,以下代码简单的设置好Manager和它 的依赖。
package org.appfuse.service;
import java.util.List;
import java.util.ArrayList;
import org.appfuse.dao.PersonDao;
import org.appfuse.model.Person;
import org.appfuse.service.impl.PersonManagerImpl;
import org.jmock.Mock;
import org.springframework.orm.ObjectRetrievalFailureException;
public class PersonManagerTest extends BaseManagerTestCase {
private final String personId = "1";
private PersonManager personManager = new PersonManagerImpl();
private Mock personDao = null;
private Person person = null;
protected void setUp() throws Exception {
super.setUp();
personDao = new Mock(PersonDao.class);
personManager.setPersonDao((PersonDao) personDao.proxy());
}
protected void tearDown() throws Exception {
super.tearDown();
personManager = null;
}
}
|
现在你已经把类的骨架搭好了,你需要添加肉了:填写确保所有测试通过的代码,以下来自DAO Tutorial的片断帮助我们理解我们将要做的事情。
- ...我们创建以"test"(全部小写)开头的方法,只要这些方法是public,返回类型是void,并且没有参数,它们就会被<junit>调用,以下是为了测试简单的CRUD操作,一件需要记住的事情是每一个方法(也可以称作测试)必须是自制的。
添加如下方法到PersonManagerTest.java:
public void testGetPerson() throws Exception {
// set expected behavior on dao
personDao.expects(once()).method("getPerson")
.will(returnValue(new Person()));
person = personManager.getPerson(personId);
assertTrue(person != null);
personDao.verify();
}
public void testSavePerson() throws Exception {
// set expected behavior on dao
personDao.expects(once()).method("savePerson")
.with(same(person)).isVoid();
personManager.savePerson(person);
personDao.verify();
}
public void testAddAndRemovePerson() throws Exception {
person = new Person();
// set required fields
person.setFirstName("firstName");
person.setLastName("lastName");
// set expected behavior on dao
personDao.expects(once()).method("savePerson")
.with(same(person)).isVoid();
personManager.savePerson(person);
personDao.verify();
// reset expectations
personDao.reset();
personDao.expects(once()).method("removePerson").with(eq(new Long(personId)));
personManager.removePerson(personId);
personDao.verify();
// reset expectations
personDao.reset();
// remove
Exception ex = new ObjectRetrievalFailureException(Person.class, person.getId());
personDao.expects(once()).method("removePerson").isVoid();
personDao.expects(once()).method("getPerson").will(throwException(ex));
personManager.removePerson(personId);
try {
personManager.getPerson(personId);
fail("Person with identifier '" + personId + "' found in database");
} catch (ObjectRetrievalFailureException e) {
assertNotNull(e.getMessage());
}
personDao.verify();
}
|
这个类不会被编译,因为我们还没有创建PersonManager接口。
- 在AppFuse里遵从这么多规范来实现可扩展性看起来很可笑,事实上,在绝大多数我参与的项目里 - 我发现在一年里学了如此多的知识,以至于我不想扩展我的架构,我想去重写它,我希望通过采纳最佳实践来保持AppFuse的时效性,但这并不经常发生,每年都仅仅是一个道最新版本的升级,而不是一个重写,;-)
创建一个新的与DAO通讯的Manager
马上,为所有实现类在src/service/**/service目录创建一个PersonManager.java接口来指定基本的CRUD操作,为了显示的目的,我去掉了所有的JavaDocs, setPersonDao()方法不是在所有的情况下出现,只是因为PersonManagerTest可以把DAO赋值。
- 通常,我会复制(打开 → 另存为)一个已存在的文件 (例如UserManager.java).
package org.appfuse.service;
import org.appfuse.model.Person;
import org.appfuse.dao.PersonDao;
public interface PersonManager {
public void setPersonDao(PersonDao dao);
public Person getPerson(String id);
public void savePerson(Person person);
public void removePerson(String id);
}
|
我们创建一个PersonManagerImpl类来实现PersonManager中的方法,为此,在src/service/**/service/impl创建一个PersonManagerImpl.java类,他必须扩展BaseManage并且实现PersonManager。
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 void savePerson(Person person) {
dao.savePerson(person);
}
public void removePerson(String id) {
dao.removePerson(Long.valueOf(id));
}
}
|
需要注意的是setPersonDao()方法,Spring使用它来绑定PersonDao到Manager,这些配置在applicationContext-service.xml 文件,我们将在Step 3配置这些,现在你可以使用"ant compile-service"编译所有代码。
现在你需要为服务层配置Spring文件,它才会知道这个新的Manager。
为这个Manager和事务配置Spring
为了通知Spring我们的PersonManager接口和它的实现类,打开src/service/**/service/applicationContext-service.xml,你会看到注释掉的关于"personManager"的定义,去掉注释,或者直接在文件末尾添加:
<bean id="personManager" parent="txProxyTemplate">
<property name="target">
<bean class="org.appfuse.service.impl.PersonManagerImpl" autowire="byName"/>
</property>
</bean>
|
"parent"属性会引用一个TransactionProxyFactoryBeanbean的定义,这也是所有的事物对象所要设置的。
运行ManagerTest
保存所有的文件,并且运行ant test-service -Dtestcase=PersonManager。
Yeah Baby, Yeah:
BUILD SUCCESSFUL
Total time: 9 seconds
此刻所有修改后的文件可以从此处下载获得.
下一部分: Part III: 创建 Struts Actions和JSPs - 在AppFuse架构下创建Actions和JSPs。
|