摘要:面向Java Web应用的开源项目能大大提高开发企业级WEB应用的速度和效率,并为开发人员在构建应用时提供了良好的架构基础和支持。论文结合Struts和Hibernate这两个开源框架给出了一个快速开发结构清晰、可重用性好、维护方便的企业级应用架构方案,并通过一个具体项目来阐述基于此架构的开发方法。 关键词:J2EE,开源框架,Struts, Hibernate, 架构
1 前 言
在企业级WEB应用开发中J2EE平台已经得到广泛应用,而J2EE[1]平台本身也在不断的完善和改进。而一些基于Java的企业级Web应用开发是一项复杂而又漫长的工程,开发人员如果自己从头开始写每一部份的代码,很有可能会影响项目的进度和代码的可维护性。要想在预定的项目期限内开发出具有良好的可维护性、可扩充性的系统,需要解决很多问题,如用户界面与业务逻辑的分离、业务逻辑与数据库操作的分离以及正确的流程控制逻辑等。框架(FrameWork)为Web应用提供了预备的软件架构和相关软件包,可以大大提高开发Web应用的速度和效率。在Java社区,开源项目进行得十分活跃,许多优秀的开源框架更是为我们提供了帮助,结合Struts和Hibernate这两个开源框架来构建应用是一个十分有效的技术选择。本文研究了没有采用EJB技术的基于Struts和Hibernate框架的轻型J2EE软件架构技术和开发方法。
2 Web应用的分层分析
在构架一个Web应用时需要考虑很多问题,如在哪里处理用户交互、在哪里处理业务逻辑、在哪里对应用数据进行持久化,以及怎样选择这些方面的实现技术和设计方案才能达到相互间松散耦合及应用具有良好的扩展性等,所以一个应用的架构方案和实现技术选择十分重要。在软件工程中我们提倡“高内聚,低耦合”,因为这样的软件才会具有易于控制、扩展、维护等优点。而分层的目的就是对应用的逻辑功能进行划分,使每层在完成自己功能的同时,不影响其它层的实现。所以分层设计是一个很好的架构方案。图1是一个典型的WEB应用分层结构。

图1 Web应用的分层
各层的功能为:
WEB层:提供用户交互接口,对用户的请求做出响应。
业务逻辑层:实现各种业务逻辑功能,是应用的核心所在。
持久层:实现数据访问细节,提供业务数据的保存、更新、删除、查询等操作。
数据库层:完成业务数据的存储和管理功能。
当前开发界中还提出了一个域模型层,但是对于采用Struts和Hibernate架构的应用,可以把此层归属到业务逻辑层,对应到业务逻辑层的JavaBean(过程域对象)、POJO(实体域对象)。
3 Struts框架研究分析
Jakarta-Struts是Apache软件组织提供的一个开放源代码项目,它为Java Web应用提供了模型-视图-控制器(MVC)框架,是基于JSP Model2开发模式的MVC的具体实现[1,5],其实现原理如图2。它为基于MVC模式来开发WEB应用程序提供了现成的框架和相关组件,有效地提高了程序的开发效率,并使程序的结构更加清晰。

