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

Struts+Spring+Hibernate开发实例

2014-09-11 14:33 465 查看

Struts+Spring+Hibernate开发实例

介绍

本文并不想介绍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 set>

10
同样在History.cfg.xml中加入:

1 <many-to-one name="student"

2 class="limq.hibernate.vo.Students"

3 column="student_id" >

4 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.Drivervalue>

8 property>

9 <property name="url">

10 <value>jdbc:mysql://localhost:3306/Studentvalue>

11 property>

12 <property name="username">

13 <value>rootvalue>

14 property>

15 <property name="password">

16 <value>value>

17 property>

18 bean>

19 <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">

20 <property name="dataSource">

21 <ref local="dataSource"/>

22 property>

23 <property name="mappingResources">

24 <list>

25 <value>limq/hibernate/vo/Admins.hbm.xmlvalue>

26 <value>limq/hibernate/vo/Classes.hbm.xmlvalue>

27 <value>limq/hibernate/vo/Courses.hbm.xmlvalue>

28 <value>limq/hibernate/vo/Students.hbm.xmlvalue>

29 <value>limq/hibernate/vo/ClassesInfo.hbm.xmlvalue>

30 <value>limq/hibernate/vo/Contact.hbm.xmlvalue>

31 <value>limq/hibernate/vo/Department.hbm.xmlvalue>

32 <value>limq/hibernate/vo/History.hbm.xmlvalue>

33 <value>limq/hibernate/vo/Teachers.hbm.xmlvalue>

34 list>

35 property>

36 <property name="hibernateProperties">

37 <props>

38 <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialectprop>

39 <prop key="hibernate.show_sql">trueprop>

40 props>

41 property>

42 bean>

43 <bean id="myTransactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">

44 <property name="sessionFactory">

45 <ref local="sessionFactory"/>

46 property>

47 bean>

48

49 <bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor">

50 <property name="sessionFactory">

51 <ref bean="sessionFactory"/>

52 property>

53 bean>

54 <bean id="studentDaoTarget" class="limq.hibernate.dao.StudentsDao">

55 <property name="sessionFactory">

56 <ref bean="sessionFactory"/>

57 property>

58 bean>

59 <bean id="teacherDaoTarget" class="limq.hibernate.dao.TeachersDao">

60 <property name="sessionFactory">

61 <ref bean="sessionFactory"/>

62 property>

63 bean>

64 <bean id="courseDaoTarget" class="limq.hibernate.dao.CoursesDao">

65 <property name="sessionFactory">

66 <ref bean="sessionFactory"/>

67 property>

68 bean>

69 <bean id="classDaoTarget" class="limq.hibernate.dao.ClassesDao">

70 <property name="sessionFactory">

71 <ref bean="sessionFactory"/>

72 property>

73 bean>

74 <bean id="departmentDaoTarget" class="limq.hibernate.dao.DepartmentDao">

75 <property name="sessionFactory">

76 <ref bean="sessionFactory"/>

77 property>

78 bean>

79 <bean id="adminDaoTarget" class="limq.hibernate.dao.AdminDao">

80 <property name="sessionFactory">

81 <ref bean="sessionFactory"/>

82 property>

83 bean>

84 <bean id="studentDao" class="org.springframework.aop.framework.ProxyFactoryBean">

85 <property name="proxyInterfaces">

86 <value>limq.hibernate.dao.IStudentsvalue>

87 property>

88 <property name="interceptorNames">

89 <list>

90 <value>hibernateInterceptorvalue>

91 <value>studentDaoTargetvalue>

92 list>

93 property>

94 bean>

95 <bean id="teacherDao" class="org.springframework.aop.framework.ProxyFactoryBean">

96 <property name="proxyInterfaces">

97 <value>limq.hibernate.dao.ITeachersvalue>

98 property>

99 <property name="interceptorNames">

100 <list>

101 <value>hibernateInterceptorvalue>

102 <value>teacherDaoTargetvalue>

103 list>

104 property>

105 bean>

106 <bean id="courseDao" class="org.springframework.aop.framework.ProxyFactoryBean">

107 <property name="proxyInterfaces">

108 <value>limq.hibernate.dao.ICoursesvalue>

109 property>

110 <property name="interceptorNames">

111 <list>

112 <value>hibernateInterceptorvalue>

113 <value>courseDaoTargetvalue>

