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


Referenced by
Articles
Articles_cn
Articles_pt
Articles_zh
CreateActions_zh
CreateDAO_zh
WebWorkActions_zh




JSPWiki v2.2.33

[RSS]


Hide Menu

CreateManager_zh


This is version 3. It is not the current version, and thus it cannot be edited.
[Back to current version]   [Restore this version]


Part II: 创建管理器Manager - 创建与数据库端(DAOs)交互的业务Facades和事务处理。
本教程依赖于Part I:在AppFuse建立DAO和对象.

关于本教程

本教程将会向你展示如何创建一个业务Facade类(和一个JUnit Test)与Part I中创建的DAO交互操作。

AppFuse的语境下,这被称作一个Manager类,它的主要职责是持久户层(DAO)和web层之间的一个桥梁,它也很好的把展示层和数据库层(例如Swing应用)解耦,Managers必定是应用程序所有的业务逻辑所在的地方。

我在“真实世界”中实际操作的方式用蓝色斜体表示。

让我们从在AppFuse的框架下创建一个ManagerTest和Manager。

目录

  • [1] 创建一个新的运行JUnit测试的ManagerTest
  • [2] 创建一个新的与DAO通讯的Manager
  • [3] 为这个Manager和事务配置Spring
  • [4] 运行ManagerTest

创建一个新的运行JUnit测试的ManagerTest [#1]

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((PersonDaopersonDao.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[#2]

马上,为所有实现类在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[3]配置这些,现在你可以使用"ant compile-service"编译所有代码。

现在你需要为服务层配置Spring文件,它才会知道这个新的Manager。

为这个Manager和事务配置Spring[#3]

为了通知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[#4]

保存所有的文件,并且运行ant test-service -Dtestcase=PersonManager

Yeah Baby, Yeah: BUILD SUCCESSFUL
Total time: 9 seconds


此刻所有修改后的文件可以从&#36825;&#37324;&#19979;&#36733;.

下一部分: Part III: &#21019;&#24314;Actions&#21644;JSPs - 在AppFuse架构下创建Actions和JSPs。



Go to top   More info...   Attach file...
This particular version was published on 06-Nov-2006 13:52:48 MST by rocksun.