Cooky - study blog

Java, Grails, OpenSolaris, Linux, programming, skateboarding...

Spring + Hibernate 简单应用

    Spring + Hibernate 是用 POJO 实现JavaEE 轻量级架构在数据持久层和业务层使用的主流模式. POJO 是指 Plain Old Java Object,即"普通Java对象". 轻量级架构可以这样理解, 它使用了诸如Spring,Hibernate,iBATIS等轻量级框架来开发企业级应用, 相对于传统的EJB(2.0及以前)重量级架构, 轻量级架构实现更容易,而且"无侵入",或者说没有侵略性,即使用轻量级框架时非常方便,并可以自由地选择使用其全部或部分功能,另外也很容易在原有框架的基础上进行扩展. 关于使用POJO 轻量级架构的详细信息请参阅<<POJOs IN ACTION>>一书. 此书中文版翻译得也不错, 链接地址为:
http://www.china-pub.com/computers/common/info.asp?id=34697.
    这里我举一个简单的Spring + Hibernate 的示例, 我是用MyEclipse开发的, 而且使用了Spring对Hibernate封装后的API来间接操作数据库.关于Spring 和 Hibernate, 以下两本书很适合入门时阅读:
精通Hibernate:Java对象持久化技术详解 http://www.china-pub.com/computers/common/info.asp?id=24485(这本书讲得不是最新的3.x版本的,但影响不大)
Spring 2.0核心技术与最佳实践 http://www.china-pub.com/computers/common/info.asp?id=34820
    由于我使用的是英文版的Eclipse, 我按照做的步骤依序记下了简单的英文表示,如下所示: (英文可能不太规范,就当伪代码来读哈~~ )
Step in English
1 New->Web Project:
    Project Name: HSpring
    J2EE Specification Level: Java EE 5.0
Finish

2 New->Class:
    Package: test.hspring.model
    Name: User

3 pragram codes in the class User:
package test.hspring.model;
public class User
{
    private long id;
    private String name;
    private String password;
    private boolean sex;

    public User()
    {
    }
}

then press Alt+Shift+S->Generate Getters and Setters...->select all
then change the "public" modifier of setId(long id) to "private"
notice that the getter method of boolean-sex filed is isSex() (getSex() is also valid)

4 right-click on the project HSpring,then select MyEclipse->Add Hibernate Capabilities...
ensure u select the Hibernate 3.1 Core Libaries and Copy checked Libary Jars to project folder and add to build-path(/WebRoot/WEB-INF/lib)
then Hibernate config file:New; default settings:src,hibernate.cfg.xml
Specify database connection details:unchecked(config it later)
Create sessionFactory class:no

5 Open the hibernate.cfg.xml file with Configuration View
check the option Use JDBC Driver
fill the URL with:   jdbc:mysql://localhost:3306/HSDB
copy the mysqldriver.jar to WebRoot/WEB-INF/lib
fill the Driver with: com.mysql.jdbc.Driver(u need first copy the mysql-connector.jar to WebRoot/WEB-INF/lib)
fill the Username with: root
fill the Password with ur password, admin eg.
select Dialect: MySQL

6 New->XML(Basic Templates) : User.hbm.xml under the package(folder) test.hspring.model,same with User class
u can find the <!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
content in the Hibernate3.jar(Referenced Libraries/hibernate3.jar/org.hibernate.hibernate-mapping-3.0.dtd) if u forgot it

7 edit the file hibernate.cfg.xml, Mappings->Add...->src/test/hspring/model/User.hbm.xml

8 right-click on the project HSpring,then select MyEclipse->Add Spring Capabilities...
Spring version: Spring 2
check MyEclipse Libraries
select Spring 2.0 AOP Libraries, Spring 2.0 Core Libraries, Spring 2.0 Persistence Core Libraries
also Copy checked Library contents to project folder..(/WebRoot/WEB-INF/lib)
check Specify new or existing Spring bean configuration file-> New
Next
check Creat Spring LocalSessionFactory that references the hibernate config using a configLocation property: LocalSessionFactory Bean Id: sessionFactory

9 New->Interface->package: test.hspring.dao   name: UserDAO

10 New->Class->UserDAOImpl extends HibernateDaoSupport implements UserDAO, package: test.hspring.dao
notice the methods in this class: this.getHibernateTemplate.get(long id), save(class,long id), update(Object), find(String)...

