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),publicCriteria 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<setname="history"
2table="history"
3cascade="all"
4inverse="true"
5lazy="true">
6<keycolumn="student_id"/>
7<one-to-manyclass="limq.hibernate.vo.History"
8/>
9set>
10

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

1<many-to-onename="student"
2class="limq.hibernate.vo.Students"
3column="student_id">
4many-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代码如下:

1packagelimq.hibernate.dao;
2
3importjava.util.Collection;
4importjava.util.List;
5importnet.sf.hibernate.Criteria;
6importnet.sf.hibernate.Query;
7importnet.sf.hibernate.Session;
8importlimq.exception.DaoException;
9
10publicinterfaceIBaseDao{
11
12publicSessionopenSession();
13
14publicintgetTotalCount(Stringhql)throwsException;
15
16publicQuerygetQuery(Stringsql)throwsException;
17
18publicCriteriagetCriteria(Classclazz)throwsException;
19
20publicintgetTotalPage(inttotalCount,intpageSize);
21
22publicvoidcreate(Objectentity);
23
24publicvoidupdate(Objectentity);
25
26publicvoiddelete(Objectentity)throwsDaoException;
27
28publicvoiddeleteAll(Classclazz)throwsDaoException;
29
30publicvoiddeleteAll(Collectionentities)throwsDaoException;
31
32publicObjectloadByKey(Classclazz,StringkeyName,ObjectkeyValue);
33
34publicListfind(StringqueryString)throwsDaoException;
35
36publicListfind(StringqueryString,Objectparam)throwsDaoException;
37
38publicListfind(StringqueryString,Object[]params)throwsDaoException;
39
40}
41

BaseDao继承org.springframework.orm.hibernate.support.HibernateDaoSupport

实现以上的定义的方法

如:

1publicvoidcreate(Objectentity){
2try{
3getHibernateTemplate().save(entity);
4
5}catch(Exceptione){
6log.error("保存"+entity.getClass().getName()+"实例到数据库失败",e);
7
8}
9}
10/**
11*获得session
12*/
13publicSessionopenSession(){
14returnSessionFactoryUtils.getSession(getSessionFactory(),false);
15}
16
17/**
18*获得Query对象
19*/
20publicQuerygetQuery(Stringsql)throwsException{
21Sessionsession=this.openSession();
22Queryquery=session.createQuery(sql);
23returnquery;
24}
25/**
26*获得Criteria对象
27*/
28publicCriteriagetCriteria(Classclazz)throwsException{
29
30Sessionsession=this.openSession();
31Criteriacriteria=session.createCriteria(clazz);
32returncriteria;
33}
34

可以看到,这里即充分利用了Spring对Hibernate的支持,还弥补了Spring的不足。最后分别为每个持久对象建立Interface,以及DAO,使其分别继承IBaseDao与BaseDao。

如IDepartment,DepartmentDao

1publicinterfaceIDepartmentextendsIBaseDao{}
2
3publicclassDepartmentDaoextendsBaseDaoimplementsIBaseDao{}
4

3 Service 层

在这里需要认真思考每个业务逻辑所能用到的持久层对象和DAO,还要完成配置Spring框架, 首先我一起看看applications-service.xml

