轻松快速建立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的文件包。修改后的文件如下:
在这个文件里,我添加了一些
plugin和repository,没什么特别的地方,其中 fatjar-maven-plugin
这个外挂是生成fat-jar的,就是把所有引用的库文件都一起打包。这样最后声称的JAR就可以在任何地方使用而不用担心缺失支持的文件包了。
pom.xml改好了以后,再执行一次
$ mvn eclipse:eclipse
maven会下载这些文件包,然后把它们添加到classpath里。一直到现在都说的是题外话,跟hibernate和spring还一点关系没有呢。得了,还是直接进入正题吧。
按照我的习惯,先建立Java Bean。根据前面已经分析好的数据结构关系,建立实体类,注意其中的Annotation,这是Hibernate赖以生存的保障。
Category.java
Customer.java
Order.java
Product.java
JAVA Bean建好了。这里就不过多赘述Annotation的用法,如果有兴趣了解的话,上网看看Hibernate Annotation的官方资料就明白了。
虽然建好了实体类,但系统还是散乱的,这些类之间的连接并不明了。下面就建立基本的Hibernate和Spring配置文件和一些测试文件,可以让我们随时测试建立好的东西,及时发现错误。
建立 src/main/resources 文件夹,在里面建立文件:
log4j.properties
hibernate.cfg.xml
applicationContext.xml
注意到在applicationContext.xml文件里的数据库名称和用户名密码,这里是用MySQL,所以需要进入MySQL先建立一个名字为 purchase_line的数据库。
下面建立一个系统初始化的类。这个类会初始化并且得到applicationContext,最终会是一个得到所有DAO的类。因为我们现在想作测试,所以只要先初始化applicationContext就可以了。
留意一下这些文件所属的package,这样的格局并非必须,但是为了使整个工程简单易读,最好遵循自己习惯的文件结构。
下面就可以开始测试了。建立一个带main的测试类,这里我建了一个PLTest.java
这个类里面目前什么都没有,只是初始化一下applicationContext,看看hibernate和spring的设置是否正确。
运行这个测试以后,系统应该在purchase_line这个数据库里建立5个表格,如下图:
可以发现pl_product_order这个表,这是Hibernate自动建立的,用以连接order和product的多对多关系。
如果这些表成功建立,那说明hibernate和spring的设置都没有错。下面我们进行DAO的设置。Hibernate提供了一个泛的DAO,这个非常好用,灵活的使用能把工作减少到最低。下面我们建立DAO。
GenericDAO.java
既然有了接口,那就要有实体类来执行这个接口。下面就建立一个GenericDAOImpl的实体类。
GenericDAOImpl.java
这两个东西就像它们名字一样,是两个基本接口和类,接下来我们建立的所有DAO都要继承它们。
CategoryDAO.java
CustomerDAO.java
OrderDAO.java
ProductDAO.java
在我们建立这些DAO的时
候,里面并没有定义任何功能,除了CustomerDAO,这就是继承GenericDAO美妙的地方,所有的基本功能,像findById,
findAll, 和makePersistence,
delete之类的方法已经在GenericDAO里定义了,大大减少了代码的重复。当然,如果你有特定的功能需要实现,当然需要在DAO里特殊定义出
来,就像在CustomerDAO里的一样。
下面执行这些借口:
CategoryDAOImpl.java
CustomerDAOImpl.java
OrderDAOImpl.java
ProductDAOImpl.java
下面在Spring里定义这些DAO,最后的applicationContext.xml是这样的:
到这里基本上就全部搞定了,但是我们并不想每次调用DAO的时候都要初始化一下applicationContext,记得前面我们有一个PurchaseLineServerInit的这么一个类,现在正是用它的时候了,非常简单的就能从Spring里得到这些DAO:
PurchaseLineServerInit.java
完成了。下面测试一下。前面我们已经有一个测试文件了,在里面添加些东西就可以:
运行之后应该在pl_category这个表里添加新记录。
下面是整个工程的文件结构:
到这里,整个过程就已经完成
了。在我的开发过程中,我一般是把这个工程打包到一个JAR里,然后在任何我想使用的地方调用。这样好处是MVC层之间完全分离,让你更加专注的去应对当
前需要工作的地方。另外,比如说用Netbeans开发JSF的时候,Netbeans做JSF倒是方便,可是编辑的速度功能上面我觉得都不如
Eclipse,所以我把数据的部分拿到Eclipse里去做,只有必须要用到Netbeans的时候我才使用它,大大提高了效率。在这个例子里,工程的结构适合任何形式的数据访问,所以这不仅是一个例子,当需要建立新工程的时候,复制粘贴这里面的几个文件,像GenericDAO, GenericDAOImpl, applicationContext.xml的前半部,就像是修改一个半成品一样,再结合各种IDE里的getter/setter自动生成之类的功能,只要很短的时间,你就可以建一个具有基本功能的数据层工程。
这只是我在工作中的经验和心得,写出来和大家分享,希望对刚刚接触Spring和Hibernate的朋友有所帮助,也希望各位高手,老鸟多多指点,大家互相帮助,共同进步。
作模式让我学习到了很多东西,从网络到数据库,从系统调试到服务器维护,从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的朋友有所帮助,也希望各位高手,老鸟多多指点,大家互相帮助,共同进步。
相关文章推荐
- 轻松快速建立Spring Hibernate工程
- 轻松快速建立Spring + Hibernate工程
- 【SpringData】轻松愉快之玩转SpringData( 第3章 Spring Data快速入门 )
- SSH快速整合 struts2、Spring3、Hibernate3
- JAVA框架三剑客 - Struts+Spring+Hibernate快速入门
- [Apache Click快速开发]整合Hibernate3.3和Spring3.0
- Eclipse3.0下Struts +spring+ hibernate快速入门(1)
- 用spring和hibernate构建web工程
- Structs+Spring+Hibernate快速入门
- SpringBoot快速启动和建立统一父pom
- Struts+Spring+Hibernate快速入门
- 【原创】搭建SSH后通过反向工程(Reverse Engineering)自动生成Hibernate Bean实体和Spring Dao对象详解(图文)
- 用myeclipse创建spring+hibernate工程时候的jar包冲突问题!!!
- maven+Spring+SpringMVC+Hibernate快速搭建
- Struts+Spring+Hibernate快速入门
- JPA hibernate spring repository pgsql java 工程(三):数据表分区与自动创建:策略
- 快速搭建ibatis+tddl+spring工程构造数据
- Intellij Idea基于现有的Eclipse工程创建 多模块工程--spring spring mvc hibernate - SSH- resin
- Hibernate反向工程步骤及DAO Type无法选择Spring DAO解决方法
- 手把手教你从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate(含源码下载)