11 New->Class->test.hspring.RunThisOnce

start your MySQL service, open your MySQL client and create a database named HSDB

right-click in the code of RunThisOnce.java and select Run As->Java Application
after the class running successfully, delete the "hbm2ddl.auto" property in the filehibernate.cfg.xml
then you can find the table USERS has been create automantically, and it has a record "cooky"

   
    整个项目工程的下载链接为: http://www.blogjava.net/Files/cooky/HSpring.rar.
    注意,由于上传文件大小有限制,我删除了用到的所有第三方开发包(jar),如果你想直接运行此项目则需先将使用到的jar包copy到HSpring/WebRoot/WEB-INF/lib 文件夹下. 另外你可以跟着我上面的英文步骤和下面的详细介绍在MyEclipse自动导入包.
    jar包的列表如下,如果提示缺少某些jar,可参考下图进行导入:



    整个项目工程的包视图(Package Explorer)如下:



    下面我对前面的英文步骤做一些说明,你可以跟着下面的步骤来做,同时参加前面的英文信息.
    1.新建一个网站项目, 名字为 HSpring, 选择 Java EE 5.0 版本.

    2.新建一个类User, 作为我们的实体bean(这里是指POJO,不是EJB里的实体bean). 指定包名为 test.hspring.model (此处为方便间接创建包,其实应该先设计包结构再建类)

    3.在User.java 编码, 先写四个属性:id,name,password,sex 和默认构造函数.bean 的定义包含默认构造函数和属性的getter,setter方法,所以下面添加这四个属性的访问方法.直接按快捷键Alt+Shift+S 选Generate Getters and Setters...然后选择全部属性(为它们生成方法).此快捷键建议记住.你也可以右击代码然后选择Source->Generate Getters and Setters....
    另外注意,我们将让数据库自动生动主键,即以自动增长的方式实现代理主键(代理主键指主键不包含逻辑含义).所以把setId()方法设为private以防止用户修改id.还有,对于boolean型的属性如sex, isSex() 和 getSex() 都可以作为此属性的getter方法.
    User.java 的源代码如下:
User.javapackage test.hspring.model;

/**
 * Model Bean - class
 *
 * @author cooky
 *
 */
public class User
{
    private long id;
    private String name;
    private String password;
    private boolean sex;

    /**
     * Default Constructor
     */
    public User()
    {
    }

    public long getId()
    {
        return id;
    }

    private void setId(long id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getPassword()
    {
        return password;
    }

    public void setPassword(String password)
    {
        this.password = password;
    }

    /**
     * Return the sex of the user.
     *
     * @return true: female; false: male
     */
    public boolean isSex()
    {
        return sex;
    }

    /**
     * Set the sex of the user.
     *
     * @return true: female; false: male
     */
    public void setSex(boolean sex)
    {
        this.sex = sex;
    }
}

    4.现在我们要加入Hibernate的内容.右击项目名HSpring,选择MyEclipse->Add Hibernate Capabilities...,选择3.1版本的核心包,并选择"copy checked..."选项以把用到的Hibernate jar包copy到HSpring/WebRoot/WEB-INF/lib文件夹下,这样你的项目移动时依然可用,不会因为build-path的不一致而需要重新导入包(如果你只是自己演示用,可以选择只加入build-path).
    下一步中选择生成新的hibernate.cfg.xml文件,位于src文件夹下.这是使用Hibernate时默认指定的配置文件.然后选择数据库连接,如果你已经在MyEclipse配置过你的数据库(这里我用的是MySQL 5.0),则可以选择配置好的数据库连接.否则的话可以取消此项的勾选,稍后在文件中手动配置. 下面一步是问你是否自动生成一个用于访问Hibernate API的sessionFactory类.由于这里我会用到Spring包装后的API,所以不选中此项.