图2 MVC模式的Struts实现
视图:由一组JSP文件构成,在这些JSP文件中没有业务逻辑代码,只有标签,可以通过标签访问模型信息(图2中查询)。Struts框架中的ActionForm Bean也属于视图部分,由它封装表单信息,在视图和控制器之间传递。
控制器:控制器由ActionServlet和Action类实现。ActionServlet是Struts框架中的中央控制器,由它处理请求并根据配置文件struts-config.xml决定转发给相应的Action组件。Action充当用户请求和业务逻辑之间的视配器,负责调用模型的方法,更新模型的状态,并帮助控制应用程序的流程。
模型:表示应用程序的状态和业务逻辑,负责访问和更新持久化数据,是应用中最重要的一部分,然而在Struts框架中并没有提供为设计和创建模型组件的方法或现成框架,这是Struts框架的一个没有真正涉及的部分。在实际应用中,模型一般用JavaBean、EJB或Java Web 服务来实现。
4 Hibernate框架研究分析
在程序中我们用对象来描述真实世界,但在关系数据库还是数据的常用永久存储技术背景下,我们需要一种有效技术来完成对象到关系数据的转化(即对象的持久化,是图1中持久化层要做的)。而对象之间有许多关系数据无法表达的概念,如关联和继承等。如果直接通过JDBC来开发自己的持久化层很有可能影响项目的进度和持久层的可靠性,并严重影响代码的可维护性。
Hibernate[4]是一种运用DAO设计模式来实现对象和关系数据库之间映射(O/R Mapping)的开源框架。它对JDBC进行了轻量级的对象封装,使得Java程序员可以完全使用面向对象的编程思维来操作关系数据库(如图3),是持久层的一项实现技术。相比于其它持久层实现技术如JDBC、EJB(实体Beans)、JDO等,Hinbernate易于掌握,更加符合编程人员的面向对象思维, Hibernate拥有自己的一种查询语言(HQL),它是完全面向对象的,其在应用中的基本结构如图3。

图3 Hibernate在应用中的结构图
Hibernate为Java 程序员提供了面向对象的API和接口来操纵数据库,从而避免了在业务逻辑中嵌入大量的JDBC访问和事物控制代码。SessionFactory接口对应我们的数据库存储源,程序从此接口中得到Session接口实例。Session接口是应用中进行持久化时经常使用的接口,它提供了所有的持久化相关操作,同时我们可以通过Session接口获得Tranaction接口来实现数据库事务的控制。Hibernate还提供了我们其它一些实用接口和类,如Query接口等。一个典型的利用Hibernate操作数据库的代码为:
//sessionFactory是SessionFactory接口//实例,应在应用开始时只被初始化一次。
Session session=sessionFactory.openSession();
//从sessionFactory获得Session,开始持//久化操作
Transaction trans=null; //事务控制
try{
//获得事务控制接口
trans=session.beginTransaction();
//具体操作,其中User是我们定义的//持久化类
session.delete(“from User as u”);
trans.commit(); //提交事务
}catch(Exception e){
if(trans!=null)
trans.rollback(); //回滚事务
throw e;
}finally{
session.close(); //最后一定要//关掉session
}
从中我们可以发现Hibernate是完全面向对象的,在具体实现相关持久化操作时,我们并没有涉及到数据库表,而是我们定义的持久化类,当然我们还必须设置持久化类和表的映射关系文件才能这样操作。同时,Hibernate还允许程序编写者绕过Hibernate API而直接使用JDBC来操作数据库,这在一些场合十分有用,如批量更新、删除操作时(Hibernate在这方面的操作性能不够理想)。
5 结合Struts和Hibernate的架构研究分析
通过对Struts的分析,Struts框架为Web应用提供了一个通用的框架,它把应用分成了三部分:视图、控制器、模型,使用Struts能够使我们的应用具有结构清晰、健壮性好、代码重用性高等优点。但是Struts框架在模型部分并没有为我们提供什么技术实现,如果我们只是单纯的利用Struts框架进行Web 应用开发,那么在我们开发的业务逻辑处理中将势必会存在大量的JDBC代码,而且还要人为控制事务。通过对Hibernate框架的分析,它完全用面向对象的方式很好地实现了持久化相关任务,使开发人员完全从JDBC硬编码中解放出来,完全用面向对象的思维来进行应用开发。
因此在开发图1所示的分层WEB应用时,我们可以采用如下架构技术:Struts(表示层)+JavaBean或EJB或Java Web服务(业务逻辑层)+Hibernate(持久层)。业务逻辑层的实现具有多种选择,这也是利用Struts和Hibernate框架的一大优点:层间的耦合十分松散。对于一般的应用我们可以在业务逻辑层采用JavaBean来实现,因为EJB和Java Web服务都需要遵循相关的技术规范和容器支持,不具有很好的移植性和扩展性。
基于Struts和Hibernat架构的应用工作流程如图4,其MVC实现方式为:
视图:JSP+Taglib(JSTL+Struts标签)
控制器:ActionServlet+Action
模型:JavaBean+Hibernate

