【原创翻译】在AppFuse 2.0 中使用 Hibernate【AppFuse 2.0 文档-10】

摘要:
本文讨论了在AppFuse 2.0 中使用 Hibernate 
关键字:
Appfuse 2.0 , Hibernate ,Maven 2 , Struct 2.0 , Spring,
Using Hibernate
 
标题
【原创翻译】在AppFuse 2.0 中使用 Hibernate【AppFuse 2.0 文档-10】
 
作者: Added by Matt Raible, last edited by Matt Raible on Oct 24, 2007 00:39
翻译者: 陈海青(josonchen)
日期:2007.11.15
 
摘要:
本文讨论了在AppFuse 2.0 中使用 Hibernate 
关键字:
Appfuse 2.0 , Hibernate ,Maven 2 , Struct 2.0 , Spring,
 
英文版网址 http://appfuse.org/display/APF/Using+Hibernate
 
关于本节教程
本教程主要关于以下两件事 :
1.      如果仅需要生成 CRUD 方法,那么不需要书写 DAOs
2.      需要定制 CRUD 方法时,应如何写 DAOs.
如果对 Hibernate 不太熟悉 , 也许在开始本课程之前需要读读 Hibernate Reference Guide.
目录
4.      运行 DAO 测试
关于源码
本课程的代码位置在 Google code appfuse-demos 项目里的 "tutorial-hibernate" 模块里 . 使用以下命令从 Subversion 服务器中检出 :
svn checkout http://appfuse-demos.googlecode.com/svn/trunk/tutorial-hibernate
注册personDao bean 定义
AppFuse 2.x 不需要写 DAO 来持久化 POJO. 如果你所需要的仅是对一个对象执行 CRUD 操作,那就可以使用以下预置的类之一 :
  • GenericDaoHibernate: 是一个通用的类,需要建立Spring bean 定义.
  • UniversalDaoHibernate: 一个特殊的类,需要建立指定的对象类型.
UniversalDaoHibernate 类已经被注册为一个 "dao" bean, 所以不必增加附加的配置就可以使用 . 然而,许多开发者更喜欢通用的 DAO generics-based DAO ),因为它提供了类型安全保证。为注册 personDao bean ,需要建立文件 src/main/webapp/WEB-INF/applicationContext.xml ( 多模块架构是 core/src/main/resources/applicationContext.xml ) 并添加以下内容 :
注意,如果使用 AppFuse 2.0 M5+ applicationContext.xml 文件可能已经存在了 .
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 
    <bean id="personDao" class="org.appfuse.dao.hibernate.GenericDaoHibernate">
        <constructor-arg value="org.appfuse.tutorial.model.Person"/>
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean> 
</beans>
完成后,使用 Spring 的应用,再添加了以下 setter 方法后,就可以在一个对象上使用这个 bean :
public void setPersonDao(GenericDao<Person, Long> personDao) {
    this.personDao = personDao;
}
如果不仅仅需要 CRUD 功能,那还要继续向下阅读本教程,否则,可以转而阅读 Creating new Managers ,这篇教程教授如何建立商业逻辑面,与 Session Facades 类似,但是不使用 EJB 技术。这些面( facades )用于提供前端与 DAO 层的通讯 .
建立DAO 测试类测试finder方法
现在需要建立一个 DaoTest 类来测试 DAO 是否能工作。 " 请等一会 ," 你也许会说 ," 我还没创建 DAO!" 当然,你是正确的。然而,我发现测试驱动开发( Test-Driven Development )更有利于提高软件开发质量 . 多年来,我一直认为写类前先写测试毫无是处,而且看起来好像是很愚蠢的。但在尝试过以后,我发现这种开发方法实际上是很了不起的。现在,我使用测试驱动的唯一原因就是因为它能迅速提高软件开发效率 .
首先 , src/test/java/**/dao directory ( 多模原型下 core/src/test/java/**/dao ) 目录下建立类 PersonDaoTest.java, 它要继承org.appfuse.dao.BaseDaoTestCase –是 Spring AbstractTransactionalDataSourceSpringContextTests 的一个子类 . 其父类是用于装载 Spring ApplicationContext ( 因为 Spring 需要依据它来把接口( interfaces )绑定到实现上( implementations ), 并且(可选的)装入一个 与你的 *Test 同名的 .properties 文件 . 在本例中,如果将一个命名为 PersonDaoTest.properties 的文件放入目录 src/test/resources/org/appfuse/tutorial/dao , 那么文件中的属性将可以使用变量 "rb" 来取得 .
package org.appfuse.tutorial.dao;
 
import java.util.List;
 
import org.appfuse.dao.BaseDaoTestCase;
import org.appfuse.tutorial.model.Person;
import org.springframework.dao.DataAccessException;
 
public class PersonDaoTest extends BaseDaoTestCase {
    private PersonDao personDao = null;
 
    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }
}
上述代码就是一个基本的与 Spring 整合的测试,初始化,并配置了 PersonDao 的实现 . Spring 将通过名字来自动回调 setPersonDao() 方法,并建立与 "personDao" bean 的关联 .
现在可以测试 DAO 中的 finder 方法了。首先建立一个以 "test" ( 全部小写 ) 开头的测试类 . ,访问权限是 public, 返回类型为 void ,没有参数,它将被 Junit 调用执行,然后将以下方法加入 PersonDaoTest.java 文件 :
public void testFindPersonByLastName() throws Exception {
    List<Person> people = personDao.findByLastName("Raible");
    assertTrue(people.size() > 0);
}
你会注意到,这个方法要测试通过必须要依赖一些预置的数据,而 DbUnit Maven Plugin 可以用来在测试运行前将数据插入数据库中 , 你只需将需加入的表或记录的信息放到文件 src/test/resources/sample-data.xml 中(多模原型是在 core/src/test/resources/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>
如果重新格式 sample-data.xml 中的 XML, 要确保在标签( tag )值内没有换行符( line breaks . 但令我吃惊的是当 <password>xxxxxxx</password> 被分为三行的情景, 由于 password 标签不再对额外的 tabs 和换行符进行解密 , 现在想用任意用户名登录将不再可能。而允许在数据库连接串里使用任意字符是 DBUnit 的特性 .
由于将要写的 PersonDao 包含了 CRUD 功能,所以也要写个校验 CRUD 的测试 .
import org.springframework.dao.DataAccessException;
 
public void testAddAndRemovePerson() throws Exception {
    Person person = new Person();
    person.setFirstName("Country");
    person.setLastName("Bry");
 
    person = personDao.save(person);
    flush();
 
    person = personDao.get(person.getId());
 
    assertEquals("Country", person.getFirstName());
    assertNotNull(person.getId());
 
    log.debug("removing person...");
 
    personDao.remove(person.getId());
    flush();
 
    try {
        personDao.get(person.getId());
        fail("Person found in database");
    } catch (DataAccessException dae) {
        log.debug("Expected exception: " + dae.getMessage());
        assertNotNull(dae);
    }
}
上例中,在保存对象前,要先调用 person.set*(value) 方法设置对象,然后再保存起来。本例情况较简单,如果对象的属性超过了 10 个,那就麻烦了。这就是为什么在 BaseDaoTestCase 要有一个资源集合( ResourceBundle ) 的原因 . 首先在 PersonDaoTest.java 所在目录里 简单地建立一个 PersonDaoTest.properties 文件,并定义属性值对如下 :
firstName=Matt
lastName=Raible
也许觉得可以用硬编码来在程序里设置测试值,但是在处理大的对象时, .properties 文件是一个很好的选择 .
然后,不必调用 person.set* 来设置对象属性 , 只需使用 BaseDaoTestCase.populate(java.lang.Object) 方法即可完成 :
Person person = new Person();
person = (Person) populate(person);
此时, PersonDaoTest 类还不能编译,因为还没有 PersonDao 类,现在需要建立它了 .
建立DAO 接口及其实现
src/main/java/**/dao ( 多模原型是 core/src/main/java/**/dao ) 目录里建立接口文件 PersonDao.java ,并为所有的实现类指定 finder 方法 .
package org.appfuse.tutorial.dao;
 
import org.appfuse.dao.GenericDao;
import org.appfuse.tutorial.model.Person;
 
import java.util.List;
 
public interface PersonDao extends GenericDao<Person, Long> {
    public List<Person> findByLastName(String lastName);
}
注意,上面这个类的方法声明( method signature )中并没有异常声明,这主要是归功于 Spring                       它使用 RuntimeExceptions 包装了异常( Exception . 现在,你可以使用 IDE 或命令 mvn test-compile 来编译代码了 . 然而,如果你试图运行 mvn test -Dtest=PersonDaoTest, 就会报错 :
Running org.appfuse.tutorial.dao.PersonDaoTest
INFO - AbstractSingleSpringContextTests.loadContextLocations(179) | Loading context for: classpath*:/applicationContext-*.xml
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.449 sec <<< FAILURE!
很不幸,这些信息并没有多少关于是导致报错的原因的,要找到问题所在 , 需要打开文件 target/surefire-reports/org.appfuse.tutorial.dao.PersonDaoTest.txt ( 在多模原型下是 core/target/surefire-reports/org.appfuse.tutorial.dao.PersonDaoTest.txt) ,在这里会告诉你有真正的问题所在 :
---------------------------------------------------------------------
Test set: org.appfuse.tutorial.dao.PersonDaoTest
---------------------------------------------------------------------
Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.444 sec <<< FAILURE!
testFindPersonByLastName(org.appfuse.tutorial.dao.PersonDaoTest) Time elapsed: 0.401 sec <<< ERROR!
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
with name 'org.appfuse.tutorial.dao.PersonDaoTest': Unsatisfied dependency expressed
through bean property 'personDao': Set this property value or disable dependency
checking for this bean.
在控制台(控制窗口)中显示错误
mvn test 命令里添加参数 -Dsurefire.useFile=false 就可以在控制台( console )中现实测试错误信息。
这个错误信息来自 Spring – 指出需要在 Spring context 文件里指定一个命名为 "personDao" bean. 在做这件事之前,首先需要建立 PersonDao 的实现类 .
我们建立一个 PersonDaoHibernate 类来实现 PersonDao 里的 finder 方法 . 首先,在 src/main/java/**/dao/hibernate ( 多模原型 core/src/main/java/**/dao/hibernate) 目录下建立一个类文件,并命名为 PersonDaoHibernate.java . 需要继承 GenericDaoHibernate 并且实现PersonDao 。一个简短的例子如下:
package org.appfuse.tutorial.dao.hibernate;
 
import java.util.List;
 
import org.appfuse.dao.hibernate.GenericDaoHibernate;
import org.appfuse.tutorial.model.Person;
import org.appfuse.tutorial.dao.PersonDao;
 
public class PersonDaoHibernate extends GenericDaoHibernate<Person, Long> implements PersonDao {
 
    public PersonDaoHibernate() {
        super(Person.class);
    }
 
    public List<Person> findByLastName(String lastName) {
        return getHibernateTemplate().find("from Person where lastName=?", lastName);
    }
}
现在如果再运行 mvn test -Dtest=PersonDaoTest , 还会看到同样的错误,因为还要配置 Spring 告诉它 PersonDaoHibernate PersonDao . 的实现类。
src/main/webapp/WEB-INF (or core/src/main/resources for a modular archetype) 目录下建立文件 applicationContext.xml ,并添加以下内容分 :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 
    <bean id="personDao" class="org.appfuse.tutorial.dao.hibernate.PersonDaoHibernate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean> 
</beans>
运行DAO 测试
保存编辑的文件,运行命令 mvn test -Dtest=PersonDaoTest ,过一会后,
是的,朋友,就是这条信息 :
BUILD SUCCESSFUL
Total time: 9 seconds
在视图过滤器( View Filter )中打开会话( Session
如果希望在应用中使用 Hibernate 的延迟载入( lazy-loading )特性, 那么,需要在文件 web.xml 中去掉 lazyLoadingFilter ( 及其 mapping) 的注释 .

接下来: Part II: 建立管理类( Creating new Managers - 关于如何建立商业逻辑层( Business Facades , 与会话层( Session Facades )类似 , 但是不使用 EJB. 这些层用于提供前台( front-end )与 DAO 层的通讯。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值