一
介绍
本文并不想介绍Struts,Spring,Hibernate的原理系统架构等,本文地目的是通过一个较复杂地实例介绍如何整合Struts,Spring,Hibernate,网上现有的例子虽然也能达到目的,但功能都比较单一,复杂的例子时会有意想不到的麻烦。本文对读者假设已经具备了以上框架的基础知识。以及那些已经了解Struts,Spring,Hibernate的基本概念,但是还没有亲身在较复杂的项目中体验Struts+Spring+Hibernate的开发人员。
1 Struts
虽然不打算过多介绍Struts的原理,但是大概介绍一下还是有必要的。Struts本身就是 MVC 在这里负责将用户数据传人业务层,以及 将业务层处理的结果返回给用户,此系统属于较简单WEB应用,采用了OpenSessionInView模式处理LazyLoad问题,这样我们可以在用户视图中使用 get,set方法来方便地获取关联对象。为了处理庞大的Action和ActionForm问题,在此我门准备使用DynaActionForm (DynaValidatorForm)和DispatchAction以及 动态验证框架 来解决。及使用Tile来解决框架问题 。使用自定义标签处理分页和身份验证问题。
2 Spring
Spring Framework最得以出名的是与Hibernate的无缝链接,虽然Spring 对Hibernate提供了90%以上的封装,使我们不必去关心Session 的建立,关闭,以及事务使我们能够专心的关注业务逻辑。但是一些特殊情况如 有时需要Query以及Criteria 对象,分页等,Spring不能给我们提供支持,总不能每次都在你的DAO上写个HibernateCallBackup()吧?Spring的作用不是把Hibernate再封装一层,而是让你接触不到Hibernate的API,而是帮助你管理好Session和Transaction。
在这里解决方法是:首先 写一个IBase 的接口,和一个BaseDao的实现。在实现中仿照HibernateTemplate,将其功能一一实现,同时考虑到Spring 未能支持的地方,我们不得已只好自己来管理Session,因此加入public Session openSession(),public Query getQuery(String sql),public Criteria getCriteria(Class clazz),以及分页的方法。 然后为每一个Entity 都建立继承于以上类的IEntity,与EntityDao。这里可以根据需求对Entity加入特殊的方法实现,如 在 StudentsDao.java 中加入类似用户身份验证等。以上就是数据访问层。接下来在Service层中通过对dao的引用完成业务逻辑方法。在下面的例子中我们分别为学生模块,教师模块,管理员模块构建Service层,StudentsServiceImpl,TeachersServiceImpl,AdminServiceImpl。
3 Hibernate
有了Spring的封装,我们要对Hibernate做的就是正确实现对象关系的映射。由于此处处于系统的最底层,准确无误的实现对象之间的关联关系映射将起着至关重要的作用。
总之,理解了Struts,Spring,Hibernate地原理以及之间的关系之后,剩下的工作就如同在以Spring为核心的Struts为表现的框架中堆积木。
下图可以更好的帮助我们理解Struts,Spring,Hibernate之间的关系。

二 案例简述:
设计思路主要源于 大学选修课,该系统可以方便处理学生在课程选报,学分查询,成绩查询,以及 成绩发布等。
系统以班级为核心,一门课程可以对应多个班级,一名教师也可以带不同的班级,学生可以选报不同课程所对应的班级,班级自身有目前人数,和最大人数,以及上课时间,上课地点的属性。
学生在选报班级之后,班级的人数会自动加一,直到等于最大人数时,其他学生将会有人数已满的错误提示。同理如果学生选择了同一课程的不同班级,也将收到错误提示。学生有密码,系别,学分,地址,电话等属性。
教师在系统中主要负责成绩发布,教师可以对其所带的班级的学生的成绩修改,系统会以成绩是否大于等于60来判断学生是否通过考试,如果通过会将该课程的学分累加到学生学分,同样如果教师二次修改了成绩,而且小于60,系统会在学生学分上扣掉该课程的分数。
课程在系统中具体体现为班级,自身带有学分属性。
系有编号,名称的属性,同时可以作为联系教师,课程,学生的桥梁。
功能模块
l 身份验证模块: 根据用户名,密码,用户类别 转发用户到不同的模块。
l 学生模块: 查看课程,查看班级,选报课程,查看己选课程,成绩查询。
l 教师模块: 录入成绩
l 管理员模块:对学生,教师,课程,班级,系 增,删,查,改。
三 具体实践
代码下载
http://www.blogjava.net/Files/limq/StudentManger.rar
1 对象关系映射:
首先,将库表映射为数据模型(SQL在源码中查看),转换后的数据模型如下图:

由此我们可以看出一下关联关系:
1 Students 和 Contact(联系方式)一对一关系。
2 Students 和 History(选课历史) 一对多关系
3 Students 和 Classes 多对多关系。
4 Classes 和 Classes_info 一对多关系。
5 Classes 和 Teachers 多对一关系。
6 Classes 和 Courses 多对一关系。
7 Course 和 Department(系) 多对一关系。
8 Teachers 和 Department 多对一关系。
9 Students 和 Department 多对一关系。
在Hibernate中将以上关系一一映射,如Students 和 History 一对多关系
Students.cfg.xm.:
1 <set name="history"
2 table="history"
3 cascade="all"
4 inverse="true"
5 lazy="true" >
6 <key column="student_id"/>
7 <one-to-many class="limq.hibernate.vo.History"
8 />
9 < SPAN>set>
10
同样在History.cfg.xml中加入:
1 <many-to-one name="student"
2 class="limq.hibernate.vo.Students"
3 column="student_id" >
4 < SPAN>many-to-one>
5
用过MyEclipse开发Hibernate的就知道,MyEclipse会帮助我们生成持久对象和抽象对象,我们要在 Students.java 中加入对History的引用
private Set history=new HashSet();
public Set getHistory() {
return history;
}
public void setHistory(Set history) {
this.history = history;
}
同时,在AbstractHistory.java 中删除student_id 以及对应的get,set 方法,History.java 中加入
private Students student;
public Students getStudent() {
return student;
}
public void setStudent(Students student) {
this.student = student;
}
具体内容请查看 源代码。
2 DAO 数据访问层
首先,编写IBaseDao与BaseDao,其中IBaseDao代码如下:
1 package limq.hibernate.dao;
2
3 import java.util.Collection;
4 import java.util.List;
5 import net.sf.hibernate.Criteria;
6 import net.sf.hibernate.Query;
7 import net.sf.hibernate.Session;
8 import limq.exception.DaoException;
9
10 public interface IBaseDao {
11
12 public Session openSession();
13
14 public int getTotalCount( String hql) throws Exception;
15
16 public Query getQuery(String sql) throws Exception;
17
18 public Criteria getCriteria(Class clazz) throws Exception;
19
20 public int getTotalPage(int totalCount,int pageSize);
21
22 public void create(Object entity);
23
24 public void update(Object entity);
25
26 public void delete(Object entity) throws DaoException;
27
28 public void deleteAll(Class clazz) throws DaoException;
29
30 public void deleteAll(Collection entities) throws DaoException;
31
32 public Object loadByKey(Class clazz, String keyName, Object keyValue);
33
34 public List find(String queryString) throws DaoException;
35
36 public List find(String queryString, Object param) throws DaoException;
37
38 public List find(String queryString, Object[] params) throws DaoException;
39
40 }
41
BaseDao继承org.springframework.orm.hibernate.support.HibernateDaoSupport
实现以上的 定义的方法
如:
1 public void create(Object entity) {
2 try {
3 getHibernateTemplate().save(entity);
4
5 } catch (Exception e) {
6 log.error("保存 " + entity.getClass().getName() + " 实例到数据库失败", e);
7
8 }
9 }
10 /**
11 * 获得session
12 */
13 public Session openSession() {
14 return SessionFactoryUtils.getSession(getSessionFactory(), false);
15 }
16
17 /**
18 * 获得Query对象
19 */
20 public Query getQuery(String sql) throws Exception{
21 Session session = this.openSession();
22 Query query = session.createQuery(sql);
23 return query;
24 }
25 /**
26 * 获得Criteria对象
27 */
28 public Criteria getCriteria(Class clazz) throws Exception{
29
30 Session session=this.openSession();
31 Criteria criteria = session.createCriteria(clazz);
32 return criteria;
33 }
34
可以看到,这里即充分利用了Spring对Hibernate的支持,还弥补了Spring的不足。最后分别为每个持久对象建立Interface,以及DAO,使其分别继承IBaseDao与BaseDao。
如IDepartment,DepartmentDao
1 public interface IDepartment extends IBaseDao {}
2
3 public class DepartmentDao extends BaseDao implements IBaseDao {}
4
3 Service 层
在这里需要认真思考每个业务逻辑所能用到的持久层对象和DAO,还要完成配置Spring框架, 首先我一起看看applications-service.xml
1 xml version="1.0" encoding="UTF-8"?>
2 DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
3 "http://www.springframework.org/dtd/spring-beans.dtd">
4 <beans>
5 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
6 <property name="driverClassName">
7 <value>com.mysql.jdbc.Driver< SPAN>value>
8 < SPAN>property>
9 <property name="url">
10 <value>jdbc:mysql://localhost:3306/Student< SPAN>value>
11 < SPAN>property>
12 <property name="username">
13 <value>root< SPAN>value>
14 < SPAN>property>
15 <property name="password">
16 <value>< SPAN>value>
17 < SPAN>property>
18 < SPAN>bean>
19 <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
20 <property name="dataSource">
21 <ref local="dataSource"/>
22 < SPAN>property>
23 <property name="mappingResources">
24 <list>
25 <value>limq/hibernate/vo/Admins.hbm.xml< SPAN>value>
26 <value>limq/hibernate/vo/Classes.hbm.xml< SPAN>value>
27 <value>limq/hibernate/vo/Courses.hbm.xml< SPAN>value>
28 <value>limq/hibernate/vo/Students.hbm.xml< SPAN>value>
29 <value>limq/hibernate/vo/ClassesInfo.hbm.xml< SPAN>value>
30 <value>limq/hibernate/vo/Contact.hbm.xml< SPAN>value>
31 <value>limq/hibernate/vo/Department.hbm.xml< SPAN>value>
32 <value>limq/hibernate/vo/History.hbm.xml< SPAN>value>
33 <value>limq/hibernate/vo/Teachers.hbm.xml< SPAN>value>
34 < SPAN>list>
35 < SPAN>property>
36 <property name="hibernateProperties">
37 <props>
38 <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect< SPAN>prop>
39 <prop key="hibernate.show_sql">true< SPAN>prop>
40 < SPAN>props>
41 < SPAN>property>
42 < SPAN>bean>
43 <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
44 <property name="sessionFactory">
45 <ref local="sessionFactory"/>
46 < SPAN>property>
47 < SPAN>bean>
48
49 <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">
50 <property name="sessionFactory">
51 <ref bean="sessionFactory"/>
52 < SPAN>property>
53 < SPAN>bean>
54 <bean id="studentDaoTarget" class="limq.hibernate.dao.StudentsDao">
55 <property name="sessionFactory">
56 <ref bean="sessionFactory"/>
57 < SPAN>property>
58 < SPAN>bean>
59 <bean id="teacherDaoTarget" class="limq.hibernate.dao.TeachersDao">
60 <property name="sessionFactory">
61 <ref bean="sessionFactory"/>
62 < SPAN>property>
63 < SPAN>bean>
64 <bean id="courseDaoTarget" class="limq.hibernate.dao.CoursesDao">
65 <property name="sessionFactory">
66 <ref bean="sessionFactory"/>
67 < SPAN>property>
68 < SPAN>bean>
69 <bean id="classDaoTarget" class="limq.hibernate.dao.ClassesDao">
70 <property name="sessionFactory">
71 <ref bean="sessionFactory"/>
72 < SPAN>property>
73 < SPAN>bean>
74 <bean id="departmentDaoTarget" class="limq.hibernate.dao.DepartmentDao">
75 <property name="sessionFactory">
76 <ref bean="sessionFactory"/>
77 < SPAN>property>
78 < SPAN>bean>
79 <bean id="adminDaoTarget" class="limq.hibernate.dao.AdminDao">
80 <property name="sessionFactory">
81 <ref bean="sessionFactory"/>
82 < SPAN>property>
83 < SPAN>bean>
84 <bean id="studentDao" class="org.springframework.aop.framework.ProxyFactoryBean">
85 <property name="proxyInterfaces">
86 <value>limq.hibernate.dao.IStudents< SPAN>value>
87 < SPAN>property>
88 <property name="interceptorNames">
89 <list>
90 <value>hibernateInterceptor< SPAN>value>
91 <value>studentDaoTarget< SPAN>value>
92 < SPAN>list>
93 < SPAN>property>
94 < SPAN>bean>
95 <bean id="teacherDao" class="org.springframework.aop.framework.ProxyFactoryBean">
96 <property name="proxyInterfaces">
97 <value>limq.hibernate.dao.ITeachers< SPAN>value>
98 < SPAN>property>
99 <property name="interceptorNames">
100 <list>
101 <value>hibernateInterceptor< SPAN>value>
102 <value>teacherDaoTarget< SPAN>value>
103 < SPAN>list>
104 < SPAN>property>
105 < SPAN>bean>
106 <bean id="courseDao" class="org.springframework.aop.framework.ProxyFactoryBean">
107 <property name="proxyInterfaces">
108 <value>limq.hibernate.dao.ICourses< SPAN>value>
109 < SPAN>property>
110 <property name="interceptorNames">
111 <list>
112 <value>hibernateInterceptor< SPAN>value>
113 <value>courseDaoTarget< SPAN>value>
114 < SPAN>list>
115 < SPAN>property>
116 < SPAN>bean>
117 <bean id="classDao" class="org.springframework.aop.framework.ProxyFactoryBean">
118 <property name="proxyInterfaces">
119 <value>limq.hibernate.dao.IClasses< SPAN>value>
120 < SPAN>property>
121 <property name="interceptorNames">
122 <list>
123 <value>hibernateInterceptor< SPAN>value>
124 <value>classDaoTarget< SPAN>value>
125 < SPAN>list>
126 < SPAN>property>
127 < SPAN>bean>
128 <bean id="departmentDao" class="org.springframework.aop.framework.ProxyFactoryBean">
129 <property name="proxyInterfaces">
130 <value>limq.hibernate.dao.IDepartment< SPAN>value>
131 < SPAN>property>
132 <property name="interceptorNames">
133 <list>
134 <value>hibernateInterceptor< SPAN>value>
135 <value>departmentDaoTarget< SPAN>value>
136 < SPAN>list>
137 < SPAN>property>
138 < SPAN>bean>
139 <bean id="adminDao" class="org.springframework.aop.framework.ProxyFactoryBean">
140 <property name="proxyInterfaces">
141 <value>limq.hibernate.dao.IAdmin< SPAN>value>
142 < SPAN>property>
143 <property name="interceptorNames">
144 <list>
145 <value>hibernateInterceptor< SPAN>value>
146 <value>adminDaoTarget< SPAN>value>
147 < SPAN>list