图4 基于Struts和Hibernate架构的工作流程图
以用户的查询请求为例,来说明其工作流程:用户的查询请求提交给Struts的ActionServlet(统一入口),由它根据用户的配置文件分发到对应的Action(可以采用DispatchAction来封装一个模块的所有操作),Action调用实现具体查询操作的JavaBean DAO(完成所有持久化操作)来完成数据的获得。JavaBean DAO通过Hibernate API把关系系统中的数据转换成POJO对象提供给Action。在Action中把获得的POJO对象转化成VO或是ActionForm对象提交给视图对象(JSP)进行浏览。
在基于此架构的分层模型的开发中,层间的耦合性问题是一个十分重要也是比较难解决的问题。分层的一个准则是:层与层之间存在着自上而下的依赖关系(即上层组件会访问下层组件),但下层组件不应该依赖上层组件[5]。因此在基于此架构的开发中:我们必须解决两个问题:
⑴ 下层的方法实现中不应该存在或依赖上层中的类或API,如在业务逻辑层不应该有HttpServletRequest之类的Web层对象。
⑵ 层间的数据传递问题。Web层的数据表示是FormBean或是其它自定义的VO,持久层的数据表示是PO,其数据来源于数据库,在此架构中持久层的数据表示是POJO。在一个规范的J2EE架构中,不同层的数据表示应该被限制在层内,而不应该扩散到其它层,这样可以降低层间的耦合性,提高J2EE架构整体的可维护性和可扩展性。因此在此架构的应用开发中把控制层(即Action类)作为数据的转换层或边界。从JSP页面来的ActionForm传递到控制器Action中,在这里把它转换成POJO对象,然后传递到业务逻辑层来实现具体的持久化操作。反之从业务逻辑层传递到Action的POJO对象在Action中进行转换,转换成ActionForm或其它VO供表示层JSP使用。经过这样的数据组织可以降低层间的耦合性,提高此架构整体的可维护性和可扩展性
应用此架构的优点有:应用具有良好的伸缩性、可维护性、可扩展性、可重用性、可管理性,能够很好的实现各层间松散耦合。在扩展性方面,我们可以在业务逻辑层采用目前非常流行的Spring框架来组装应用。
6 基于此架构的化检数据管理系统开发
本文以实际项目化检数据管理系统为例来阐述基于此架构的基本开发方法。
⑴ 开发环境的准备
目前支持此框架组合开发的工具很多,此系统采用当前十分流行的Eclipse+MyEclipse组合来开发,MyEclipse支持Struts、Hibernate以及Spring等框架,能够很大程度上提高程序编写者的开发效率。
⑵ 系统整体开发架构搭建
在确定了系统的分层模型和基于图4的的架构方案后,对系统的文件夹结构进行严格的功能划分,如图5所示。

图5 基于此架构的开发文件夹结构
其中各文件夹的作用:
edu.csu.common: 存放一些应用范围内的通用文件,如系统用到的常量文件(CONSTANTS.java)。
edu.csu.hibernate: 存放对应数据库表的所有需要被持久化的实体域对象(POJO)及其映射文件,是应用Hibernate的直接体现,可以通过MyEclipse生成。
edu.csu.services: 包括系统中用来执行业务逻辑操作的过程域对象,它们利用Hibernate API完成上述POJO的持久化操作,此部分采用了DAO的设计思想,还包括一些执行特殊服务的类,如在export子包中是一些导入导出工具类,是应用的业务逻辑核心所在。
edu.csu.struts:应用Struts的直接体现。actions、forms、plugin子包分别存放系统中的Struts action、ActionForm、Struts插件。
edu.csu.tags:对应系统中的自定义标签,如系统中的用户会话验证标签等。
edu.csu.util:对应系统中的实用工具类,如自定义的字符串处理、验证码生成、MD5加密工具类、字符编码过滤器等。
edu.csu.vo:存放系统中所有的值对象(VO即数据传输对象DTO)。
⑶ 应用此架构开发时的一些考虑
在系统的开发中,采用一些设计模式的思想,通过这些方法提高了系统的可维护性和降低系统各层间的偶合性。如在表现层(JSP)和控制层间传输的对象是ActionFrom对象,反方向传输的则是ActionForm或是VO;在控制层和业务逻辑层间传输的对象则是POJO。即在控制器层来完成VO和POJO的相互转化,达到了表示层、业务逻辑层、持久化层之间的耦合分离。
在系统开发中控制器采用Struts的DispatchAction机制,即让自定义的Action类继承它,在一个这样的Action中定义一个原子模块的所有操作(如样品属性管理的添、删、改和查等操作),这样就能够最大限度地减少Action类的个数,从而提高系统的可维护性。而在表示层部分中(JSP)采用Struts标签库、JSTL标签和EL语言,通过JSTL标签和EL语言来弥补Struts标签不能嵌套、页面控制逻辑比较薄落等缺点。
由于Hibernate在进行批量删除、更新操作时,会先进行选择操作,在操作数据量大的情况下,这样会严重影响性能,所以在系统开发中我们选择了直接使用JDBC方法(实现类放在edu.csu.servies.JDBC包中)进行批量操作,其它情况下采用Hibernate来完成所有持久化操作。
(3) 基于此架构的单位信息管理模块
单位管理是化检数据管理系统中重要的关键信息处理模块,包括系统用户、单位职工、样品信息(需要分析单位和采样单位信息)、分析数据录入及查询等重要的系统管理模块和业务模块都需要单位信息的支持。在此次系统实现中,笔者设计实现了一个基于Struts和Hibernate架构的通用的单位信息管理模块,此模块实现的功能涉及到日常单位信息管理的所有功能,包括单位的添加、删除、修改、级别调整(上升下降)及合并和导出功能。
此模块的设计原则为:在JSP页面中不能出现任何业务逻辑代码,JSP只负责WEB端的页面呈现;在Action中实现Web层与业务逻辑服务层的业务代理,即在Action中实现服务层取得的数据的封装(把服务层取得的POJO对象转化为ActionForm VO对象),同时根据Web层的请求选择调用服务层的服务;所有的业务操作实现都封装在业务服务类中,在具体的业务实现过程中,考虑到批量操作的要求(因为在更新单位信息时,会级联更新其他相关信息,调用相关存储过程和执行JDBC操作),而Hibernate在批量处理方面的性能不是很理想,所以在程序中还定义了一个GroupJDBCService类,在此类中完成所有的更新操作和存储过程的调用(直接通过JDBC完成)。图6是其总体的设计。通过这样的设计,很大程度上提高了代码的可维护性和可重用性,且模块的处理流程十分清晰。

图6 单位信息管理的重构设计图
7 总结
本文首先介绍了WEB应用的分层结构,阐述了这种分层结构的优点;然后分析了Struts和Hibernate这两个框架,最后提出了一个结合Struts和Hibernate的软件架构方案。表示层由Struts实现,持久层由Hibernate实现,中间层由自定义的JavaBean实现,并通过实际项目来阐述基于此架构的开发方法。基于这种架构技术开发的应用系统具有层间松耦合、结构清晰、开发周期短、可维护性好、扩展性好的优点。本文为基于框架的J2EE开发提供了一定的方法指导。
参考文献:
[1] 陆荣幸,郁洲,阮永良,王志强. J2EE平台上MVC设计模式的研究与实现[J]. 计算机应用研究,2003,3:144-146
[2] 徐长盛,戴起,谢立.一种快速开发Web应用程序方法的研究.计算机工程与设计[J],2004,25(12):2237-2239
[3] 吴岳,翁敬农. 用Struts和Hibernate构筑Web应用开发策略. 计算机工程与设计[J],2006,27(7):1176-1179
[4] 陈晓晖,姚宇明,郑明华. 基于Struts和HIBERNATE架构的保险公司核心业务系统[J].计算机工程,2006,32(4):264-266,271
[5] 孙卫琴.精通Struts: 基于MVC的Java Web设计与开发[M].北京:电子工业出版社,2005
|