    5.第4步中的xml文件生成后,以配置视图打开该文件(默认情况下已经这样打开了).现在先在这个文件中配置数据库连接.选择使用JDBC驱动,在URL项填jdbc:mysql://localhost:3306/HSDB,当然端口(3306)和数据库名(HSDB)你可以根据自己的情况自行指定.由于我们后面会在此数据库中新建USERS表,所以确保现在这个数据库中没有此表(不区分大小写).否则将会覆盖此表造成数据丢失.(当然你也可以在下面的步骤里重新指定表的名称而不用USERS,稍后会讲到)
    现在要指定数据库连接用到的驱动类,在这之前,先把MySQL的连接驱动包copy到lib文件夹下(你可以到MySQL官方下载,名称类似mysql-connector-java-5.0.5-bin.jar).然后指定驱动类为com.mysql.jdbc.Driver. 接着设置用户名(默认主用户为root)和密码(比如我的MySQL访问密码是admin).最后选择数据库方言为MySQL.
    可能的hibernate.cfg.xml类似:
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

<session-factory>
    <property name="connection.url">
        jdbc:mysql://localhost:3306/HSDB
    </property>
    <property name="myeclipse.connection.profile">
        JDBC for MySql
    </property>
    <property name="connection.username">root</property>
    <property name="connection.password">admin</property>
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <property name="dialect">
        org.hibernate.dialect.MySQLDialect
    </property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="hbm2ddl.auto">create</propety>
    <mapping resource="test/hspring/model/User.hbm.xml" />
</session-factory>

</hibernate-configuration>
    注意,里面最后设置的<mapping />指向第6步中生成的配置文件,此文件用来定义如果把User类映射到数据库表.另外,我额外添加了三个属性:show_sql一般在调试时使用,即在控制台显示程序执行的sql语句;format_sql用来格式化前面的sql语句,否则每条(比如插入)语句都占一行很不直观;最后的hbm2ddl.auto属性设为create,用来配置由数据库映射文件(如第6步中生成的文件User.hbm.xml)生成数据库表的定义(ddl),并且执行此ddl(即创建表的sql语句)来自动生成表,这样就不用手动在数据库创建表了.由此更可见Hibernate强大的ORM(Object Relational Mapping,对象关系映射)能力.hbm2ddl是基于ant运行的开放工具,由于MyEclipse集成了ant,运用更方便.但使用ant也是J2EE 开发人员必备的能力之一.
    自动生成数据库表可作为测试用,但我在这里是专门用它来生成表,此表以后就可以使用了,不是为了测试.所以执行一次程序并生成了表后,就要把这个属性删除,否则每次执行都会重新建表并覆盖原来的表了.下面还会详讲.

    6.现在我们就可以新建配置文件,来为User类指定如何映射到数据库.在test.hspring.model包(或称文件夹)下新建xml文件User.hbm.xml(你也可以建在其他地方).文件的文件头<!DOCTYPE>定义了此xml文件的语法,如果你忘记了文件头的格式,可以去你添加的hibernate3.jar包里找位于最后的两个dtd文件,分别是cfg.xml和 hbm.xml两种hibernate配置文件的语法格式,注释内容中有文件头示例(或参照下面的代码).
    User.hbm.xml文件内容如下:
User.hbm.xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="test.hspring.model.User" table="USERS">
        <id name="id" column="ID">
            <generator class="native"></generator>
        </id>
        <property name="name" column="NAME" length="20" not-null="true" />
        <property name="password" column="PASSWORD" length="30"
            not-null="true" />
        <property name="sex" column="SEX" />
    </class>
</hibernate-mapping>
    文件中的一个<class>标签将对应一个实体bean类,这里只有一个:User. <class>标签的name属性指定要映射的实体bean类; table属性指定要映射的表名,不设置此属性的话将默认采取类的名称(如User).类的属性用<property>子标签来说明,但用来映射主键的属性(如id)要用用专门的<id>标签标识.<property>的name属性和实体bean类里的属性对应(名称相同); column属性指定此属性将映射到表中的哪一列(字段),不设的话默认和name相同.另外<property>还有not-null,length属性等,都是故名思义.<id>有个子属性:<generator>,用来指定主键的生成方式,为auto_increment时表示采用Hibernate自己实现的增长机制,为native时表示将采用底层数据库自己的实现机制,所以移植性更好.关于映射的更多信息请参阅Hibernate的相关内容.
   
    7.现在要把写好的User.hbm.xml加入hibernate.cfg.xml中.在配置视图下打开hibernate.cfg.xml,点Mappings区域的Add...,找到User.hbm.xml并选择.第5步中的hibernate.cfg.xml内容已经实现加入了User.hbm.xml.

    8.Hibernate的配置告一段落,现在来进行和Spring相关的操作.右击项目名选择MyEclipse->Add Spring Capabilities...,在出来的对话框中,选择Spring版本为:Spring 2.0,勾选 MyEclipse Libraries 选项,在列出的jar包里,选择 Spring 2.0 AOP Libraries, Spring 2.0 Core Libraries, Spring 2.0 Persistence Core Libraries,同样选中最下面的选项把包copy进项目(或者只加入build-path).然后选择新建Spring bean 配置文件.下面可以按照默认选项,来生成一个引用已有的Hibernate配置文件的sessionFactory来供Spring使用.

    9.下面我们来实现DAO(Data Access Object,数据访问对象)的操作.由于Spring鼓励面向接口编程,所以虽然我们的项目很简单,还是使用了接口.新建接口(Interface) UserDAO, 位于test.hspring.dao 包下.此接口定义了通过Hibernate访问数据库的一系列操作,用来为服务(Service)提供方法,而面向表现层的服务是不能直接调用Hibernate(或Srping)的API来实现这些方法的.以下是其源码:
UserDAO.javapackage test.hspring.dao;
import java.util.List;
import test.hspring.model.User;
/**
 * Data Access Object interface
 *
 * @author cooky
 *
 */
public interface UserDAO
{
    User getUserByID(long id);
    User getUserByName(String name);
    List<User> listAllUsers();
    void changePassword(User user, String password);
    void addUser(User user);
}

   
    10.现在编写实现了以上接口的类(如 UserDAOImpl).在这里我把这个类扩展(继承)了Spring包里的HibernateDAOSupport类,这样可以加入Spring提供的事务管理,并通过Spring封装了Hibernate API后的方法来间接进行数据库操作(对类的对象进行操作,Hibernate将操作映射到数据库).这些方法常用的有HibernateTemplate.get(long id), save(class,long id), update(Object), find(String),load()等等.HibernateTemplate对象可由父类中提供的this.getHibernateTemplate()方法得到.以下是UserDAOImpl类的源代码:
UserDAOImpl.javapackage test.hspring.dao;
import java.util.Iterator;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import test.hspring.model.User;
/**
 * An implementation of UserDAO using Spring's API which resue the API of
 * hibernate3
 *
 * @author cooky
 *
 */
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO
{
    @Override
    public void addUser(User user)
    {
        this.getHibernateTemplate().save(user);
    }

    @Override
    public void changePassword(User user, String password)
    {
        User userToChange = this.getUserByID(user.getId());
        userToChange.setPassword(password);
        this.getHibernateTemplate().update(userToChange);
    }

    @Override
    public User getUserByID(long id)
    {
        User user = (User) this.getHibernateTemplate().get(User.class, id);
        return user;
    }

    @Override
    public User getUserByName(String name)
    {
        User user = null;
        List userList = this.getHibernateTemplate().find("from User u where u.name=?", name);
        if (!userList.isEmpty())
        {
            Iterator userItr = userList.iterator();
            user = (User) userItr.next();
        }
        return user;
    }

    @Override
    public List<User> listAllUsers()
    {
        List<User> userList = this.getHibernateTemplate().find("from User");
        if (userList == null || userList.isEmpty())
        {
            return null;
        } else
        {
            return userList;
        }
    }
}


    11.现在,Hibernate+Spring的内容基本完成,就缺少和表现层交互的内容了.不过,前面提过要运行一次程序以自动生成数据库表,所以这里我提供了一个类:RunThisOnce,位于test.hspring包.它把一个User对象保存对数据库.源码如下:
RunTestOncepackage test.hspring;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.hspring.dao.UserDAO;
import test.hspring.model.User;
/**
 * Run this class once to generate the tables that to be mapped by hibernate(we
 * only generate one table: USERS). After you run this, delete the
 * "hbm2ddl.auto" property in the file hibernate.cfg.xml
 *
 * @author cooky
 *
 */
public class RunThisOnce
{
    public static void main(String[] args)
    {
        UserDAO userDAO = (UserDAO) new ClassPathXmlApplicationContext("applicationContext.xml").getBean("userDAO");
        User user = new User();
        user.setName("cooky");
        user.setPassword("test-password");
        user.setSex(false);
        userDAO.addUser(user);
    }
}

