陈志宾,王 娜,李 洁
(1.河北省科学院 应用数学研究所,河北 石家庄 050081;2.河北省信息安全认证工程技术研究中心,河北 石家庄 050081;3.河北省科学院,河北 石家庄 050081)
由于互联网的发展,针对Web应用需求的日益增长,快速开发高质量的Web应用系统,满足社会需要,成为业界研究的一大热点问题。
目前,大部分Web应用开发都采用框架技术,即应用一种框架作为整个系统实现和程序编写的基础,如Java框架Struts/JSF、Spring、Hibernate、iBATIS、Tapestry、WebWork、Maverick等。这些框架虽然能够屏蔽J2EE架构[3]的复杂性,帮助开发人员快速编写web应用,但框架之间的配合和MVC分层设计以及应用部署等方面对开发者的技术水平要求较高。Maverick[1]特点是采用不同的模板和转换技术实现表示层逻辑,文献[2]利用Schema实现Pojo对象与关系数据库表的松散耦合,减少需求变化时的系统修改量,文献[3]仅对Struts在易用性方面进行了改善。截至目前,几乎所有的Java框架都需要编写后台Java代码,流程控制和权限配置仅限于页面级别。
在此笔者将阐述一种新型Java框架设计方法,让开发人员不用编写后台Java代码,仅用类似语义语言配置构建最小功能单元——Step,然后将Step流装配成业务功能——Action。它有效的将业务域和技术域进行分离,达到业务流程的敏捷实现和灵活调整,使开发人员能专注于具体应用的业务逻辑而不用将精力过多地放在技术实现细节上,极大地降低了Web应用开发难度。
本框架是针对B/S应用从Web层、业务逻辑层到持久层的基于MVC(Model-View-Controller)的完整实现。
图1 框架结构
框架结构如图1所示,当浏览器向应用服务器发出请求后,Action Servlet(MVC中的Controller)接受该请求,找到对应的Action,调用Action Engine执行该Action。Action Engine首先创建action运行环境(context),得到action所配置的step流,按顺序对每个step进行参数准备和验证,然后执行并把结果记录在上下文环境变量中。
Step为业务工作流的最小功能单元,使用XML格式的类似语义语言构造,如<operator operation="userLogin"result="sysUser"/>表示执行userLogin的操作,将结果保存在sysUser变量中,<ajax from="sysUser"type="json"/>表示将变量sysUser的内容以JSON格式发回给前端。框架内置多种常用通用step,如数据类型转换、字符串操作、数据表Model的CRUD、文件的上传和下载、逻辑判断、表达式赋值等,可以快速组合成功能模块,在框架应用一节详细介绍。
所有Step都继承于AbstractStep并实现IStep接口,如涉及数据库操作,则执行程序从数据源连接池中取得数据库连接。Action Engine负责管理连接池,提供和回收所需连接以及维护事务一致性。其中operator可以通过自定义SQL语句来扩充Step集,以满足复杂情况下的数据操作需要。
在定义数据源连接时,框架增加一项数据库适配器配置,用于屏蔽不同数据库之间的差异,使框架做到数据库无关性,可以将应用系统方便地移植到任何其它数据库系统上,极大降低移植成本。
传统Web的权限控制一般在URL级别,而本框架这种script->server方式的权限控制则要在对象级别、方法级别、Code片断级别了,使得控制更加粒度精细和灵活。
首先,当应用服务器启动时,从web.xml中加载Action Servlet,Action Servlet初始化例程收集框架的参数配置,并放置到ConfigInfo中缓存,再调用WebLoader使配置生效,加载项目资源文件,然后创建 上下文Context,根据应用程序配置文件目录遍历并解析配置文件。
为了加强框架的灵活性和可扩展性,允许开发人员将配置文件任意分割成多个XML文件,只要每个XML文件都具有相对完整的格式即可,便于在开发大型应用时,多组或多个开发人员能较好地协同开发。因此在解析每个配置文件时,总是按顺序从connection(数据链接)、attribute regular(公共属性)、attribute group(公共属性组)、parameter group(公共参数组)、model(实体模型)、result map(结果映射)、operation(自定义操作)、step define(step命名与类的对应)、action、constant(公共常量)、model relation(实体关系)几个种类分析,并分类存储在ConfigInfo中以提高系统性能。
由于是由多个Step组装而成,Action的初始化是每个Step的有效检验和参数准备工作,执行所有action的init方法(传入Context参数),该方法同样执行它所有的step的init方法。如果涉及到数据库的操作,还要设置数据库连接信息。
图2 Action的执行流程图
由图2可以看出,Action的执行是利用Java反射机制 ,得到Step类的修饰符、方法、属性、继承的父类以及实现接口等信息,实现类方法的动态执行,也就是业务工作流程的分步执行过程,并有事务的完整性控制。对于数据表单HttpForm,自动搜集表单域的属性值并验证,并放在上下文中同名的变量中,以待进一步的处理。
2.3.1 物理模型映射
框架引入模型(Model)定义概念,类似ORM(Object Relational Mapping,对象关系映射),从表示层、业务层到持久层其实都是围绕模型展开的。在分析客户需求后,定义出所需的各个模型及模型之间的关系,在Step配置中直接使用,无需编写java代码构造实体类。
框架的数据模型主要包括一组模型属性(即物理数据表中的字段,但引用名可以改变,便于系统复用)、数据库连接、物理表映射、缓存类和主键等信息。对模型属性可定义它的取值范围、是否可空、缺省值等验证规则。表映射和字段映射使业务模型能与持久层隔离,它们和数据库适配器共同构成了数据库可移植的核心。
为了减少开发工作量,提高简洁性和灵活性,框架引入属性规则定义和属性组。开发人员可根据系统情况定义属性命名格式和属性配置之间的通用对应关系,如 .*Id格式的属性定义为整数类型,可配置为:
也可把常用的多个属性定义为属性组,在需要用到的地方引用该属性组即可,减少配置时的工作量,如:
2.3.2 数据库适配器
在定义数据源连接时,增加一项数据库操作包装类配置,用于隔离不同数据库和数据库驱动的差异,使应用系统做到与数据库无关性,可以将应用系统方便地移植到任何其它数据库。
同时数据库适配器DBAdapter还负责:
(1)维护Connection Wrapper对象集和映射连接:Connection Wrapper对象有名称和打开、关闭连接方法;
(2)准备Connection:当申请连接的新Connection Wrapper在对象集中有同名对象,则直接取该同名对象映射的已申请过的连接作为当前连接进行数据库操作,否则调用新Connection Wrapper的方法取到连接作为当前连接,并将对象和连接映射关系放进对象集。
(3)维护数据库操作的事务完整性:对每个Connection Wrapper进行提交和回滚,一旦出错自动回滚。
(4)释放所有连接:除了通过正常方法释放外,在它被回收时强制进行所有连接的释放。
Web表现层一直是体现各个框架个性的地方,在做开发过程和技术架构定义时,日益复杂的业务需求使Web界面与交互性也越来越复杂,也是令开发者最头疼的事情。在Java Web表现层技术领域,通常的做法是采用模板加标签的思路,即JSP+TagLib,利用Ajax的通信机制结合UI组件进行页面局部刷新。但这样使页面变得不规范,在网页制作工具中不能正常显示,用户体验效果改善也甚微。
笔者认为,Ajax只是使表现层有能力主动从后端的数据模型中拉取数据,仅是一种数据获取方式。要想达到C/S模式的用户体验,最终的方案就是实现UI组件和数据的彻底分离,各UI组件通过数据引用来共享数据,这种模式其实在以前C/S架构下非常常见,例如VB、Delphi、PowerBuilder等。“以数据为中心”的表现层应用才是真正具有生命力的。
本框架在表现层建立dataset类,通过url属性设置Action,以此从后台提取XML或JSON格式数据,在HTML中存贮,网页内置的XML处理器产生一个数据源对象(DSO,全称是Data Source Object),以便存贮和读取数据。DSO在存贮XML或JSON数据流时,会将元素解释成记录和字段的集合,并自动抽取元素的数据和处理所有的显示细节。也可以将标准的 HTML元素(例如TABLE、SPAN等)和dataset元素绑定。
Dataset类用来管理一组二维数据,其结构类似于关系型数据库中的表或视图,功能基本涵盖了对数据处理的各项要求。开发人员可以利用dataset来完成绝大部分的数据持久化、数据提取的操作以及dataset间的数据拷贝等。每个数据UI组件通过dataset属性与数据集建立连接,对数据的所有改变,包括增加、删除、修改等,可以一次性提交给后台处理。
用户登录页面是每个B/S结构的应用系统必不可少的功能,看似简单,其实包含几乎所有的数据处理操作,一般作为框架的入门实例介绍。
如果采用目前流行框架的完美组合SSH(Struts、Spring、Hibernate)[4]实现此功能,需要先生成用户的实体Bean,进行登录用户验证的Method,在Spring中配置方法注入,在Struts中编写Action引用该方法,最后在JSP页面上调用Action。每一步都需要编写java代码来完成。
以下是通过本框架实现的配置文件,并对关键地方进行了注解。
<!--调用其它action-->
<operator operation="userLogin"result="sysUser"/><!--调用验证操作,返回信息-->
<if express="sysUser==null"trueAction="NotExist"falseAction="loginOK"/>根据判断进行Action跳转
<!--返回前台错误信息-->
<operation-list><!--定义操作-->
<parameter-list><!--定义操作参数-->
</parameter-list><!--返回类型-->
<map-list><!--属性映射-->
<sql-define-list><!--定义操作SQL-->
</sql><!--${}中是sql中的参数-->
在登录页面index.jsp中添加<form method="post"action="login.do">即可,提交操作调用’login’action,根据form传递来的loginName和password调用自定义操作‘userLogin’operator执行SQL语句,取得登录用户model信息放到session中。登录成功调用main.jsp显示系统主页面,失败则返回错误信息。
示例表明,采用本框架开发web应用,开发者不必了解J2EE编程技术,不需编写java代码,仅按业务流程配置step即可,相似的功能可以在今后直接拷贝使用。
本文描述的java编程框架模型,改变了Web应用开发模式,由传统的编写源码模式改为定定义配置模式。采用面向过程和服务编程,将业务模块的操作步骤分解为Step流,利用Java反射机制动态解释执行,为客户端提供服务机制。同时在表现层设计上,提出以数据为中心的设计模式,注重客户端UI组件间数据的共享,来减少通信中的数据传输量,从本质上解决Web用户体验不佳的问题。希望能对人们探索研究编程框架提供一些帮助。进一步的工作是遵循惯例优先 (Convention over Configuration,CoC)原则尽可能地减少配置量,进而设计本框架的可视化配置工具。
[1] Maverick Web框架设计与实现[EB/OL].[2009-3-16].http://www.ibm.com/developerworks/cn/java/l-Maverick/index.html.
[2] 潘仙张,米根锁.基于Schema的 Web框架设计[J].计算机工程,2009,35(10):57-59.
[3] 王家骐,于海霞.基于MVC设计模式的 WEB应用框架研究[J].计算机与信息技术,2007,(3).
[4] 叶键毅.精通Java EE:Eclipse Struts2Hibernate Spring整合应用案例[M].北京:人民邮电出版社,2009.