114 list>

115 property>

116 bean>

117 <bean id="classDao" class="org.springframework.aop.framework.ProxyFactoryBean">

118 <property name="proxyInterfaces">

119 <value>limq.hibernate.dao.IClassesvalue>

120 property>

121 <property name="interceptorNames">

122 <list>

123 <value>hibernateInterceptorvalue>

124 <value>classDaoTargetvalue>

125 list>

126 property>

127 bean>

128 <bean id="departmentDao" class="org.springframework.aop.framework.ProxyFactoryBean">

129 <property name="proxyInterfaces">

130 <value>limq.hibernate.dao.IDepartmentvalue>

131 property>

132 <property name="interceptorNames">

133 <list>

134 <value>hibernateInterceptorvalue>

135 <value>departmentDaoTargetvalue>

136 list>

137 property>

138 bean>

139 <bean id="adminDao" class="org.springframework.aop.framework.ProxyFactoryBean">

140 <property name="proxyInterfaces">

141 <value>limq.hibernate.dao.IAdminvalue>

142 property>

143 <property name="interceptorNames">

144 <list>

145 <value>hibernateInterceptorvalue>

146 <value>adminDaoTargetvalue>

147 list>

148 property>

149 bean>

150

151 <bean id="studentManagerTarget" class="limq.spring.service.StudentsServiceImpl">

152 <property name="studentsDao">

153 <ref bean="studentDao"/>

154 property>

155 <property name="coursesDao">

156 <ref bean="courseDao"/>

157 property>

158 <property name="classesDao">

159 <ref bean="classDao"/>

160 property>

161 <property name="departmentsdao">

162 <ref bean="departmentDao"/>

163 property>

164 bean>

165 <bean id="teacherManagerTarget" class="limq.spring.service.TeachersServiceImpl">

166 <property name="teachersDao">

167 <ref bean="teacherDao"/>

168 property>

169 <property name="coursesDao">

170 <ref bean="courseDao"/>

171 property>

172 <property name="classesDao">

173 <ref bean="classDao"/>

174 property>

175 <property name="studentsDao">

176 <ref bean="studentDao"/>

177 property>

178 bean>

179 <bean id="adminManagerTarget" class="limq.spring.service.AdminServiceImpl">

180 <property name="adminDao">

181 <ref bean="adminDao"/>

182 property>

183 <property name="teachersDao">

184 <ref bean="teacherDao"/>

185 property>

186 <property name="coursesDao">

187 <ref bean="courseDao"/>

188 property>

189 <property name="classesDao">

190 <ref bean="classDao"/>

191 property>

192 <property name="studentsDao">

193 <ref bean="studentDao"/>

194 property>

195 <property name="departmentsdao">

196 <ref bean="departmentDao"/>

197 property>

198 bean>

199

200 <bean id="studentManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

201 <property name="transactionManager">

202 <ref bean="myTransactionManager"/>

203 property>

204 <property name="target">

205 <ref bean="studentManagerTarget"/>

206 property>

207 <property name="transactionAttributes">

208 <props>

209 <prop key="get*">PROPAGATION_SUPPORTSprop>

210 <prop key="*">PROPAGATION_REQUIREDprop>

211 props>

212 property>

213 bean>

214 <bean id="teacherManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

215 <property name="transactionManager">

216 <ref bean="myTransactionManager"/>

217 property>

218 <property name="target">

219 <ref bean="teacherManagerTarget"/>

220 property>

221 <property name="transactionAttributes">

222 <props>

223 <prop key="get*">PROPAGATION_SUPPORTSprop>

224 <prop key="*">PROPAGATION_REQUIREDprop>

225 props>

226 property>

227 bean>

228 <bean id="adminManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">

229 <property name="transactionManager">

230 <ref bean="myTransactionManager"/>

231 property>

232 <property name="target">

233 <ref bean="adminManagerTarget"/>

234 property>

235 <property name="transactionAttributes">

236 <props>

237 <prop key="get*">PROPAGATION_SUPPORTSprop>

238 <prop key="*">PROPAGATION_REQUIREDprop>

239 props>

240 property>

241 bean>

242 beans>

243

以StudentsServiceImpl以为例,下图演示了如何利用Spring的Ioc与Hibernate的结合。
可以看到分别将studentDao,classDao,coursesDao,departmentDao,注入studentManager.