1xmlversion="1.0"encoding="UTF-8"?>
2DOCTYPEbeansPUBLIC"-//SPRING//DTDBEAN//EN"
3"http://www.springframework.org/dtd/spring-beans.dtd">
4<beans>
5<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
6<propertyname="driverClassName">
7<value>com.mysql.jdbc.Drivervalue>
8property>
9<propertyname="url">
10<value>jdbc:mysql://localhost:3306/Studentvalue>
11property>
12<propertyname="username">
13<value>rootvalue>
14property>
15<propertyname="password">
16<value>value>
17property>
18bean>
19<beanid="sessionFactory"class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
20<propertyname="dataSource">
21<reflocal="dataSource"/>
22property>
23<propertyname="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>
34list>
35property>
36<propertyname="hibernateProperties">
37<props>
38<propkey="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialectprop>
39<propkey="hibernate.show_sql">trueprop>
40props>
41property>
42bean>
43<beanid="myTransactionManager"class="org.springframework.orm.hibernate.HibernateTransactionManager">
44<propertyname="sessionFactory">
45<reflocal="sessionFactory"/>
46property>
47bean>
48
49<beanid="hibernateInterceptor"class="org.springframework.orm.hibernate.HibernateInterceptor">
50<propertyname="sessionFactory">
51<refbean="sessionFactory"/>
52property>
53bean>
54<beanid="studentDaoTarget"class="limq.hibernate.dao.StudentsDao">
55<propertyname="sessionFactory">
56<refbean="sessionFactory"/>
57property>
58bean>
59<beanid="teacherDaoTarget"class="limq.hibernate.dao.TeachersDao">
60<propertyname="sessionFactory">
61<refbean="sessionFactory"/>
62property>
63bean>
64<beanid="courseDaoTarget"class="limq.hibernate.dao.CoursesDao">
65<propertyname="sessionFactory">
66<refbean="sessionFactory"/>
67property>
68bean>
69<beanid="classDaoTarget"class="limq.hibernate.dao.ClassesDao">
70<propertyname="sessionFactory">
71<refbean="sessionFactory"/>
72property>
73bean>
74<beanid="departmentDaoTarget"class="limq.hibernate.dao.DepartmentDao">
75<propertyname="sessionFactory">
76<refbean="sessionFactory"/>
77property>
78bean>
79<beanid="adminDaoTarget"class="limq.hibernate.dao.AdminDao">
80<propertyname="sessionFactory">
81<refbean="sessionFactory"/>
82property>
83bean>
84<beanid="studentDao"class="org.springframework.aop.framework.ProxyFactoryBean">
85<propertyname="proxyInterfaces">
86<value>limq.hibernate.dao.IStudentsvalue>
87property>
88<propertyname="interceptorNames">
89<list>
90<value>hibernateInterceptorvalue>
91<value>studentDaoTargetvalue>
92list>
93property>
94bean>
95<beanid="teacherDao"class="org.springframework.aop.framework.ProxyFactoryBean">
96<propertyname="proxyInterfaces">
97<value>limq.hibernate.dao.ITeachersvalue>
98property>
99<propertyname="interceptorNames">
100<list>
101<value>hibernateInterceptorvalue>
102<value>teacherDaoTargetvalue>
103list>
104property>
105bean>
106<beanid="courseDao"class="org.springframework.aop.framework.ProxyFactoryBean">
107<propertyname="proxyInterfaces">
108<value>limq.hibernate.dao.ICoursesvalue>
109property>
110<propertyname="interceptorNames">
111<list>
112<value>hibernateInterceptorvalue>
113<value>courseDaoTargetvalue>
114list>
115property>
116bean>
117<beanid="classDao"class="org.springframework.aop.framework.ProxyFactoryBean">
118<propertyname="proxyInterfaces">
119<value>limq.hibernate.dao.IClassesvalue>
120property>
121<propertyname="interceptorNames">
122<list>
123<value>hibernateInterceptorvalue>
124<value>classDaoTargetvalue>
125list>
126property>
127bean>
128<beanid="departmentDao"class="org.springframework.aop.framework.ProxyFactoryBean">
129<propertyname="proxyInterfaces">
130<value>limq.hibernate.dao.IDepartmentvalue>
131property>
132<propertyname="interceptorNames">
133<list>
134<value>hibernateInterceptorvalue>
135<value>departmentDaoTargetvalue>
136list>
137property>
138bean>
139<beanid="adminDao"class="org.springframework.aop.framework.ProxyFactoryBean">
140<propertyname="proxyInterfaces">
141<value>limq.hibernate.dao.IAdminvalue>
142property>
143<propertyname="interceptorNames">
144<list>
145<value>hibernateInterceptorvalue>
146<value>adminDaoTargetvalue>
147list>
148property>
149bean>
150
151<beanid="studentManagerTarget"class="limq.spring.service.StudentsServiceImpl">
152<propertyname="studentsDao">
153<refbean="studentDao"/>
154property>
155<propertyname="coursesDao">
156<refbean="courseDao"/>
157property>
158<propertyname="classesDao">
159<refbean="classDao"/>
160property>
161<propertyname="departmentsdao">
162<refbean="departmentDao"/>
163property>
164bean>
165<beanid="teacherManagerTarget"class="limq.spring.service.TeachersServiceImpl">
166<propertyname="teachersDao">
167<refbean="teacherDao"/>
168property>
169<propertyname="coursesDao">
170<refbean="courseDao"/>
171property>
172<propertyname="classesDao">
173<refbean="classDao"/>
174property>
175<propertyname="studentsDao">
176<refbean="studentDao"/>
177property>
178bean>
179<beanid="adminManagerTarget"class="limq.spring.service.AdminServiceImpl">
180<propertyname="adminDao">
181<refbean="adminDao"/>
182property>
183<propertyname="teachersDao">
184<refbean="teacherDao"/>
185property>
186<propertyname="coursesDao">
187<refbean="courseDao"/>
188property>
189<propertyname="classesDao">
190<refbean="classDao"/>
191property>
192<propertyname="studentsDao">
193<refbean="studentDao"/>
194property>
195<propertyname="departmentsdao">
196<refbean="departmentDao"/>
197property>
198bean>
199
200<beanid="studentManager"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
201<propertyname="transactionManager">
202<refbean="myTransactionManager"/>
203property>
204<propertyname="target">
205<refbean="studentManagerTarget"/>
206property>
207<propertyname="transactionAttributes">
208<props>
209<propkey="get*">PROPAGATION_SUPPORTSprop>
210<propkey="*">PROPAGATION_REQUIREDprop>
211props>
212property>
213bean>
214<beanid="teacherManager"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
215<propertyname="transactionManager">
216<refbean="myTransactionManager"/>
217property>
218<propertyname="target">
219<refbean="teacherManagerTarget"/>
220property>
221<propertyname="transactionAttributes">
222<props>
223<propkey="get*">PROPAGATION_SUPPORTSprop>
224<propkey="*">PROPAGATION_REQUIREDprop>
225props>
226property>
227bean>
228<beanid="adminManager"class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
229<propertyname="transactionManager">
230<refbean="myTransactionManager"/>
231property>
232<propertyname="target">
233<refbean="adminManagerTarget"/>
234property>
235<propertyname="transactionAttributes">
236<props>
237<propkey="get*">PROPAGATION_SUPPORTSprop>
238<propkey="*">PROPAGATION_REQUIREDprop>
239props>
240property>
241bean>
242beans>
243