    在运行之前,要在applicationContext.xml文件中配置要使用的bean: userDAO.这里我们用Spring事务及AOP(Aspect Oriented Programming,面向切面编程)机制来管理bean.配置后的applicationContext.xml内容如下:
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="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation"
            value="classpath:hibernate.cfg.xml">
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <bean id="userDAOTarget" class="test.hspring.dao.UserDAOImpl">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

    <bean id="userDAO"
         class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="target" ref="userDAOTarget"></property>
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="proxyTargetClass" value="true"></property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
</beans>
    bean 的proxyTargetClass属性设为true,是因为得到bean里可能会抛出ClassCastException,这样就需要指明此bean为代理bean.其他配置一目了然,userDAO这个代理bean用target属性指明实际代理的类.关于此处配置的详细信息(如设置方法中事务的传播机制等),请参阅Spring 相关内容.
    运行RunThisOnce之前,你还需要开启MySQL服务,并创建在hibernate.cfg.xml中指定的数据库(如HSDB).但USERS表不用创建.现在,在RunThisOnce.java的代码中右击,选择 Run As->Java Application, 运行成功后会在数据库生成USERS表,而且里面有一条记录(name为"cooky").
    正如前面所说,我运行此程序只为了自动生成数据库,所以,现在去hibernate.cfg.xml把<property name="hbm2ddl.auto">create</property>删除,以防止程序每次运行都重新建立表.而且RunThisOnce.java也应该删除.如果现在再次运行此程序你只会向表中添加name,password和sex都相同的一条新记录(之前没有设这三个之中的任一个的unique为true,即允许重复).

    Okay...终于写完了~~
    那么,表现层(如网页浏览器)怎么和现在的Spring+Hibernate框架进行交互呢(即实现服务/Service)? 你可能想到在Servlet中像RunThisOnce.java中那样得到applicationContext.xml配置的bean,并调用dao的方法.但是,这样是极不规范的.Spring配置的bean不能随便获取.我会再写一篇关于JSF与Spring结合的文章来简单探讨这个问题.
    另外,我还会写一篇关于JUnit单元测试的文章,也会用到现在的这个项目HSpring.



Keep It Simple, Stupid

posted on 2007-10-15 23:47 Cooky 阅读(1733) 评论(12)  编辑  收藏 所属分类: Java

评论

# re: Spring + Hibernate 简单应用[未登录] 2007-10-16 11:37 chance

严重顶一下
我已加入收藏  回复  更多评论   

# re: Spring + Hibernate 简单应用 2007-10-17 12:47 Micky

Hello,Cooky!  回复  更多评论   

# re: Spring + Hibernate 简单应用 2007-10-18 00:16 cooky

@Micky
Hello u guy  回复  更多评论   

# re: Spring + Hibernate 简单应用 2007-10-18 01:59 Micky

cooky真强~
鞠躬,握手~
罪过啊罪过,一开始我还以为这文章是转载的……  回复  更多评论   

# re: Spring + Hibernate 简单应用 2007-10-18 02:03 Micky

blogjava也挺强,我刚发现原来这里的评论是ajax实现的异步刷新……
好意外~~
这么老土古旧的博客模板了。真是模板不可貌相。。。  回复  更多评论   

# re: Spring + Hibernate 简单应用 2007-10-19 00:35 cooky

@Micky
对你真是无语了...  回复  更多评论   

# re: Spring + Hibernate 简单应用 2008-03-23 19:44

不错,牛写得这么清楚  回复  更多评论   

# re: Spring + Hibernate 简单应用[未登录] 2008-04-11 17:54 ling

正在学,感谢哦,很详细啊!嘿嘿,楼主以后多发一些哦!  回复  更多评论   

# re: Spring + Hibernate 简单应用 2008-11-12 10:26 ddd

henhao!  回复  更多评论   

# re: Spring + Hibernate 简单应用 2008-12-03 13:02 marshall

试一下AJAX更新..  回复  更多评论   

# re: Spring + Hibernate 简单应用 2008-12-03 13:02 marshall

哈哈,,再来一次,  回复  更多评论   

# re: Spring + Hibernate 简单应用 2008-12-23 21:57 xc

试一下,哈哈  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航: