Struts+Spring+Hibernate开发实例

SunRHC 贡献于2011-07-26

作者 张虎  创建于2008-12-13 07:26:00   修改者liyan  修改于2010-06-28 09:47:00字数33896

文档摘要:本文并不想介绍Struts,Spring,Hibernate的原理系统架构等,本文地目的是通过一个较复杂地实例介绍如何整合Struts,Spring,Hibernate,网上现有的例子虽然也能达到目的,但功能都比较单一,复杂的例子时会有意想不到的麻烦。本文对读者假设已经具备了以上框架的基础知识。以及那些已经了解Struts,Spring,Hibernate的基本概念,但是还没有亲身在较复杂的项目中体验Struts+Spring+Hibernate的开发人员。
关键词:

华虎设计站资料欢迎大家光临http://www.alonebar.com.cn [张虎] 地址:南昌航空大学科技学院7#406室 QQ:632926059 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   6                    7               9             set> 10  同样在History.cfg.xml中加入: 1       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    2 DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"    3     "http://www.springframework.org/dtd/spring-beans.dtd">   4    5      6        7       com.mysql.jdbc.Drivervalue>   8     property>   9       10       jdbc:mysql://localhost:3306/Studentvalue>  11     property>  12       13       rootvalue>  14     property>  15       16       value>  17     property>  18   bean>  19     20       21         22     property>  23       24         25         limq/hibernate/vo/Admins.hbm.xmlvalue>  26         limq/hibernate/vo/Classes.hbm.xmlvalue>  27         limq/hibernate/vo/Courses.hbm.xmlvalue>  28         limq/hibernate/vo/Students.hbm.xmlvalue>  29         limq/hibernate/vo/ClassesInfo.hbm.xmlvalue>  30         limq/hibernate/vo/Contact.hbm.xmlvalue>  31         limq/hibernate/vo/Department.hbm.xmlvalue>  32         limq/hibernate/vo/History.hbm.xmlvalue>  33         limq/hibernate/vo/Teachers.hbm.xmlvalue>  34       list>  35     property>  36       37         38         net.sf.hibernate.dialect.MySQLDialectprop>  39         trueprop>  40       props>  41     property>  42   bean>  43     44       45         46     property>  47   bean>  48     49     50       51         52     property>  53   bean>  54     55       56         57     property>  58   bean>  59     60       61         62     property>  63   bean>  64     65       66         67     property>  68   bean>  69     70       71         72     property>  73   bean>  74     75       76         77     property>  78   bean>  79     80       81         82     property>  83   bean>  84     85       86       limq.hibernate.dao.IStudentsvalue>  87     property>  88       89         90         hibernateInterceptorvalue>  91         studentDaoTargetvalue>  92       list>  93     property>  94   bean>  95     96       97       limq.hibernate.dao.ITeachersvalue>  98     property>  99      100        101         hibernateInterceptorvalue> 102         teacherDaoTargetvalue> 103       list> 104     property> 105   bean> 106    107      108       limq.hibernate.dao.ICoursesvalue> 109     property> 110      111        112         hibernateInterceptorvalue> 113         courseDaoTargetvalue> 114       list> 115     property> 116   bean> 117    118      119       limq.hibernate.dao.IClassesvalue> 120     property> 121      122        123         hibernateInterceptorvalue> 124         classDaoTargetvalue> 125       list> 126     property> 127   bean> 128    129      130       limq.hibernate.dao.IDepartmentvalue> 131     property> 132      133        134         hibernateInterceptorvalue> 135         departmentDaoTargetvalue> 136       list> 137     property> 138   bean> 139    140      141       limq.hibernate.dao.IAdminvalue> 142     property> 143      144        145         hibernateInterceptorvalue> 146         adminDaoTargetvalue> 147       list> 148     property> 149   bean> 150    151    152      153        154     property> 155      156        157     property> 158      159        160     property> 161      162        163     property> 164   bean> 165    166      167        168     property> 169      170        171     property> 172      173        174     property> 175      176        177     property> 178   bean> 179    180      181        182     property> 183      184        185     property> 186      187        188     property> 189      190        191     property> 192      193        194     property> 195      196        197     property> 198   bean> 199    200    201      202        203     property> 204      205        206     property> 207      208        209         PROPAGATION_SUPPORTSprop> 210         PROPAGATION_REQUIREDprop> 211       props> 212     property> 213   bean> 214    215      216        217     property> 218      219        220     property> 221      222        223         PROPAGATION_SUPPORTSprop> 224         PROPAGATION_REQUIREDprop> 225       props> 226     property> 227   bean> 228    229      230        231     property> 232      233        234     property> 235      236        237         PROPAGATION_SUPPORTSprop> 238         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   2   3     4     contextConfigLocationparam-name>  5     /WEB-INF/classes/applications-service.xmlparam-value>  6   context-param>  7     8     log4jConfigLocationparam-name>  9     /WEB-INF/log4j.propertiesparam-value> 10   context-param> 11    12     hibernateFilterfilter-name> 13     org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class> 14   filter> 15    16     hibernateFilterfilter-name> 17     /*url-pattern> 18   filter-mapping> 19    20     Set Character Encodingfilter-name> 21     limq.struts.SetCharacterEncodingFilterfilter-class> 22   filter> 23    24     Set Character Encodingfilter-name> 25     /*url-pattern> 26   filter-mapping> 27    28     SpringContextServletservlet-name> 29     org.springframework.web.context.ContextLoaderServletservlet-class> 30     1load-on-startup> 31   servlet> 32    33     actionservlet-name> 34     org.apache.struts.action.ActionServletservlet-class> 35      36       configparam-name> 37       /WEB-INF/struts-config.xmlparam-value> 38     init-param> 39      40       debugparam-name> 41       3param-value> 42     init-param> 43      44       detailparam-name> 45       3param-value> 46     init-param> 47     0load-on-startup> 48   servlet> 49    50     actionservlet-name> 51     *.dourl-pattern> 52   servlet-mapping> 53 web-app> 54  55  其中注意这几句, 1  2     hibernateFilterfilter-name> 3 org.springframework.orm.hibernate.support.OpenSessionInViewFilterfilter-class> 4   filter> 5  6     hibernateFilterfilter-name> 7     /*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 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    2   3   4   5   6   7   8    9    10    14  15    16     td> 17     td> 18     td> 19     td> 20     td> 21   tr> 22    26    27     td> 28     td> 29     td> 30     td> 31     td> 32   tr> 33    36 table> 37  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("< SPAN>"400\" align=\"center\"  cellPadding=\"0\" cellSpacing=\"0\"> "); 30         out.print(""); 31         out.println("共" + totalcount + "条," + totalpage + "页,当前" 32                 + pageNo + "页"); 33         out.println(" "); 34         if (pageNo > 1) { 35             out 36                     .println("&< SPAN>"/StudentManger/" + action 37                             + "?pageNo=1"+ "&totalpage=" + totalpage + "&totalcount=" 38                     + totalcount + "\">" ); 39         } 40         out.print("首页"); 41         out.println(" "); 42         if (pageNo > 1) { 43             out.println("&< SPAN>"/StudentManger/" + action + "?pageNo=" 44                     + minPageNo + "&totalpage=" + totalpage + "&totalcount=" 45                     + totalcount + "\">"); 46         } 47         out.print("上页"); 48         out.println(" "); 49         if (pageNo < totalpage) { 50             out.println("&< SPAN>"/StudentManger/" + action + "?pageNo=" 51                     + addPageNo + "&totalpage=" + totalpage + "&totalcount=" 52                     + totalcount + "\">"); 53         } 54         out.print("下页"); 55         out.println(" "); 56         if (pageNo < totalpage) { 57  58             out.println("< SPAN>"/StudentManger/" + action + "?pageNo=" 59                     + totalpage + "&totalpage=" + totalpage + "&totalcount=" 60                     + totalcount + "\">"); 61  62         } 63         out.print("末页"); 64         out.println(" "); 65         out.println("   "); 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 1jdbc:mysql://localhost:3306/Studentproperty> 2 net.sf.hibernate.dialect.MySQLDialectproperty> 3 property> 4 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 posted on 2005-09-20 20:47 limq 阅读(24621) 评论(58)  编辑  收藏 评论 # re: Struts+Spring+Hibernate开发实例  回复  更多评论    收藏。 不过提供的代码下载后无法打开。有问题。 有点疑问,用opensession()打开的session什么时候close,spring会帮你close吗。 2005-09-21 10:03 | superwar # re: Struts+Spring+Hibernate开发实例  回复  更多评论    代码地址没有问题,可以新开一个 IE 地址中输入 http://www.blogjava.net/Files/limq/StudentManger.rar 就可以下载。 至于你说的Session问题,我参考的是 Spring Framework之最佳实践: http://www.gpowersoft.com/tech/Spring/46.htm 我的理解是最终Session还是要交给Sping 处理的。 2005-09-21 10:13 | lmq # re: Struts+Spring+Hibernate开发实例  回复  更多评论    Spring可以减少开发中的close,比如普通的connection、ps、rresultset等等,Hibernate的session它也可以帮助close 2005-09-21 16:07 | yonge # Struts+Spring+Hibernate开发实例(转)[TrackBack]  回复  更多评论    Ping Back来自:blog.csdn.net [引用提示]轻舟引用了该文章, 地址: http://blog.csdn.net/maomaochong713/archive/2005/09/22/486875.aspx 2005-09-22 09:17 | 轻舟 # 提点建议  回复  更多评论    提点建议:粗略看了一下,做为教学示例,这个例子很好,但下载的代码好象没有文中提到的这么多内容 ,例如管理员模块,教师,班级,系的增删除查改好象都没有,而且资源文件也不齐,致使运行出错,希望作者完备一下, 并在下载的程序中增加一个readme.html文件,把运行过程要注意的一些问题和配置中要注意的事项说清楚,免得浪费调试时间, 2005-09-26 09:23 | xingwen # re: Struts+Spring+Hibernate开发实例  回复  更多评论    非常不错, 对于session的close问题,如果用了singleton模式的话,是不用关闭的。 如果关闭了,下次你还得再建一个。 这种东东应是反复使用的。 2005-09-29 11:09 | stoneskin # re: Struts+Spring+Hibernate开发实例  回复  更多评论    如果可以把正项目做完整,打包到网上。我将感激不尽!谢谢!!! 2005-10-12 17:08 | 大头 # re: Struts+Spring+Hibernate开发实例  回复  更多评论    非常好! 2005-10-29 15:06 | faithful # re: Struts+Spring+Hibernate开发实例  回复  更多评论    还是很不错的代码 ,特别是对于刚开始接触spring的人来说可能是很大的帮助。。。 谢谢先。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档