StudentsServiceImpl以为例,下图演示了如何利用Spring的Ioc与Hibernate的结合。

可以看到分别将studentDao,classDao,coursesDao,departmentDao,注入studentManager.

1IStudentsService.java
2publicinterfaceIStudentsService{
3
4publicbooleanvalidate(Stringusername,Stringpasword);
5publicClasses[]getClassesFromCourse(Coursescourses);
6publicDepartmentgetDepFromID(Integerid);
7publicCoursesgetCourseFromID(Integerid);
8publicClassesgetClassFromID(Integerid);
9publicStudentsgetStudetFromName(Stringname);
10publicbooleanifEnrolSameCourse(Classesclazz,Studentsstu);
11publicvoidselectClasses(Studentsstu,Classesclazz,Datedate);
12publicbooleanifMoreThanCap(Classesclazz);
13publicvoidupdateSudent(Studentsstu,Contactcontact);
14publicHashMapgetCourse(PageInfopageinfo)throwsException;
15publicHashMapgetStudentHistory(PageInfopageinfo,Stringstu_name)throwsException;
16
17}
18
19实现StudentsServiceImpl.java
20publicclassStudentsServiceImplimplementsIStudentsService{
21
22privateLoggerlog=Logger.getLogger(this.getClass());
23
24privateIStudentsstudentsDao;
25
26privateICoursescoursesDao;
27
28privateIClassesclassesDao;
29
30privateIDepartmentdepartmentsdao;
31
32/**
33*验证用户名密码
34*
35*@paramusername
36*用户名
37*@parampassword
38*密码
39*/
40
41publicbooleanvalidate(Stringusername,Stringpassword){
42
43Stringpassword2=studentsDao.getPasswordFromUsername(username);
44if(password.equals(password2))
45returntrue;
46else
47returnfalse;
48
49}
50
51/**
52*查找所有课程
53*
54*/
55publicCourses[]getAllCourses(){
56
57Listlist=null;
58try{
59
60list=coursesDao.find("selectcfromCoursesasc");
61}catch(Exceptione){
62}
63
64return(Courses[])list.toArray(newCourses[0]);
65}
66
67/**
68*分页显示所有课程
69*
70*@parampageinfo
71*/
72publicHashMapgetCourse(PageInfopageinfo)throwsException{
73
74HashMaphp=newHashMap();
75Stringhsql="selectcfromCoursesascorderbyc.id";
76Queryquery=coursesDao.getQuery(hsql);
77inttotalCount=pageinfo.getTatalCount();
78inttotalPage=pageinfo.getTotalpage();
79intstart=pageinfo.getStart();
80totalCount=totalCount==-1?coursesDao.getTotalCount(hsql)
81:totalCount;
82totalPage=totalPage==-1?coursesDao.getTotalPage(totalCount,
83pageinfo.getPageSize()):totalPage;
84query.setFirstResult(start);
85query.setMaxResults(pageinfo.getPageSize());
86Listlist=query.list();
87hp.put("courses",(Courses[])list.toArray(newCourses[0]));
88hp.put("totalCount",newInteger(totalCount));
89hp.put("totalPage",newInteger(totalPage));
90returnhp;
91}
92/**
93*分页显示所有选课历史
94*@parampageinfo
95*@paramstu_name
96*/
97publicHashMapgetStudentHistory(PageInfopageinfo,Stringstu_name)
98throwsException{
99HashMaphp=newHashMap();
100Studentsstu=this.getStudetFromName(stu_name);
101Integerstu_id=stu.getId();
102Criteriacriteria=coursesDao.getCriteria(History.class);
103criteria.createCriteria("student").add(Expression.eq("name",stu_name));
104inttotalCount=pageinfo.getTatalCount();
105inttotalPage=pageinfo.getTotalpage();
106intstart=pageinfo.getStart();
107totalCount=totalCount==-1?criteria.list().size():totalCount;
108totalPage=totalPage==-1?studentsDao.getTotalPage(totalCount,
109pageinfo.getPageSize()):totalPage;
110criteria.setFirstResult(start);
111criteria.setMaxResults(pageinfo.getPageSize());
112criteria.addOrder(Order.asc("id"));
113Listlist=criteria.list();
114hp.put("history",(History[])list.toArray(newHistory[0]));
115hp.put("totalCount",newInteger(totalCount));
116hp.put("totalPage",newInteger(totalPage));
117returnhp;
118}
119/**
120*根据课程查找班级
121*@paramcourse
122*课程实体
123*@return返回该课程下所有班级
124*/
125publicClasses[]getClassesFromCourse(Coursescourse){
126returncoursesDao.getClassesFromCourse(course);
127}
128
129/**
130*根据主键查找系
131*@paramid
132*主键ID
133*/
134publicDepartmentgetDepFromID(Integerid){
135return(Department)departmentsdao
136.loadByKey(Department.class,"id",id);
137}
138
139/**
140*根据主键查找课程
141*@paramid
142*主键ID
143*/
144publicCoursesgetCourseFromID(Integerid){
145return(Courses)coursesDao.loadByKey(Courses.class,"id",id);
146}
147/**
148*根据主键查找班级
149*@paramid
150*主键ID
151*/
152publicClassesgetClassFromID(Integerid){
153return(Classes)classesDao.loadByKey(Classes.class,"id",id);
154}
155
156/**
157*根据姓名查找学生
158*@paramname
159*/
160publicStudentsgetStudetFromName(Stringname){
161return(Students)studentsDao.loadByKey(Students.class,"name",name);
162}
163
164/**
165*检查学生是否选报了同一课程的班级
166*@paramclazz
167*所选报的班级
168*@paramstu
169*学生实体
170*@returntrue该生选报同一课程的班级
171*@returnfalse没有报过该课程的班级,可以选报
172*
173*/
174publicbooleanifEnrolSameCourse(Classesclazz,Studentsstu){
175
176Coursescour=clazz.getCourse();
177
178Classes[]classes=(Classes[])stu.getClasses()
179.toArray(newClasses[0]);
180for(inti=0;i<classes.length;i++){
181
182Coursesc1=classes[i].getCourse();
183
184if(c1.getId().equals(cour.getId()))
185returntrue;
186}
187returnfalse;
188}
189
190/**
191*检查课程的目前人数
192*@paramclazz
193*检查班级人数是否已满
194*@paramclazz
195*班级实体
196*@returntrue班级人数已满
197*@returnfalse班级人数未满
198*
199*/
200publicbooleanifMoreThanCap(Classesclazz){
201Integercapacity=clazz.getCapacity();
202Integermaxcapacity=clazz.getMaxcapacity();
203if(capacity.intValue()<maxcapacity.intValue()){
204clazz.setCapacity(Integer.valueOf(capacity.intValue()+1));
205//classesDao.update(clazz);
206returnfalse;
207}else
208returntrue;
209
210}
211
212/**
213*数据库插入选择班级的记录
214*@paramstu
215*学生
216*@paramclazz
217*所选择的班级
218*/
219publicvoidselectClasses(Studentsstu,Classesclazz,Datedate)
220{
221stu.getClasses().add(clazz);
222clazz.getStudents().add(stu);
223Historyhis=newHistory();
224his.setEnrolTime(date);
225his.setStudent(stu);
226his.setClasses(clazz);
227his.setScore(clazz.getCourse().getScore());
228his.setMarking(newDouble(0));
229try{
230Stringcour_name=newString(clazz.getCourse().getName().getBytes("GBK"));
231his.setCourseName(cour_name);
232}catch(java.io.UnsupportedEncodingExceptione){e.getStackTrace();}
233stu.getHistory().add(his);
234}
235
236publicvoidupdateSudent(Studentsstu,Contactcontact){
237
238studentsDao.update(stu);
239studentsDao.update(contact);
240
241}
242publicIStudentsgetStudentsDao(){
243returnstudentsDao;
244}
245publicvoidsetStudentsDao(IStudentsstudentsDao){
246this.studentsDao=studentsDao;
247}
248publicIClassesgetClassesDao(){
249returnclassesDao;
250}
251publicvoidsetClassesDao(IClassesclassesDao){
252this.classesDao=classesDao;
253}
254publicICoursesgetCoursesDao(){
255returncoursesDao;
256}
257publicvoidsetCoursesDao(ICoursescoursesDao){
258this.coursesDao=coursesDao;
259}
260publicIDepartmentgetDepartmentsdao(){
261returndepartmentsdao;
262}
263publicvoidsetDepartmentsdao(IDepartmentdepartmentdao){
264this.departmentsdao=departmentdao;
265}
266}
267
268

4 UI层

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

1xmlversion="1.0"encoding="UTF-8"?>
2<web-appxmlns="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/j2eehttp://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>
6context-param>
7<context-param>
8<param-name>log4jConfigLocationparam-name>
9<param-value>/WEB-INF/log4j.propertiesparam-value>
10context-param>
11<filter>
12<filter-name>hibernateFilterfilter-name>
13<filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class>
14filter>
15<filter-mapping>
16<filter-name>hibernateFilterfilter-name>
17<url-pattern>/*url-pattern>
18filter-mapping>
19<filter>
20<filter-name>SetCharacterEncodingfilter-name>
21<filter-class>limq.struts.SetCharacterEncodingFilterfilter-class>
22filter>
23<filter-mapping>
24<filter-name>SetCharacterEncodingfilter-name>
25<url-pattern>/*url-pattern>
26filter-mapping>
27<servlet>
28<servlet-name>SpringContextServletservlet-name>
29<servlet-class>org.springframework.web.context.ContextLoaderServletservlet-class>
30<load-on-startup>1load-on-startup>
31servlet>
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>
38init-param>
39<init-param>
40<param-name>debugparam-name>
41<param-value>3param-value>
42init-param>
43<init-param>
44<param-name>detailparam-name>
45<param-value>3param-value>
46init-param>
47<load-on-startup>0load-on-startup>
48servlet>
49<servlet-mapping>
50<servlet-name>actionservlet-name>
51<url-pattern>*.dourl-pattern>
52servlet-mapping>
53web-app>
54
55

其中注意这几句,

1<filter>
2<filter-name>hibernateFilterfilter-name>
3<filter-class>org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class>
4filter>
5<filter-mapping>
6<filter-name>hibernateFilterfilter-name>
7<url-pattern>/*url-pattern>
8filter-mapping>
9

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

org.hibernate.LazyInitializationException: failed tolazily initialize a collection

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

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

1abstractclassBaseActionextendsAction{
2
3privateIStudentsServicestudentsService;
4privateITeachersServiceteachersSerivce;
5privateIAdminServiceadminService;
6publicvoidsetServlet(ActionServletactionServlet){
7super.setServlet(actionServlet);
8ServletContextservletContext=actionServlet.getServletContext();
9WebApplicationContextwac=WebApplicationContextUtils
10.getRequiredWebApplicationContext(servletContext);
11
12this.studentsService=(IStudentsService)wac.getBean("studentManager");
13this.adminService=(IAdminService)wac.getBean("adminManager");
14this.teachersSerivce=(ITeachersService)wac.getBean("teacherManager");
15}
16publicIStudentsServicegetStudentsService(){
17returnstudentsService;
18}
19publicITeachersServicegetTeachersSerivce(){
20returnteachersSerivce;
21}
22publicvoidsetTeachersSerivce(ITeachersServiceteachersSerivce){
23this.teachersSerivce=teachersSerivce;
24}
25publicIAdminServicegetAdminService(){
26returnadminService;
27}
28publicvoidsetAdminService(IAdminServiceadminService){
29this.adminService=adminService;
30}
31}
32

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

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

1CoursesAction.java
2/**
3*查看课程下的班级
4*/
5publicActionForwardviewClassFromCourse(ActionMappingmapping,
6ActionFormform,HttpServletRequestrequest,
7HttpServletResponseresponse)throwsException{
8Integercour_id=Integer.valueOf((request.getParameter("cour_id")));
9Coursescour=super.getStudentsService().getCourseFromID(cour_id);
10Classes[]clazz=(Classes[])cour.getClasses().toArray(newClasses[0]);
11request.setAttribute("clazz",clazz);
12returnmapping.findForward("success");
13}
14

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

1publicCoursesgetCourseFromID(Integerid){
2return(Courses)coursesDao.loadByKey(Courses.class,"id",id);
3}
4

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

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

select_course_Content.jsp

CustomRequestProcessor.java 介绍

1publicclassCustomRequestProcessorextendsRequestProcessor{
2protectedbooleanprocessPreprocess(HttpServletRequestrequest,
3HttpServletResponseresponse){
4booleancontinueProcessing=true;
5HttpSessionsession=request.getSession();
6Stringuri=request.getRequestURI();
7if(session==null||session.getAttribute("userName")==null){
8continueProcessing=false;
9if(uri.endsWith("login.do"))returntrue;
10try{
11response.sendRedirect("/StudentManger/login.jsp");
12}catch(Exceptionex){
13log.error("ProblemsendingredirectfromprocessPreprocess()");
14}
15}
16returncontinueProcessing;
17}
18}
19

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

1<controller
2contentType="text/html;charset=UTF-8"
3locale="true"
4nocache="true"
5processorClass="limq.struts.CustomRequestProcessor"/>
6

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

4分页处理:

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

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

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

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

1publicQuerygetQuery(Stringsql)throwsException{
2Sessionsession=this.openSession();
3Queryquery=session.createQuery(sql);
4returnquery;
5}
6
7publicCriteriagetCriteria(Classclazz)throwsException{
8
9Sessionsession=this.openSession();
10Criteriacriteria=session.createCriteria(clazz);
11returncriteria;
12}
13

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

1StudentsServiceImpl.java
2publicHashMapgetCourse(PageInfopageinfo)throwsException{
3
4HashMaphp=newHashMap();
5Stringhsql="selectcfromCoursesascorderbyc.id";
6Queryquery=coursesDao.getQuery(hsql);
7inttotalCount=pageinfo.getTatalCount();
8inttotalPage=pageinfo.getTotalpage();
9intstart=pageinfo.getStart();
10totalCount=totalCount==-1?coursesDao.getTotalCount(hsql)
11:totalCount;
12totalPage=totalPage==-1?coursesDao.getTotalPage(totalCount,
13pageinfo.getPageSize()):totalPage;
14query.setFirstResult(start);
15query.setMaxResults(pageinfo.getPageSize());
16Listlist=query.list();
17hp.put("courses",(Courses[])list.toArray(newCourses[0]));
18hp.put("totalCount",newInteger(totalCount));
19hp.put("totalPage",newInteger(totalPage));
20returnhp;
21}
22
23publicHashMapgetStudentHistory(PageInfopageinfo,Stringstu_name)
24throwsException{
25HashMaphp=newHashMap();
26Studentsstu=this.getStudetFromName(stu_name);
27Integerstu_id=stu.getId();
28Criteriacriteria=coursesDao.getCriteria(History.class);
29criteria.createCriteria("student").add(Expression.eq("name",stu_name));
30inttotalCount=pageinfo.getTatalCount();
31inttotalPage=pageinfo.getTotalpage();
32intstart=pageinfo.getStart();
33totalCount=totalCount==-1?criteria.list().size():totalCount;
34totalPage=totalPage==-1?studentsDao.getTotalPage(totalCount,
35pageinfo.getPageSize()):totalPage;
36criteria.setFirstResult(start);
37criteria.setMaxResults(pageinfo.getPageSize());
38criteria.addOrder(Order.asc("id"));
39Listlist=criteria.list();
40hp.put("history",(History[])list.toArray(newHistory[0]));
41hp.put("totalCount",newInteger(totalCount));
42hp.put("totalPage",newInteger(totalPage));
43returnhp;
44}
45PageIngfo.java
46publicclassPageInfo{
47
48intpageNo=0;
49inttotalpage=-1;
50inttatalCount=-1;
51intpageSize=0;
52intstart=0;
53
54

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

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

1PageAction.java
2publicclassPageActionextendsBaseDispatchAction{
3publicActionForwardexecute(ActionMappingmapping,
4ActionFormform,
5HttpServletRequestrequest,
6HttpServletResponseresponse)
7throwsException{
8StringpageNo=request.getParameter("pageNo");
9Stringtotalcount=request.getParameter("totalcount");
10Stringtotalpage=request.getParameter("totalpage");
11intpagesize=2;//每页的大小
12PageInfopage=newPageInfo();
13page.setPageSize(pagesize);
14HashMaphp=null;
15History[]historys=null;
16Stringstu_name=null;
17HttpSessionsession=request.getSession();
18stu_name=(String)session.getAttribute("userName");
19if(pageNo==null||totalcount==null||totalpage==null){
20//第一次发送请求
21page.setPageNo(1);
22hp=super.getStudentsService().getStudentHistory(page,stu_name);
23page.setTatalCount(((Integer)hp.get("totalCount")).intValue());
24page.setTotalpage(((Integer)hp.get("totalPage")).intValue());
25}else{
26page.setPageNo(Integer.parseInt(pageNo));
27page.setTatalCount(Integer.parseInt(totalcount));
28page.setTotalpage(Integer.parseInt(totalpage));
29hp=super.getStudentsService().getStudentHistory(page,stu_name);
30
31}
32historys=(History[])hp.get("history");
33request.setAttribute("history",historys);
34request.setAttribute("pageinfo",page);
35returnmapping.findForward("success");
36}
37}
38

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

1<%@pagecontentType="text/html;charset=UTF-8"language="java"%>
2<%@tagliburi="/WEB-INF/struts-bean.tld"prefix="bean"%>
3<%@tagliburi="/WEB-INF/struts-html.tld"prefix="html"%>
4<%@tagliburi="/WEB-INF/struts-logic.tld"prefix="logic"%>
5<%@pageimport="limq.hibernate.vo.*"%>
6<%@tagliburi="/WEB-INF/MyTag.tld"prefix="mytag"%>
7<%@pageimport="limq.common.*"%>
8<html:htmllocale="true">
9<body>
10<%
11PageInfopageinfo=(PageInfo)request.getAttribute("pageinfo");
12History[]historys=(History[])request.getAttribute("history");
13%>
14<tablewidth="550"border="1"cellspacing="0"align="center"cellpadding="0">
15<tr>
16<td><bean:messagekey="class.id"/>td>
17<td><bean:messagekey="course.name"/>td>
18<td><bean:messagekey="enrol.time"/>td>
19<td><bean:messagekey="score"/>td>
20<td><bean:messagekey="marking"/>td>
21tr>
22<%
23for(inti=0;i<historys.length;i++){
24Historyhis=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>
32tr>
33<%
34}
35%>
36table>
37<mytag:pagepageinfo="<%=pageinfo%>"action="getHistory.do"/>
38body>
39html:html>
40

标志处理类如下:

1PageTag.java
2
3publicclassPageTagextendsSimpleTagSupport{
4
5privatePageInfopageinfo=null;
6privateStringaction=null;
7
8publicStringgetAction(){
9returnaction;}
10publicvoidsetAction(Stringaction){
11this.action=action;
12}
13publicPageInfogetPageinfo(){
14returnpageinfo;
15}
16publicvoidsetPageinfo(PageInfopageinfo){
17this.pageinfo=pageinfo;
18}
19
20publicvoiddoTag()throwsJspException,IOException{
21JspWriterout=getJspContext().getOut();
22
23inttotalpage=pageinfo.getTotalpage();
24inttotalcount=pageinfo.getTatalCount();
25intpageNo=pageinfo.getPageNo();
26intaddPageNo=pageNo+1;
27intminPageNo=pageNo-1;
28
29out.println(""400\"align=\"center\"cellPadding=\"0\"cellSpacing=\"0\">");
30out.print("");
31out.println("共"+totalcount+"条,"+totalpage+"页,当前"
32+pageNo+"

");
66
67}
68
69}
70


5 中文乱码问题:

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

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

3 在数据库中做如下设定

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

1CREATETABLE`students`(
2`id`int(20)NOTNULLdefault'0',
3`name`varchar(20)NOTNULLdefault'',
4`department_id`int(11)defaultNULL,
5`password`varchar(20)defaultNULL,
6`score`double(15,3)defaultNULL,
7PRIMARYKEY(`id`)
8)ENGINE=MyISAMDEFAULTCHARSET=gbk
9

5 配置hibernate.cfg.xml

1<propertyname="connection.url">jdbc:mysql://localhost:3306/Studentproperty>
2<propertyname="dialect">net.sf.hibernate.dialect.MySQLDialectproperty>
3<propertyname="connection.password">property>
4<propertyname="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,这样理解会更深刻。同时如果你有好的建议,或问题请联系我

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值