1 IStudentsService.java

2 public interface IStudentsService {

3

4 public boolean validate(String username,String pasword);

5 public Classes[] getClassesFromCourse(Courses courses);

6 public Department getDepFromID(Integer id);

7 public Courses getCourseFromID(Integer id);

8 public Classes getClassFromID(Integer id);

9 public Students getStudetFromName(String name);

10 public boolean ifEnrolSameCourse(Classes clazz,Students stu);

11 public void selectClasses(Students stu, Classes clazz,Date date);

12 public boolean ifMoreThanCap(Classes clazz);

13 public void updateSudent(Students stu,Contact contact);

14 public HashMap getCourse(PageInfo pageinfo) throws Exception;

15 public HashMap getStudentHistory(PageInfo pageinfo,String stu_name) throws Exception;

16

17 }

18

19 实现StudentsServiceImpl.java

20 public class StudentsServiceImpl implements IStudentsService {

21

22 private Logger log = Logger.getLogger(this.getClass());

23

24 private IStudents studentsDao;

25

26 private ICourses coursesDao;

27

28 private IClasses classesDao;

29

30 private IDepartment departmentsdao;

31

32 /**

33 * 验证用户名密码

34 *

35 * @param username

36 * 用户名

37 * @param password

38 * 密码

39 */

40

41 public boolean validate(String username, String password) {

42

43 String password2 = studentsDao.getPasswordFromUsername(username);

44 if (password.equals(password2))

45 return true;

46 else

47 return false;

48

49 }

50

51 /**

52 * 查找所有课程

53 *

54 */

55 public Courses[] getAllCourses() {

56

57 List list = null;

58 try {

59

60 list = coursesDao.find("select c from Courses as c ");

61 } catch (Exception e) {

62 }

63

64 return (Courses[]) list.toArray(new Courses[0]);

65 }

66

67 /**

68 * 分页显示所有课程

69 *

70 * @param pageinfo

71 */

72 public HashMap getCourse(PageInfo pageinfo) throws Exception {

73

74 HashMap hp = new HashMap();

75 String hsql = "select c from Courses as c order by c.id";

76 Query query = coursesDao.getQuery(hsql);

77 int totalCount = pageinfo.getTatalCount();

78 int totalPage = pageinfo.getTotalpage();

79 int start = pageinfo.getStart();

80 totalCount = totalCount == -1 ? coursesDao.getTotalCount(hsql)

81 : totalCount;

82 totalPage = totalPage == -1 ? coursesDao.getTotalPage(totalCount,

83 pageinfo.getPageSize()) : totalPage;

84 query.setFirstResult(start);

85 query.setMaxResults(pageinfo.getPageSize());

86 List list = query.list();

87 hp.put("courses", (Courses[]) list.toArray(new Courses[0]));

88 hp.put("totalCount", new Integer(totalCount));

89 hp.put("totalPage", new Integer(totalPage));

90 return hp;

91 }

92 /**

93 * 分页显示所有选课历史

94 * @param pageinfo

95 * @param stu_name

96 */

97 public HashMap getStudentHistory(PageInfo pageinfo, String stu_name)

98 throws Exception {

99 HashMap hp = new HashMap();

100 Students stu = this.getStudetFromName(stu_name);

101 Integer stu_id = stu.getId();

102 Criteria criteria = coursesDao.getCriteria(History.class);

103 criteria.createCriteria("student").add(Expression.eq("name", stu_name));

104 int totalCount = pageinfo.getTatalCount();

105 int totalPage = pageinfo.getTotalpage();

106 int start = pageinfo.getStart();

107 totalCount = totalCount == -1 ? criteria.list().size() : totalCount;

108 totalPage = totalPage == -1 ? studentsDao.getTotalPage(totalCount,

109 pageinfo.getPageSize()) : totalPage;

110 criteria.setFirstResult(start);

111 criteria.setMaxResults(pageinfo.getPageSize());

112 criteria.addOrder(Order.asc("id"));

113 List list = criteria.list();

114 hp.put("history", (History[]) list.toArray(new History[0]));

115 hp.put("totalCount", new Integer(totalCount));

116 hp.put("totalPage", new Integer(totalPage));

117 return hp;

118 }

119 /**

120 * 根据课程查找班级

121 * @param course

122 * 课程实体

123 * @return 返回该课程下所有班级

124 */

125 public Classes[] getClassesFromCourse(Courses course) {

126 return coursesDao.getClassesFromCourse(course);

127 }

128

129 /**

130 * 根据主键查找系

131 * @param id

132 * 主键ID

133 */

134 public Department getDepFromID(Integer id) {

135 return (Department) departmentsdao

136 .loadByKey(Department.class, "id", id);

137 }

138

139 /**

140 * 根据主键查找课程

141 * @param id

142 * 主键ID

143 */

144 public Courses getCourseFromID(Integer id) {

145 return (Courses) coursesDao.loadByKey(Courses.class, "id", id);

146 }

147 /**

148 * 根据主键查找班级

149 * @param id

150 * 主键ID

151 */

152 public Classes getClassFromID(Integer id) {

153 return (Classes) classesDao.loadByKey(Classes.class, "id", id);

154 }

155

156 /**

157 * 根据姓名查找学生

158 * @param name

159 */

160 public Students getStudetFromName(String name) {

161 return (Students) studentsDao.loadByKey(Students.class, "name", name);

162 }

163

164 /**

165 * 检查学生是否选报了同一课程的班级

166 * @param clazz

167 * 所选报的班级

168 * @param stu

169 * 学生实体

170 * @return true 该生选报同一课程的班级

171 * @return false 没有报过该课程的班级,可以选报

172 *

173 */

174 public boolean ifEnrolSameCourse(Classes clazz, Students stu) {

175

176 Courses cour = clazz.getCourse();

177

178 Classes[] classes = (Classes[]) stu.getClasses()

179 .toArray(new Classes[0]);

180 for (int i = 0; i < classes.length; i++) {

181

182 Courses c1 = classes[i].getCourse();

183

184 if (c1.getId().equals(cour.getId()))

185 return true;

186 }

187 return false;

188 }

189

190 /**

191 * 检查课程的目前人数

192 * @param clazz

193 * 检查班级人数是否已满

194 * @param clazz

195 * 班级实体

196 * @return true 班级人数已满

197 * @return false 班级人数未满

198 *

199 */

200 public boolean ifMoreThanCap(Classes clazz) {

201 Integer capacity = clazz.getCapacity();

202 Integer maxcapacity = clazz.getMaxcapacity();

203 if (capacity.intValue() < maxcapacity.intValue()) {

204 clazz.setCapacity(Integer.valueOf(capacity.intValue() + 1));

205 //classesDao.update(clazz);

206 return false;

207 } else

208 return true;

209

210 }

211

212 /**

213 * 数据库插入选择班级的记录

214 * @param stu

215 * 学生

216 * @param clazz

217 * 所选择的班级

218 */

219 public void selectClasses(Students stu, Classes clazz, Date date)

220 {

221 stu.getClasses().add(clazz);

222 clazz.getStudents().add(stu);

223 History his = new History();

224 his.setEnrolTime(date);

225 his.setStudent(stu);

226 his.setClasses(clazz);

227 his.setScore(clazz.getCourse().getScore());

228 his.setMarking(new Double(0));

229 try{

230 String cour_name=new String(clazz.getCourse().getName().getBytes("GBK"));

231 his.setCourseName(cour_name);

232 }catch( java.io.UnsupportedEncodingException e){e.getStackTrace();}

233 stu.getHistory().add(his);

234 }

235

236 public void updateSudent(Students stu,Contact contact){

237

238 studentsDao.update(stu);

239 studentsDao.update(contact);

240

241 }

242 public IStudents getStudentsDao() {

243 return studentsDao;

244 }

245 public void setStudentsDao(IStudents studentsDao) {

246 this.studentsDao = studentsDao;

247 }

248 public IClasses getClassesDao() {

249 return classesDao;

250 }

251 public void setClassesDao(IClasses classesDao) {

252 this.classesDao = classesDao;

253 }

254 public ICourses getCoursesDao() {

255 return coursesDao;

256 }

257 public void setCoursesDao(ICourses coursesDao) {

258 this.coursesDao = coursesDao;

259 }

260 public IDepartment getDepartmentsdao() {

261 return departmentsdao;

262 }

263 public void setDepartmentsdao(IDepartment departmentdao) {

264 this.departmentsdao = departmentdao;

265 }

266 }

267

268

4 UI层

这里我们选择Struts,首先配置 web.xml

1 xml version="1.0" encoding="UTF-8"?>

2 <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
3 <context-param>

4 <param-name>contextConfigLocationparam-name>

5 <param-value>/WEB-INF/classes/applications-service.xmlparam-value>

6 context-param>

7 <context-param>

8 <param-name>log4jConfigLocationparam-name>

9 <param-value>/WEB-INF/log4j.propertiesparam-value>

10 context-param>

11 <filter>

12 <filter-name>hibernateFilterfilter-name>

13 <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class>

14 filter>

15 <filter-mapping>

16 <filter-name>hibernateFilterfilter-name>

17 <url-pattern>/*url-pattern>

18 filter-mapping>

19 <filter>

20 <filter-name>Set Character Encodingfilter-name>

21 <filter-class>limq.struts.SetCharacterEncodingFilterfilter-class>

22 filter>

23 <filter-mapping>

24 <filter-name>Set Character Encodingfilter-name>

25 <url-pattern>/*url-pattern>

26 filter-mapping>

27 <servlet>

28 <servlet-name>SpringContextServletservlet-name>

29 <servlet-class>org.springframework.web.context.ContextLoaderServletservlet-class>

30 <load-on-startup>1load-on-startup>

31 servlet>

32 <servlet>

33 <servlet-name>actionservlet-name>

34 <servlet-class>org.apache.struts.action.ActionServletservlet-class>

35 <init-param>

36 <param-name>configparam-name>

37 <param-value>/WEB-INF/struts-config.xmlparam-value>

38 init-param>

39 <init-param>

40 <param-name>debugparam-name>

41 <param-value>3param-value>

42 init-param>

43 <init-param>

44 <param-name>detailparam-name>

45 <param-value>3param-value>

46 init-param>

47 <load-on-startup>0load-on-startup>

48 servlet>

49 <servlet-mapping>

50 <servlet-name>actionservlet-name>

51 <url-pattern>*.dourl-pattern>

52 servlet-mapping>

53 web-app>

54

55
其中注意这几句,

1 <filter>

2 <filter-name>hibernateFilterfilter-name>

3 <filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class>

4 filter>

5 <filter-mapping>

6 <filter-name>hibernateFilterfilter-name>

7 <url-pattern>/*url-pattern>

8 filter-mapping>

9

由于我们使用了lazy = "true",如果想在UI层使用实体对象关联来获得其他对象时就会有这样的提示:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection

Spring 中引入了 OpenSessionInView模式可以处理以上问题,即在web.xml中加入以上代码。

接下来建立抽象BaseAction,和 BaseDispatchAction,其中后者与前者相似目的为减少Action的数量

1 abstract class BaseAction extends Action {

2

3 private IStudentsService studentsService;

4 private ITeachersService teachersSerivce;

5 private IAdminService adminService;

6 public void setServlet(ActionServlet actionServlet) {

7 super.setServlet(actionServlet);

8 ServletContext servletContext = actionServlet.getServletContext();

9 WebApplicationContext wac = WebApplicationContextUtils

10 .getRequiredWebApplicationContext(servletContext);

11

12 this.studentsService = (IStudentsService) wac.getBean("studentManager");

13 this.adminService = (IAdminService) wac.getBean("adminManager");

14 this.teachersSerivce = (ITeachersService) wac.getBean("teacherManager");

15 }

16 public IStudentsService getStudentsService() {

17 return studentsService;

18 }

19 public ITeachersService getTeachersSerivce() {

20 return teachersSerivce;

21 }

22 public void setTeachersSerivce(ITeachersService teachersSerivce) {

23 this.teachersSerivce = teachersSerivce;

24 }

25 public IAdminService getAdminService() {

26 return adminService;

27 }

28 public void setAdminService(IAdminService adminService) {

29 this.adminService = adminService;

30 }

31 }

32

BaseDispatchAction与之类似,请查看源码。其他Action都从这两个类继承。

以下就以查看课程下的班级为例演示Struts与Spring的使用:

1 CoursesAction.java

2 /**

3 * 查看课程下的班级

4 */

5 public ActionForward viewClassFromCourse(ActionMapping mapping,

6 ActionForm form, HttpServletRequest request,

7 HttpServletResponse response) throws Exception {

8 Integer cour_id = Integer.valueOf((request.getParameter("cour_id")));

9 Courses cour = super.getStudentsService().getCourseFromID(cour_id);

10 Classes[] clazz =(Classes[])cour.getClasses().toArray(new Classes[0]);

11 request.setAttribute("clazz", clazz);

12 return mapping.findForward("success");

13 }

14
这里从上一个页面获得课程编号 cour_id, 然后通过StudentsServiceImpl中的

1 public Courses getCourseFromID(Integer id) {

2 return (Courses) coursesDao.loadByKey(Courses.class, "id", id);

3 }

4
方法查到Courses实例,利用Courses和Classes的关联关系得到Classes[],在将其放入

Request. 通过mapping.findForward("success"),转发到

select_course_Content.jsp

CustomRequestProcessor.java 介绍



1 public class CustomRequestProcessor extends RequestProcessor {

2 protected boolean processPreprocess(HttpServletRequest request,

3 HttpServletResponse response) {

4 boolean continueProcessing = true;

5 HttpSession session = request.getSession();

6 String uri =request.getRequestURI();

7 if ( session == null || session.getAttribute("userName") == null ) {

8 continueProcessing = false;

9 if(uri.endsWith("login.do")) return true;

10 try{

11 response.sendRedirect("/StudentManger/login.jsp" );

12 }catch( Exception ex ){

13 log.error( "Problem sending redirect from processPreprocess()" );

14 }

15 }

16 return continueProcessing;

17 }

18 }

19


为了验证用户操作权限,这里扩展了Struts 的RequestProcessor来判断Session如果Session和userName都不空则程序继续,否则重定向到login.jsp。要想扩展RequestProcessor类,需在Struts的配置文件中加入

1 <controller

2 contentType="text/html;charset=UTF-8"

3 locale="true"

4 nocache="true"

5 processorClass="limq.struts.CustomRequestProcessor"/>

6
呵呵,当然在正规使用时仅仅这样验证是不够的。欢迎你把自己修改方法告诉我。

4分页处理:

下面重点讨论一下Hibernate的分页处理方式。

Hibernate 中处理查询主要有 Query ,Criteria,分别以 HSQL或编程方式实现,

本例对这两种方法都有相关处理。由于在Spring中无法直接使用Query和Criteria对象

所以只有先从Spring那里借一个Session,等使用完了在还给Sping处理。读者应该还记得在BaseDao中有这样的语句方便我们获取Session及其他对象:

1 public Query getQuery(String sql) throws Exception{

2 Session session = this.openSession();

3 Query query = session.createQuery(sql);

4 return query;

5 }

6

7 public Criteria getCriteria(Class clazz) throws Exception{

8

9 Session session=this.openSession();

10 Criteria criteria = session.createCriteria(clazz);

11 return criteria;

12 }

13
Service层以查询所有课程与学生选课记录为例处理Query与Criteria:

1 StudentsServiceImpl.java

2 public HashMap getCourse(PageInfo pageinfo) throws Exception {

3

4 HashMap hp = new HashMap();

5 String hsql = "select c from Courses as c order by c.id";

6 Query query = coursesDao.getQuery(hsql);

7 int totalCount = pageinfo.getTatalCount();

8 int totalPage = pageinfo.getTotalpage();

9 int start = pageinfo.getStart();

10 totalCount = totalCount == -1 ? coursesDao.getTotalCount(hsql)

11 : totalCount;

12 totalPage = totalPage == -1 ? coursesDao.getTotalPage(totalCount,

13 pageinfo.getPageSize()) : totalPage;

14 query.setFirstResult(start);

15 query.setMaxResults(pageinfo.getPageSize());

16 List list = query.list();

17 hp.put("courses", (Courses[]) list.toArray(new Courses[0]));

18 hp.put("totalCount", new Integer(totalCount));

19 hp.put("totalPage", new Integer(totalPage));

20 return hp;

21 }

22

23 public HashMap getStudentHistory(PageInfo pageinfo, String stu_name)

