您的位置:首页 > 编程语言 > Java开发

轻松快速建立Spring + Hibernate工程

2009-04-02 10:48 357 查看
从2006年起,我便在一家小软件公司打工。由于员工数量少,所以基本上每个人都是身兼多职,这是我当时安心在小公司工作的一个重要理由,这样的工
作模式让我学习到了很多东西,从网络到数据库,从系统调试到服务器维护,从JEE到PHP, 从JAVA GUI
到Workflow,在最近的这一年时间里,这些东西都需要由我来负责,确实对我在JAVA领域的学习促进很大。在公司参与的工程基本上都是网络应用程序
类的,其中有用iBatis的,有OJB的,有Hibernate的,着实使用了好些个框架。这里我想和大家分享一下快速建立Spring +
Hibernate的方法,谈谈我的开发习惯,大家一起讨论,共勉。

在开发JEE程序的时候,想必提及最多的就是MVC结构,这是大家在大学里学到的程序开发的基本规则。在我的开发中,我习惯将Model和Control这两个东西放在一起,界面单独处理。这里我主要想说的是数据层。

我想事先说明的是我将使用Hibernate Annotation,而不是传统的XML
Mapping。题目是“轻松快速”,那么就要找最快捷的方法。我刚刚使用Hibernate
Annotation没多久,但深切的体会其中的方便,现在已经不愿意再回到XML时代了。

闲话就不说了,进入实例吧。在实例中,我将不使用MyEclipse之类的工具,这样能够更清楚的描述每一个步骤。

表:Categoty, Product, Order, Customer

它们之间的关系应该是这样:

Category单- Product多

Product多 - Order多

Customer单 - Order多

这个工程起名叫做
PurchaseLine吧。下面开始建立这个工程,我使用Maven2。按照个人的习惯,有的人愿意用Ant,有的人愿意用Maven,各擅胜
场,Maven可能没有Ant灵活,但是要比Ant快多了。下载一个Maven2,安装好之后,进入eclipse的workspace路径下,执行以下
命令:

$ mvn archetype:create -DgroupId=com.purchaseline -DartifactId=PurchaseLine-Server

这是用maven2建立工程的最简单的方法。下面用Eclipse打开这个建立好的工程。在这之前,我们需要用maven把这个工程转化成Eclipse的格式,建立所有的classpath和project properties之类的东西。执行下面的命令:

$ cd PurchaseLine-Server

$ mvn eclipse:eclipse

打开Eclipse,点取:File -> Import,然后是General -> Existing Project Into Workspace,找到刚刚建立的PurchaseLine-Server,把这个工程输入到Eclipse里。

工程打开之后,可以看到maven已经为我们建立了一个文件结构,如图:



可以看到maven自动建立了一个正常的java路径和一个JUnit的测试路径,程序将会在src/main/java里。打开pom.xml这个文件,我们需要对其进行修改,添加hibernate和Spring的文件包。修改后的文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.purchaseline</groupId>
<artifactId>PurchaseLine-Server</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>PurchaseLine-Server</name>
<url>http://www.xchecka.com</url>
<developers>
<developer>
<id>your id</id>
<name>your name</name>
<email>your email</email>
<url>your website</url>
<organization>organisation name</organization>
<organizationUrl>organisation website</organizationUrl>
</developer>
</developers>
<!-- Build Plugins -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>com.anydoby</groupId>
<artifactId>fatjar-maven-plugin</artifactId>
<version>0.0.1</version>
<executions>
<execution>
<id>pre-jar</id>
<phase>package</phase>
<goals>
<goal>prepare-jars</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- External Repositories -->
<pluginRepositories>
<pluginRepository>
<id>anydoby.com</id>
<url>http://anydoby.com/maven</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>repository.jboss.org</id>
<name>JBoss Maven Repository</name>
<url>http://repository.jboss.org/maven2</url>
<layout>default</layout>
</repository>
</repositories>
<!-- Dependencies -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.4.0.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.1.ga</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>spring</groupId>
<artifactId>spring</artifactId>
<version>2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>3.1.12</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>2.7.5</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.4.3</version>
</dependency>
<dependency>
<groupId>castor</groupId>
<artifactId>castor</artifactId>
<version>1.0M2</version>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</project>


在这个文件里,我添加了一些
plugin和repository,没什么特别的地方,其中 fatjar-maven-plugin
这个外挂是生成fat-jar的,就是把所有引用的库文件都一起打包。这样最后声称的JAR就可以在任何地方使用而不用担心缺失支持的文件包了。
pom.xml改好了以后,再执行一次

$ mvn eclipse:eclipse

maven会下载这些文件包,然后把它们添加到classpath里。一直到现在都说的是题外话,跟hibernate和spring还一点关系没有呢。得了,还是直接进入正题吧。

按照我的习惯,先建立Java Bean。根据前面已经分析好的数据结构关系,建立实体类,注意其中的Annotation,这是Hibernate赖以生存的保障。

Category.java
/**
*
*/
package com.purchaseline.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Version;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
@Entity
@Table(name="pl_category")
public class Category implements Serializable{
/**
*
*/
private static final long serialVersionUID = 768102058416840404L;

@Id
@Column(name="pk_category_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long pkId;

@Version
@Column(name="last_updated", columnDefinition="timestamp", nullable=false)
private Date lastUpdated;

private String name;

@OneToMany(mappedBy="parentCategory")
@OrderBy("pkId")
@LazyCollection(value=LazyCollectionOption.FALSE)
@Sort(type=SortType.NATURAL)
private List<Product> products = new ArrayList<Product>();
public long getPkId() {
return pkId;
}
public void setPkId(long pkId) {
this.pkId = pkId;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}


Customer.java
/**
*
*/
package com.purchaseline.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Version;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
@Entity
@Table(name="pl_customer")
@NamedQueries({
@NamedQuery(name="find.customer.by.name", query="SELECT c FROM Customer c WHERE name = :name")
})
public class Customer implements Serializable{
/**
*
*/
private static final long serialVersionUID = 8694256634511189339L;

@Id
@Column(name="pk_customer_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long pkId;

@Version
@Column(name="last_updated", columnDefinition="timestamp", nullable=false)
private Date lastUpdated;

private String name;

private String address;

private String email;

@OneToMany(mappedBy="parentCustomer")
@OrderBy("pkId")
@LazyCollection(value=LazyCollectionOption.FALSE)
@Sort(type=SortType.NATURAL)
private List<Order> orders = new ArrayList<Order>();
public long getPkId() {
return pkId;
}
public void setPkId(long pkId) {
this.pkId = pkId;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}


Order.java
/**
*
*/
package com.purchaseline.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Version;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
@Entity
@Table(name="pl_order")
public class Order implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6924147187783817610L;
@Id
@Column(name="pk_order_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long pkId;

@Version
@Column(name="last_updated", columnDefinition="timestamp", nullable=false)
private Date lastUpdated;

@Column(name="order_number")
private int orderNumber;

@ManyToMany(
cascade={CascadeType.PERSIST, CascadeType.MERGE}
)
@JoinTable(
name="pl_product_order",
joinColumns = @JoinColumn(name="fk_order_id"),
inverseJoinColumns=@JoinColumn(name="fk_product_id")
)
@LazyCollection(value=LazyCollectionOption.FALSE)
@Sort(type=SortType.NATURAL)
private List<Product> products = new ArrayList<Product>();

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="parent_customer", updatable=false)
private Customer parentCustomer;
public long getPkId() {
return pkId;
}
public void setPkId(long pkId) {
this.pkId = pkId;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
public int getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(int orderNumber) {
this.orderNumber = orderNumber;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Customer getParentCustomer() {
return parentCustomer;
}
public void setParentCustomer(Customer parentCustomer) {
this.parentCustomer = parentCustomer;
}
}


Product.java
/**
*
*/
package com.purchaseline.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Version;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.Sort;
import org.hibernate.annotations.SortType;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
@Entity
@Table(name="pl_product")
public class Product implements Serializable{
/**
*
*/
private static final long serialVersionUID = -7250259164118909169L;
@Id
@Column(name="pk_product_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long pkId;

@Version
@Column(name="last_updated", columnDefinition="timestamp", nullable=false)
private Date lastUpdated;

private String name;

private String description;

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="parent_category", updatable=false)
private Category parentCategory;

@ManyToMany(
cascade={CascadeType.PERSIST, CascadeType.MERGE},
mappedBy="products",
targetEntity=Order.class,
fetch=FetchType.EAGER
)
@LazyCollection(value=LazyCollectionOption.FALSE)
@Sort(type=SortType.NATURAL)
private List<Order> orders = new ArrayList<Order>();
public long getPkId() {
return pkId;
}
public void setPkId(long pkId) {
this.pkId = pkId;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
}


JAVA Bean建好了。这里就不过多赘述Annotation的用法,如果有兴趣了解的话,上网看看Hibernate Annotation的官方资料就明白了。

虽然建好了实体类,但系统还是散乱的,这些类之间的连接并不明了。下面就建立基本的Hibernate和Spring配置文件和一些测试文件,可以让我们随时测试建立好的东西,及时发现错误。

建立 src/main/resources 文件夹,在里面建立文件:

log4j.properties
#
# Global logging configuration
#
# rootLogger level will be inherited by children
log4j.rootLogger=INFO, fileout, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{dd MMM HH:mm:ss} %-5p %25.25c..%-10.10M:%-3L - %m%n
# Settings for logging to file
# Rolling log file output...
#
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=/home/purchaseline/pl_log.log
log4j.appender.fileout.MaxFileSize=8192KB
log4j.appender.fileout.MaxBackupIndex=2
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=%d{dd MMM HH:mm:ss} %-5p %25.25c..%-10.10M:%-3L - %m%n


hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping class="com.purchaseline.model.Category"/>
<mapping class="com.purchaseline.model.Customer"/>
<mapping class="com.purchaseline.model.Order"/>
<mapping class="com.purchaseline.model.Product"/>
</session-factory>
</hibernate-configuration>


applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/purchase_line" />
<property name="username" value="your_username" />
<property name="password" value="your_password" />
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="configLocation">
<value>hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
</beans>


注意到在applicationContext.xml文件里的数据库名称和用户名密码,这里是用MySQL,所以需要进入MySQL先建立一个名字为 purchase_line的数据库。

下面建立一个系统初始化的类。这个类会初始化并且得到applicationContext,最终会是一个得到所有DAO的类。因为我们现在想作测试,所以只要先初始化applicationContext就可以了。

/**
*
*/
package com.purchaseline.server;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class PurchaseLineServerInit {
private static ApplicationContext ctx =
new ClassPathXmlApplicationContext(
new String[] {
"applicationContext.xml"
});

public static void test() {
return;
}
}


留意一下这些文件所属的package,这样的格局并非必须,但是为了使整个工程简单易读,最好遵循自己习惯的文件结构。

下面就可以开始测试了。建立一个带main的测试类,这里我建了一个PLTest.java

/**
*
*/
package com.purchaseline;
import com.purchaseline.server.PurchaseLineServerInit;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class PLTest {
public static void main(String args[]) {
try{
PurchaseLineServerInit.test();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}


这个类里面目前什么都没有,只是初始化一下applicationContext,看看hibernate和spring的设置是否正确。

运行这个测试以后,系统应该在purchase_line这个数据库里建立5个表格,如下图:



可以发现pl_product_order这个表,这是Hibernate自动建立的,用以连接order和product的多对多关系。

如果这些表成功建立,那说明hibernate和spring的设置都没有错。下面我们进行DAO的设置。Hibernate提供了一个泛的DAO,这个非常好用,灵活的使用能把工作减少到最低。下面我们建立DAO。

GenericDAO.java
/**
*
*/
package com.purchaseline.dao;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
import java.io.Serializable;
import java.util.List;
import org.springframework.dao.DataIntegrityViolationException;
/**
* <p>Title: GenericDAO.java</p>
*
* <p>Description: </p>
*
* <p>Created on: 27/01/2009</p>
*
* <p>Copyright (c) 2008 XChecka</p>
*
* @author Liudi <liudi@siab.com.au>
*
*/
public interface GenericDAO<T, ID extends Serializable> {
/**
*
* @param pkId
* @param lock
* @return T
*/
T findById(ID pkId, boolean lock);

/**
*
* @param pkId
* @return T
*/
T findById(ID pkId);

/**
*
* @return List<T>
*/
List<T> findAll();

/**
*
* @param entity
* @return T
* @throws DataIntegrityViolationException
*/
T makePersistent(T entity) throws DataIntegrityViolationException;

/**
*
* @param entity
* @param userId
* @return T
* @throws DataIntegrityViolationException
*/
T makePersistent(T entity, long userId) throws DataIntegrityViolationException;

/**
*
* @param entity
* @throws DataIntegrityViolationException
*/
void makeTransient(T entity) throws DataIntegrityViolationException;

/**
*
* @param entity
* @param userId
* @throws DataIntegrityViolationException
*/
void makeTransient(T entity, long userId) throws DataIntegrityViolationException;
}


既然有了接口,那就要有实体类来执行这个接口。下面就建立一个GenericDAOImpl的实体类。

GenericDAOImpl.java
/**
*
*/
package com.purchaseline.dao.impl;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.criterion.Criterion;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.purchaseline.dao.GenericDAO;
public class GenericDAOImpl<T, ID extends Serializable>
extends HibernateDaoSupport
implements GenericDAO<T, ID> {

private Class<T> persistentClass;

// Default Constructor
@SuppressWarnings("unchecked")
public GenericDAOImpl() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<T> getPersistentClass() {
return persistentClass;
}

/**
*
* @param entityId
* @return HibernateTemplate
*/
public HibernateTemplate getHibernateTemplateWithAuditInterceptor(long userId) {

HibernateTemplate ht = new HibernateTemplate(getSessionFactory(), true);
return ht;
}
public List<T> findAll() {
return findByCriteria();
}
@SuppressWarnings("unchecked")
public T findById(ID pkId, boolean lock) {
T entity;
if (lock)
entity = (T) getHibernateTemplate().get(getPersistentClass(), pkId,
LockMode.UPGRADE);
else
entity = (T) getHibernateTemplate().get(getPersistentClass(), pkId);

if (entity == null)
throw new ObjectRetrievalFailureException(getPersistentClass(), pkId);
return entity;
}
public T findById(ID pkId) {
return findById(pkId, true);
}
public T makePersistent(T entity) throws DataIntegrityViolationException {
try {
getHibernateTemplate().saveOrUpdate(entity);
} catch (org.springframework.dao.DataIntegrityViolationException dive) {
throw new DataIntegrityViolationException(dive.getMessage());
}

return entity;
}
public T makePersistent(T entity, long userId) throws DataIntegrityViolationException {
if (userId == 0)
return makePersistent(entity);
HibernateTemplate ht = getHibernateTemplateWithAuditInterceptor(userId);
try {
ht.saveOrUpdate(entity);
} catch (org.springframework.dao.DataIntegrityViolationException dive) {
throw new DataIntegrityViolationException(dive.getMessage());
}
return entity;
}
public void makeTransient(T entity)
throws DataIntegrityViolationException {
getHibernateTemplate().delete(entity);
}
public void makeTransient(T entity, long userId) throws DataIntegrityViolationException {
if (userId == 0)
makeTransient(entity);
HibernateTemplate ht = getHibernateTemplateWithAuditInterceptor(userId);
try {
ht.delete(entity);
} catch (org.springframework.dao.DataIntegrityViolationException dive) {
throw new DataIntegrityViolationException(dive.getMessage());
}
}
@SuppressWarnings("unchecked")
protected List<T> findByCriteria(Criterion... criterion) {
Criteria crit = getSession().createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
}


这两个东西就像它们名字一样,是两个基本接口和类,接下来我们建立的所有DAO都要继承它们。

CategoryDAO.java
/**
*
*/
package com.purchaseline.dao;
import com.purchaseline.dao.impl.GenericDAOImpl;
import com.purchaseline.model.Category;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class CatetoryDAO extends GenericDAOImpl<Category, Long>{
}


CustomerDAO.java

/**
*
*/
package com.purchaseline.dao;
import com.purchaseline.model.Customer;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public interface CustomerDAO extends GenericDAO<Customer, Long>{
/**
*
* @param name
* @return Customer
* @throws Exception
*/
public Customer findCustomerByName(String name) throws Exception;
}


OrderDAO.java
/**
*
*/
package com.purchaseline.dao;
import com.purchaseline.model.Order;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public interface OrderDAO extends GenericDAO<Order, Long>{
}


ProductDAO.java
/**
*
*/
package com.purchaseline.dao;
import com.purchaseline.model.Product;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public interface ProductDAO extends GenericDAO<Product, Long>{
}


在我们建立这些DAO的时
候,里面并没有定义任何功能,除了CustomerDAO,这就是继承GenericDAO美妙的地方,所有的基本功能,像findById,
findAll, 和makePersistence,
delete之类的方法已经在GenericDAO里定义了,大大减少了代码的重复。当然,如果你有特定的功能需要实现,当然需要在DAO里特殊定义出
来,就像在CustomerDAO里的一样。

下面执行这些借口:

CategoryDAOImpl.java
/**
*
*/
package com.purchaseline.dao.impl;
import com.purchaseline.dao.CategoryDAO;
import com.purchaseline.model.Category;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class CategoryDAOImpl
extends GenericDAOImpl<Category, Long>
implements CategoryDAO{
}


CustomerDAOImpl.java
/**
*
*/
package com.purchaseline.dao.impl;
import com.purchaseline.dao.CustomerDAO;
import com.purchaseline.model.Customer;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class CustomerDAOImpl
extends GenericDAOImpl<Customer, Long>
implements CustomerDAO{
public Customer findCustomerByName(String name) throws Exception {
return (Customer)getHibernateTemplate().
findByNamedQueryAndNamedParam("find.customer.by.name", "name", name).get(0);
}
}


OrderDAOImpl.java
/**
*
*/
package com.purchaseline.dao.impl;
import com.purchaseline.dao.OrderDAO;
import com.purchaseline.model.Order;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class OrderDAOImpl
extends GenericDAOImpl<Order, Long>
implements OrderDAO{
}


ProductDAOImpl.java
/**
*
*/
package com.purchaseline.dao.impl;
import com.purchaseline.dao.ProductDAO;
import com.purchaseline.model.Product;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class ProductDAOImpl
extends GenericDAOImpl<Product, Long>
implements ProductDAO{
}


下面在Spring里定义这些DAO,最后的applicationContext.xml是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/purchase_line" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="configLocation">
<value>hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>

<bean id="categoryDAO" class="com.purchaseline.dao.impl.CategoryDAOImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<bean id="customerDAO" class="com.purchaseline.dao.impl.CustomerDAOImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<bean id="orderDAO" class="com.purchaseline.dao.impl.OrderDAOImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<bean id="productDAO" class="com.purchaseline.dao.impl.ProductDAOImpl">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
</beans>


到这里基本上就全部搞定了,但是我们并不想每次调用DAO的时候都要初始化一下applicationContext,记得前面我们有一个PurchaseLineServerInit的这么一个类,现在正是用它的时候了,非常简单的就能从Spring里得到这些DAO:

PurchaseLineServerInit.java
/**
*
*/
package com.purchaseline.server;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.purchaseline.dao.CategoryDAO;
import com.purchaseline.dao.CustomerDAO;
import com.purchaseline.dao.OrderDAO;
import com.purchaseline.dao.ProductDAO;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class PurchaseLineServerInit {
private static ApplicationContext ctx =
new ClassPathXmlApplicationContext(
new String[] {
"applicationContext.xml"
});

public static void test() {
return;
}

public static CategoryDAO getCategoryDAO() {
return (CategoryDAO)ctx.getBean("categoryDAO");
}

public static CustomerDAO getCustomerDAO() {
return (CustomerDAO)ctx.getBean("customerDAO");
}

public static OrderDAO getOrderDAO() {
return (OrderDAO)ctx.getBean("orderDAO");
}

public static ProductDAO getProductDAO() {
return (ProductDAO)ctx.getBean("productDAO");
}
}


完成了。下面测试一下。前面我们已经有一个测试文件了,在里面添加些东西就可以:

/**
*
*/
package com.purchaseline;
import com.purchaseline.dao.CategoryDAO;
import com.purchaseline.model.Category;
import com.purchaseline.server.PurchaseLineServerInit;
/**
* <p>Title: PurchaseLine-Server</p>
*
* <p>Description: </p>
*
* <p>Created on: 02/04/2009</p>
*
* <p>Copyright (c) 2008 Daeo</p>
*
* @author daeo <daeo@toppc.com.au>
*
*/
public class PLTest {
public static void main(String args[]) {
try{
CategoryDAO categoryDAO = PurchaseLineServerInit.getCategoryDAO();

categoryTest(categoryDAO);
} catch(Exception ex) {
ex.printStackTrace();
}
}

public static void categoryTest(CategoryDAO dao) throws Exception {
Category c = new Category();
c.setName("new category");

dao.makePersistent(c);
}
}


运行之后应该在pl_category这个表里添加新记录。

下面是整个工程的文件结构:



到这里,整个过程就已经完成
了。在我的开发过程中,我一般是把这个工程打包到一个JAR里,然后在任何我想使用的地方调用。这样好处是MVC层之间完全分离,让你更加专注的去应对当
前需要工作的地方。另外,比如说用Netbeans开发JSF的时候,Netbeans做JSF倒是方便,可是编辑的速度功能上面我觉得都不如
Eclipse,所以我把数据的部分拿到Eclipse里去做,只有必须要用到Netbeans的时候我才使用它,大大提高了效率。在这个例子里,工程的结构适合任何形式的数据访问,所以这不仅是一个例子,当需要建立新工程的时候,复制粘贴这里面的几个文件,像GenericDAO, GenericDAOImpl, applicationContext.xml的前半部,就像是修改一个半成品一样,再结合各种IDE里的getter/setter自动生成之类的功能,只要很短的时间,你就可以建一个具有基本功能的数据层工程。

这只是我在工作中的经验和心得,写出来和大家分享,希望对刚刚接触Spring和Hibernate的朋友有所帮助,也希望各位高手,老鸟多多指点,大家互相帮助,共同进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: