Spring+Hibernate+Junit+Oracle的最简单的人门
一年前,就计划学习Spring,但初步了解一下,发现还是有些庞大,就知难而退了。最近反思一年来开发进展迟缓的原因,发现技术学习上比较保守,是重要原因。学习主流的开发技术,虽然有学习成本,但会有开发效率的提升。
第一个目标:用Spring+Hibernate完成对持久层的改造,这是Spring最迷人的应用之一吧。
Spring比较复杂,有七大部分,比如ORM/MVC/WEB等等,我想,应该分步学习,有些部分可能我以后也不打算学习,比如其MVC部分。
首先,作一点理论准备。SpringFramework的官方站点查阅资料,初步了解一下IOC,AOP这些SpringFramework力推的核心概念。阅读了官方手册,以及《Spring In Action》的部分内容,以及Martin Fowler谈IOC(Dependency Injection)的文章。
其次,寻找可用的入门教程,最后锁定了IBM developworks上的一篇文章,以及SpringFramework自带的petclinic作为实战材料。
Object-relation mapping without the container-Develop a transactional persistence layer using Hibernate and Spring这篇文章非常符合我的目标。透明思考称该文的作法是:“Spring结合Hibernate的标准做法”。
我的开发环境是:Jbuilder X+Oracle 8i +Jboss 3.27,操作系统是TurboLinux Server 8.0。
下载Richard HighTower 的源代码。
让这个例子运行起来,居然费了我一整天的时间。HighTower的例子,其数据库用的是Mysql,而我的是Oracle 8i,单单这个差别,就浪费了我一天的时间,因为Dbunit操作Mysql 与Oracle有些细节地方不同,就会导致运行失败。
为了让和我一样的初学者少走点弯路,下面给出我改造过的例子,尽可能的简化再简化,因此本例特地只使用一个数据库表:hofman_user。
1. 建立数据表
create table hofman_user (pk_user_id number(8),
vc_email varchar2(50),
vc_password varchar2(80),
primary key(pk_user_id));
2. 建立hofman_user表主键pk_user_id使用的序列
create sequence hofmanid_seq;
3. 一个数据表对应一个POJO:
package hofman;
import java.util.ArrayList;
import java.util.List;
public class User {
private Long id = new Long(-1);
private String email;
private String password;
public Long getId() {
return id;
}
public void setId(Long long1) {
id = long1;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public void setEmail(String string) {
email = string;
}
public void setPassword(String string) {
password = string;
}
}
4. 对应的hibernate 的映射文件:User_hbm.xml
<?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="hofman.User"
table="HOFMAN_USER"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="2"
>
<id
name="id"
column="PK_USER_ID"
type="java.lang.Long"
unsaved-value="-1"
>
<generator class="sequence">
<param name="sequence">hofmanid_seq</param>
</generator>
</id>
<property
name="email"
type="string"
update="false"
insert="true"
column="VC_EMAIL"
length="82"
not-null="true"
unique="true"
/>
<property
name="password"
type="string"
update="false"
insert="true"
column="VC_PASSWORD"
length="20"
not-null="true"
unique="true"
/>
</class>
<query name="AllUsers"><![CDATA[
from User user order by user.email asc
]]></query>
</hibernate-mapping>
5. UserDAO的interface文件:UserDAO.java
package hofman;
import java.util.List;
public interface UserDAO {
public List getUsers();
public void addUser(User user);
public User findUserByEmail(String email);
public void removeUser(String email);
}
6. UserDAO的实现文件:UserDAOImpl.java
package hofman;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Query;
import org.springframework.orm.hibernate.HibernateCallback;
import org.springframework.orm.hibernate.support.HibernateDaoSupport;
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO{
public List getUsers(){
return getHibernateTemplate().findByNamedQuery("AllUsers");
}
public User findUserByEmail(String email) {
return (User) getHibernateTemplate().find("from User u where u.email=?",email).get(0);
}
public void addUser(User user){
getHibernateTemplate().save(user);
}
public void removeUser (String email) {
User user = findUserByEmail(email);
this.getHibernateTemplate().delete(user);
}
}
7.SpringFramework的配置文件:. ApplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!--
- Application context definition for Express on Hibernate.
-->
<beans>
<!--
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/comp/env/jdbc/OracleDs</value>
</property>
</bean>
-->
<!-- Datasource that works in any application server
You could easily use J2EE data source instead if this were
running inside of a J2EE container.
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="url"><value>jdbc:oracle:thin:@192.168.1.2:1521:yulog</value></property>
<property name="username"><value>hofman</value></property>
<property name="password"><value>topSecret</value></property>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="dataSource"><ref local="dataSource"/></property>
<!-- Must references all OR mapping files. -->
<property name="mappingResources">
<list>
<value>/hofman/User.hbm.xml</value>
</list>
</property>
<!-- Set the type of database; changing this one property will port this to Oracle,
MS SQL etc. -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
</props>
</property>
</bean>
<!-- Pass the session factory to our UserDAO -->
<bean id="userDAOTarget" class="hofman.UserDAOImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<bean id="userDAO"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="target"><ref local="userDAOTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="addUser">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
7. 调用SrpingFramework的文件:ApplicationContextFactory.xml
package hofman;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Richard Hightower
* ArcMind Inc. http://www.arc-mind.com
*/
public class ApplicationContextFactory {
private static Log log = LogFactory.getLog(ApplicationContextFactory.class);
private static Object initObj = null;
private static int count = 0;
public static void init(Object o){
if (count > 0){
log.error("Can't initialize the application context twice: THIS SHOULD ONLY HAPPEN DURING TESTING");
}
initObj=o;
count++;
}
public static ApplicationContext getApplicationContext(){
if (initObj == null){
throw new IllegalStateException("Application context not initialized");
}
// else if (initObj instanceof ServletContext){
// ServletContext servletContext = (ServletContext) initObj;
// return WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
//
// }
else if (initObj instanceof String){
String contextResourceLocation = (String) initObj;
return new ClassPathXmlApplicationContext(contextResourceLocation);
} else {
//throw new IllegalStateException("You must initialize the context with a String or ServletContext");
throw new IllegalStateException("You must initialize the context with a String");
}
}
}
8. Junit的测试用例:UserDAOTest.java
package hofman;
import java.util.List;
import junit.framework.TestCase;
// added by hofman on 2005-07-22
public class UserDAOTest extends TestCase {
private UserDAO userDAO;
static {
ApplicationContextFactory.init("/hofman/applicationContext.xml");
}
public void testAddUser(){
User user = new User();
String email = "hofman@zhuoda.org";
user.setEmail(email);
user.setPassword("fakePass");
userDAO.addUser(user);
email = "s@s.com";
user.setEmail(email);
user.setPassword("topSecret");
userDAO.addUser(user);
User user2 = userDAO.findUserByEmail(email);
assertEquals(email, user2.getEmail());
}
public void testFindUserByEmail(){
User user = userDAO.findUserByEmail("hofman@zhuoda.org");
assertNotNull(user);
}
public void testKillUser()throws Exception{
String email = "s@s.com";
userDAO.removeUser(email);
}
protected void setUp() throws Exception {
super.setUp();
userDAO = (UserDAO) ApplicationContextFactory.getApplicationContext().getBean("userDAO");
}
protected void tearDown() throws Exception {
super.tearDown();
}
public static void main(String[] args) {
junit.swingui.TestRunner.run(UserDAOTest.class);
}
}
9. 调用UserDAO的jsp文件:getPass.jsp
<%@ page contentType="text/html; charset=GBK" %>
<%@ page import="hofman.*" %>
<%
UserDAO userDAO;
String password;
ApplicationContextFactory.init("/hofman/applicationContext.xml");
userDAO = (UserDAO) ApplicationContextFactory.getApplicationContext().getBean("userDAO");
User user = userDAO.findUserByEmail("hofman@zhuoda.org");
password = user.getPassword();
%>
<html>
<head><title>Get Password</title></head>
<body bgcolor="#ffffff">
<h1>hofman's password:<%=password %></h1>
</body>
</html>
10.完整的代码下载
[url=ftp://ftp.zhuoda.org/incoming/SpringInAction/helloSpring.tgz]helloSring.tgz[/url]
说明:
源代码很伟大,但适合新手阅读的源代码的文档很难找。我就是从HighTower的代码基础上开始起步,但编译时,首先就遇到一出错误,getHibernate.creatQuery()不存在,可能原作所使用的SpringFramework的版本比较老,我用的是写作本文时最新的1.2.2,注释掉相关部分,算是通过了,但UserDAOTest.java无法运行,Dbunit出问题了,费了老大劲,也未完全搞定,只不过,可用继续运行。
今天才发现,就本例,其实用junit就可用了,没有必要使用dbunit。Dbunit很伟大,如果数据库用的是Mysql的话,如果象我一样,数据库用oracle的话,也许有不少麻烦。
让Jbuider X支撑最新的SpringFramework很简单,Tools/Configure Libraries建立一个spring库,把spring发行包里面dist目录里面的jar加进去,就可用了。
支持Dbunit的方法类似。
前后化了一个星期的时间,终于可用使用被大吹特吹的Spring+Hibernate的持久层方案了,总算学会了用Junit调试连接数据库的DAO程序。
当然,这只是第一步。不过,目前,我并不想完全放弃我比较熟悉的J2EE开发模式,不管怎么说,引入新的持久层开发模式、特别是高效地调试模式,对提升开发效率无疑有好处。
hofman
2005-07-22 20:44:35
评论:5
阅读:5959
引用:0
下载路径
@2007-01-05 19:35:35 hofman
新的下载路径,helloSpring
@2007-01-05 17:52:09 hello
怎么找不到下载的路径
这片教程对新手非常好
@2006-11-19 17:19:50 lunzi
这教程对于学习spring和hibernate的结合的新手来说,是再合适不过了.现在对spring熟悉了,看这代码非常舒服!
包名称
@2006-09-14 16:36:10 hofman
src/hofman, hofman是包的名称,因为文件少,没有再分子包,比如hofman.dao,hofman.model,hofman.service之类.
请教一下
@2006-09-14 11:10:17 地主
我不明白你的这句
ApplicationContextFactory.init("/hofman/applicationContext.xml");
难道你的applicationContext.xml文件放到hofman下的?
hofman是个什么目录?普通目录?
ApplicationContextFactory.init("/hofman/applicationContext.xml");
难道你的applicationContext.xml文件放到hofman下的?
hofman是个什么目录?普通目录?