24 throws Exception {

25 HashMap hp = new HashMap();

26 Students stu = this.getStudetFromName(stu_name);

27 Integer stu_id = stu.getId();

28 Criteria criteria = coursesDao.getCriteria(History.class);

29 criteria.createCriteria("student").add(Expression.eq("name", stu_name));

30 int totalCount = pageinfo.getTatalCount();

31 int totalPage = pageinfo.getTotalpage();

32 int start = pageinfo.getStart();

33 totalCount = totalCount == -1 ? criteria.list().size() : totalCount;

34 totalPage = totalPage == -1 ? studentsDao.getTotalPage(totalCount,

35 pageinfo.getPageSize()) : totalPage;

36 criteria.setFirstResult(start);

37 criteria.setMaxResults(pageinfo.getPageSize());

38 criteria.addOrder(Order.asc("id"));

39 List list = criteria.list();

40 hp.put("history", (History[]) list.toArray(new History[0]));

41 hp.put("totalCount", new Integer(totalCount));

42 hp.put("totalPage", new Integer(totalPage));

43 return hp;

44 }

45 PageIngfo.java

46 public class PageInfo {

47

48 int pageNo=0;

49 int totalpage=-1;

50 int tatalCount=-1;

51 int pageSize=0;

52 int start=0;

53

54

可以看到getCourse和getStudentHistory有很多相似之处,Hibernate为Query和Criteria提供了针对不同数据库的解决分页方法, Quey需要我们写HSQL, Criteria不但可以应付带有条件的查询,还不用我们自己写HSQL,PageInfo是含有分页信息的普通java类。

再看看Struts是如何调用getStudentHistory 的,

1 PageAction.java

2 public class PageAction extends BaseDispatchAction{

3 public ActionForward execute(ActionMapping mapping,

4 ActionForm form,

5 HttpServletRequest request,

6 HttpServletResponse response)

7 throws Exception {

8 String pageNo=request.getParameter("pageNo");

9 String totalcount=request.getParameter("totalcount");

10 String totalpage=request.getParameter("totalpage");

11 int pagesize=2;//每页的大小

12 PageInfo page =new PageInfo();

13 page.setPageSize(pagesize);

14 HashMap hp=null;

15 History[] historys = null;

16 String stu_name=null;

17 HttpSession session = request.getSession();

18 stu_name = (String) session.getAttribute("userName");

19 if(pageNo == null || totalcount == null || totalpage==null){

20 //第一次发送请求

21 page.setPageNo(1);

22 hp=super.getStudentsService().getStudentHistory(page,stu_name);

23 page.setTatalCount(((Integer)hp.get("totalCount")).intValue());

24 page.setTotalpage(((Integer)hp.get("totalPage")).intValue());

25 }else{

26 page.setPageNo(Integer.parseInt(pageNo));

27 page.setTatalCount(Integer.parseInt(totalcount));

28 page.setTotalpage(Integer.parseInt(totalpage));

29 hp=super.getStudentsService().getStudentHistory(page,stu_name);

30

31 }

32 historys =(History[]) hp.get("history");

33 request.setAttribute("history",historys);

34 request.setAttribute("pageinfo",page);

35 return mapping.findForward("success");

36 }

37 }

38

在stu_his_Content.jsp中避免代码重复使用了自定义标志来处理分页

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %>

2 <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>

3 <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>

4 <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

5 <%@ page import="limq.hibernate.vo.*"%>

6 <%@ taglib uri="/WEB-INF/MyTag.tld" prefix="mytag"%>

7 <%@ page import="limq.common.*"%>

8 <html:html locale="true">

9 <body>

10 <%

11 PageInfo pageinfo =(PageInfo) request.getAttribute("pageinfo");

12 History[] historys = (History[])request.getAttribute("history");

13 %>

14 <table width="550" border="1" cellspacing="0" align="center" cellpadding="0">

15 <tr>

16 <td><bean:message key="class.id"/>td>

17 <td><bean:message key="course.name"/>td>

18 <td><bean:message key="enrol.time"/>td>

19 <td><bean:message key="score"/>td>

20 <td><bean:message key="marking"/>td>

21 tr>

22 <%

23 for(int i=0;i<historys.length;i++){

24 History his=historys[i];

25 %>

26 <tr>

27 <td><%=his.getClasses().getId()%>td>

28 <td><%=his.getCourseName()%>td>

29 <td><%=his.getEnrolTime()%>td>

30 <td><%=his.getScore()%>td>

31 <td><%=his.getMarking()%>td>

32 tr>

33 <%

34 }

35 %>

36 table>

37 <mytag:page pageinfo="<%=pageinfo%>" action="getHistory.do"/>

38 body>

39 html:html>

40

标志处理类如下:

1 PageTag.java

2

3 public class PageTag extends SimpleTagSupport {

4

5 private PageInfo pageinfo = null;

6 private String action = null;

7

8 public String getAction() {

9 return action;}

10 public void setAction(String action) {

11 this.action = action;

12 }

13 public PageInfo getPageinfo() {

14 return pageinfo;

15 }

16 public void setPageinfo(PageInfo pageinfo) {

17 this.pageinfo = pageinfo;

18 }

19

20 public void doTag() throws JspException, IOException {

21 JspWriter out = getJspContext().getOut();

22

23 int totalpage = pageinfo.getTotalpage();

24 int totalcount = pageinfo.getTatalCount();

25 int pageNo = pageinfo.getPageNo();

26 int addPageNo = pageNo + 1;

27 int minPageNo = pageNo - 1;

28

29 out.println("<table width=\<>"400\" align=\"center\" cellPadding=\"0\" cellSpacing=\"0\"> ");

30 out.print("");

31 out.println("

共</td width=47%>" + totalcount + "条," + totalpage + "页,当前"

32 + pageNo + "页</table width=\<>
");

66

67 }

68

69 }

70


5 中文乱码问题:


1 数据库:MYSQL 4.1 (或以上版本)4.1直接支持Unicode,以下版本支持的不好。

2 驱动: MySQL JDBC Driver的3.0.16(或以上版本)

3 在数据库中做如下设定



4 在建立表时同样加上ENGINE=MyISAM DEFAULT CHARSET=gbk

1CREATE TABLE `students` (

2 `id` int(20) NOT NULL default '0',

3 `name` varchar(20) NOT NULL default '',

4 `department_id` int(11) default NULL,

5 `password` varchar(20) default NULL,

6 `score` double(15,3) default NULL,

7 PRIMARY KEY (`id`)

8) ENGINE=MyISAM DEFAULT CHARSET=gbk

9
5 配置hibernate.cfg.xml

1 <property name="connection.url">jdbc:mysql://localhost:3306/Studentproperty>

2 <property name="dialect">net.sf.hibernate.dialect.MySQLDialectproperty>

3 <property name="connection.password">property>

4 <property name="connection.driver_class">com.mysql.jdbc.Driverproperty>

5
robbin: MySQL JDBC Driver的3.0.16也是一个分水岭,3.0.16版本会取数据库本身的编码,然后按照该编码转换,这种方式和Oracle的JDBC Driver是一样的。例如你的数据库是GBK编码的话,JDBC Driver就会把数据库里面的取出来的字符串按照GBK往unicode转换,送给JVM。因此正确的设置数据库本身的编码就尤为重要。

MySQL JDBC Driver3.0.16以下的版本则不然,它不会那么智能的根据数据库编码来确定如何转换,它总是默认使用ISO8859-1,因此你必须使用 characterEncoding=GBK来强制他把数据库中取出来的字符串按照GBK来往unicode转换。

因此,使用什么数据库版本,不管是3.x,还是4.0.x还是4.1.x,其实对我们来说不重要,重要的有二:

1) 正确的设定数据库编码,MySQL4.0以下版本的字符集总是默认ISO8859-1,MySQL4.1在安装的时候会让你选择。如果你准备使用UTF- 8,那么在创建数据库的时候就要指定好UTF-8(创建好以后也可以改,4.1以上版本还可以单独指定表的字符集)

2) 使用3.0.16以上版本的JDBC Driver,那么你就不需要再写什么characterEncoding=UTF-8

6 开发工具介绍

MyEclipse 3.8

首先添加用户库,如下图将Struts,Spring,Hibernate 的库添加到用户库中



如果出现环境问题可能你的Struts包有问题,请到http://struts.apache.org/download.cgi下载struts-1.2.7-lib.zip

具体使用参考http://www.laliluna.de/struts-hibernate-integration-tutorial-en.html

总结

本文至此已将Struts+Sprng+Hibernate的大致思路以及本人所遇到的难点,重点介绍完了。

其中管理员我只完成了对学生的部分,其他功能大同小异,有兴趣的读者不妨动手试试。最后建议初学者不要直接使用Spring对Hibernate的封装,而是从Hibernate学起,先要学会自己管理Session,Transaction,然后在用Spring,这样理解会更深刻。同时如果你有好的建议,或问题请联系我

QQ 39315890

Email: mill_lmq@yahoo.com.cn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: