1 总体目标
基于开源框架结合项目需求,形成一套既能满足现状又能适应技术发展趋势的技术框架。要求该技术框架能够提升开发效率避免技术风险;能够形成可重用的技术基础;能够提高软件质量的同时便于对软件开发的过程进行有效的管理和控制。
本着“不要重复发明轮子”的精神,我们没有必要从头开始构架自己的开发框架,现在Java社区相当活跃,各种类型的开源框架层出不穷,有大量优秀的框架供我们选择。但是一套开源框架一般只关注我们整个应用的一个部分,例如WEB开发框架关注的是如何对Servlet API进行封装,持久化框架关注是如何封装JDBC,因此,我们需要选择多套开源框架进行集成,形成一套适合我们项目的框架,并在此框架上对该项目遇到的技术问题如分页查询问题、大数据量EXCEL导出问题等提出相应的解决方案。
2 开源框架的选择
Java EE本身形成了一套以EJB规范为核心采用三层结构的技术框架,但因为其着眼点为超大规模分布式复杂系统提供的技术框架,在我们绝大部分系统中都达不到需要采用EJB架构的程度。但其提出的分层结构是一种很好的企业应用的模块划分方式。所以在选择技术框架的时候我们会把Java EE的分层结构作为框架选择的参考标准。Java EE的三层结构为:
1、表现层
2、业务层
3、持久化层
2.1 表现层
基于经验,在一般的Java EE的web应用中,我们至少有60%的工作量是用在表现层。表现层一方面直接与最终用户相关,需求容易发生变动;另一方面该层涉及到了多种技术的配合使用有一定的复杂度。但是Java EE对这一层的重视不够,和.NET比起来Java EE除了与ASP相当的JSP技术以及自定义标签技术以外,没有提供更多的支持,实践证明使用JSP技术会让系统变得难于维护,无法针对不同技术进行分工,一个JSP文件往往包含了显示逻辑,显示样式,交互逻辑三个部分的内容,这就需要开发人员同时具备多种知识例如css,html,javascript,java等才能应付jsp的开发。所以WEB开发框架的选择有着非常重要的意义。下面是结合个人经验总结的WEB框架应该具有的核心功能。
1、实现页面代码分离。作为WEB应用,表现层是通过HTML的形式在浏览器中展现的,作为应用系统的UI,表现层不仅仅只是把数据展现出来,还需要能够实现系统和用户之间的交互,也就是说表现层是包含了一定交互逻辑,如果采用传统的JSP技术,数据的展现样式和交互逻辑都被高度耦合的放到了JSP中。表现层选择的首先要考虑的就是需要把交互逻辑和显示逻辑进行解耦,也就是经常所说的HTM页面和代码的分离。页面代码分离有着多方面的意义,首先页面的调整尽量不会波及后台业务;其次美工参与页面的美化;能够使用HTML编辑工具对面进行编辑以提供工作效率;同时能够尽量保证设计期页面效果与运行期页面效果保持一致性。
2、组件可重用机制。在WEB应用有很多类似的应用场景,例如分页查询就是一类在绝大多数应用中需要用到都应用场景,WEB框架需要提供机制来保证开发人员能够简单灵活的重用类似的应用场景。
3、模块解耦机制。在WEB这一层实现模块之间的相互调用如果不能很好的处理好页面间的导航会带来很大麻烦。传统模式下(包括采用了Struts的应用)模块间的互相调用都采用跳转URL的方式来实现,这样的跳转打破了原有的导航顺序,为了不带来混乱需要在URL中增加额外的参数(例如很多时候需要通过参数告诉被调用的模块需要返回的URL)来保证URL导航的正确顺序,这些加入的额外的参数需要非常小心的处理,有时候还需把这些参数放置到SESSION这会给状态的维护带来麻烦。给维护也带来很大的麻烦,维护人员需要去猜测这些参数的作用。WEB框架应该能够以OO的方式对模块进行解耦方便相互之间的调用。
4、状态管理机制。由于HTTP协议的无状态特性,需要开发人员把一些状态放入HTTP SESSION来进行管理。如果不对SESSION进行必要封装和控制,任由开发人员随意的把对象放置到SESSION,必然会带来混乱,更严的情况是大量的状态复制严重消耗应用服务器群集的资源。
5、AJAX支持。WEB应用正朝着RIA方向发展,与客户的交互能力的要求越来越高,在硬件资源足够的情况,WEB应用的交互能力与桌面应用已经持平,画图甚至是三维动画都已经能在WEB应用中实现,这些技术上的突破都是应用AJAX技术的结果。AJAX从长远来讲是大的趋势,从现实上来讲AJAX技术能克服现有WEB应用的一些技术难题。WEB框架应该提供相应的功能能够支持AJAX技术。
6、尽量少的配置。很多WEB框架希望通过配置文件的方式来提供应用的灵活性,但这样做并没有取得想要的结果反而给开发带来了麻烦,首先配置没有编译器来检查它的正确性,其次开发人员需要维护配置文件和程序代码的一致性,团队开发需要对配置文件进行额外的协调。WEB框架最好能够在提供更好灵活性的前提下尽量少的使用配置文件。
7、开发工具支持。WEB开发很多时候会让人觉得十分的乏味和枯燥,例如编写一个需要提交几十个字段的Form表单就是一件很让人头疼的事情,极容易出错又十分的枯燥。我们希望Web框架能够提供相应的功能来完成这项讨厌的工作。
根据以上7点核心功能,对Struts1 ,Struts 2,JSF,wicket框架进行了分析,从7方面和学习难度上考虑觉得Wicket是一个非常优秀的WEB开发框架,能够完全满足我们应用的需求。下面我们先对Wicket做一个简单的介绍,然后和Struts进行对比分析。
2.1.1 Wicket简介
Wicket是一套借鉴了许多其他框架的优点而开发出来的WEB框架,是一个基于组件开发的框架。与早期的一些WEB框架相比较,Wicket使得Web开发更加简单,方便。与其它Web框架一样,Wicket也建立在Sun’s servlet API;但是与Struts和Spring那种MVC框架不同,因为使用Wicket的开发者,所关心的已经不再如何从客户端接收一个请求又或者如何向客户端发送一个应答。以往的框架往往提供一个Controller同时为多用户和多线程服务,负责处理请求及回复,不需要保存各种状态。但Wicket为用户提供了带有状态的各种组件。Wicket不再创建一个Controller,而是使用一个页面,并在上面放置各种控件,并定义控件如何响应用户的输入。
表面上看,这和开发桌面的GUI程序没有区别,象使用 Microsoft的VB,SUN的Swing,Borland的Delphi一样。使用控件可以使得可视化层更加容易开发,把更多时间花在业务或者其它核心功能上。更重要的是,这也让基于控件的GUI更加容易扩展。只需要通过添加相应的控件即可为系统添加更多的功能,而且不会影响到其它控件。这种基于控件开发的优势也同样可以用于Web开发,事实上许多Web框架都试图将桌面程序开发的优势移植到Web开发中。Apache Jakarta小组的Tapestry项目和Microsoft’s的ASP.NET,以及Sun’s JSF(Java Server Faces)标准都是佼佼者,Wicket也从它们中获益良多。目前这种技术象是一个模子刻出来的,通过一个模板文件来描述页面布局。 JSF使用了Sun的JSP技术(还有标签), ASP.NET则使用了ASP,而Tapestry则在标准的HTML基础上定义自己的模板系统。(译注:其实这几种技术有些不同,象ASP.NET则把模板文件当成可执行文件,继承一个Page,然后编译。JSF则把JSP编译成Servlet,它们事实上都是可以执行的,面Tapestry和 Wicket则是将HTML和代码分开,用后台类动态输出信息来替换HTML模板中的指定内容),当收到用户请求时,这些页面负责输出,同时调用后台对象动态输出时所需要的内容。 后台支持类往往是以Listener的方式出现的,而模板仅仅只定义控件的相关信息,如位置,类型等信息。
这种方式是对MVC2结构的一个改进。开发人员可以定义各种方法而不是使用一个统一而庞大的类而处理系统。通常的MVC2结构的框架,都是无状态的,通过 Wicket,开发人员不再管理状态。现在编写Java代码已经成为了自由人不再需要考虑WEB的特殊性,因为这些Java代码只需要提供页面输出时所需要的信息就可以了。
Wicket网站上对其特点归纳如下:
? 像swing一样的面向对象组件模型
Wicket中的所有页面和组件都是真正的java对象.具有对象的封装,继承以及事件等特征.
? 轻松开发
因为wicket是java 和html组成的,开发Wicket应用的时候,你可以选择你自己喜欢的编辑器来分别开发java和html.
? 关联分离
Wicket 不会混合html标记到你的java代码,对html标记文件也没有特殊的的语法要求.HTML和JAVA是两个并行的世界,他们仅仅通过wicket ids来联系.wicket id,在html中是一个元素的id,在java中是一个组件的属性.因为Wicket 中Html仅仅是html 并且Wicket中Java仅仅是java.那么编码者和界面设计者可以最大成都的独立工作而且不以为任何特别的工具.
? 安全可靠
默认情况下wicket是安全可靠的.不会通过URL暴露敏感信息,所有组件路径都是通过会话(session)关联的.会话之间共享信息必须通过确切的清晰的步骤来完成.这里还有很多关于在未来版本中为wicket增加URL加密来提高网络站点安全的计划.
? 透明的可缩放的集群支持
一个Wicket 应用可以不需要任何额外的工作就可以自动运行在集群上.一点理解瓶颈问题,Wicket能够调节页面状态.wicket的下一个版本将支持客户端模型的状态伸缩
? 透明后退按钮支持
? 组件重用
在Wicket开发可重用的组件是非常容易的,你只用Java关键字extends继承已有的组件加上你的扩展就成了一个新的组件,你也可以创建Panel来把其他组件组合成一个可以重用的单元。
? 简单,灵活,本地化的表单验证
? 会话类型安全
Wicket能够保证会话能够安全的在集群之间复制
? 可定制的工厂
Wicket非常容易扩展,利用工厂类和工厂方法可以轻松的配置Wicket选项
? 支持所有基本html特征
? 可编程处理html标签属性
? 自动转换
把内容自动转化为方便显示的格式。也可以自己定制如何转换
? 动态图形
支持动态的生成图形
? 分页列表
? 树组件
? 本地化
? 所有资源都能被延迟加载
? 透明支持Ajax
2.2 Wicket与Struts1比较
一、体系
Struts 从技术较大的方面来讲,虽然每个部分之间做到了一定程度的解耦,但是基于HTTP请求的处理模式,仅仅只是对Servlet的扩展,与Servlet API的紧密耦合造成Action的重用性很低,XML配置的灵活性完全被Action与Servlet API的紧密耦合完全抵消,通过修改XML来改变应用的导航顺序只能是不切实际的奢望。Struts通过标记库的方式来分离页面与显示逻辑,其结果是把Java代码替换成了仍然会让美工一头雾水的标记,把for语句替换成
? Struts没有实现与Servlet底层api解耦合,封装不完,没有重用的可能性;
? Struts采用自定义标记库,没有实现显示逻辑与页面的分离;
? Struts 没有完全实现MVC框架所需的事件驱动,仍就是HTTP传统的请求/应答方式。
而 Wicket的处理方式则不同,从整体来讲应该说是更加优雅些。他采用面向对象的组件技术实现web和用户的交互(这点有些如Swing)。在 Wicket中的每一页是由若干的使用组合设计模板生成的组件构成。页面和组件各自渲染自己,并直接或间接的和XHTML模板关联。当HTTP请求到来时,这些请求被转换、传递到组件上的相应事件中来,这一点和微软的ASP.NET很相象。所以Wicket能够解决struts体系中存在的问题:
? Wicket是完全面向对象的,并引入了组件技术,对Servlet底层api进行了完整的封装,我们能够利用组件的继承性设计自己的应用。在对Servlet底层api完整封装的前提下实现了事件驱动,这里无需为处理HTTP协议的请求/响应而作任何工作,这样的机制为重用提供很好的机会。
? Wicket所使用的视图模板和纯粹的HTML很接近,所以容易上手使用。Wicket在视图模板中所引入的内容很整洁,并符合 XHTML标准。任何了解HTML的开发者也就是美工都能够如编辑HTML文档那样编辑Wicket的视图模板,就好似他并不知道这是Wicket的视图模板。
二、HTTP请求处理
在 Struts中,一个HTTP请求被接收后,Struts将在配置文档中查找请求的URI和相应的Action类。假如这些已被配置好了,他将将提取请求参数放入到ActionForm bean中,并执行一些验证。然后HTTP请求、回应和ActionForm对象都将作为参数传入到Action类中。从这点能够看出Action的开发者掌控着应用的方方面面:他们必须处理HTTP session,维护HTTP请求和session的属性,并在action执行完时建立需要返回的信息,最后还要返回相应的ActionForward 以使struts知道下一步在哪里。假如此时ActionForward将控制权交给了JSP页面,开发者就要使用struts自定义的tag库编写 JSP代码。如此繁复的工作环节很容易出现错误,而且struts还需要保证三个位置的数据引用保持一致:struts XML配置文档、java Action类、JSP自定义tag。
而在Wicket中,一个HTTP请求被接收后,Wicket将确认HTTP所请求的那个页面和在这个页面关联的组件。假如请求的目的是form,Wicket将自动提取请求参数、验证参数、进行一些预先规定好的类型转换、配置form组件中的 model(模式,这里用法和MVC中类似,但有不同)值;接着转化请求为相应类型的事件、调用目标组件上的相应事件侦听器,这样就会导致事件处理代码运行来执行业务逻辑;然后,事件处理器还将指定下一步页面的位置,被指定的页面将初始化(假如页面从未被初始化的话)并自动渲染;渲染处理将按照顺序访问每个页面组件,需要他们进行自我渲染。在视图模板中能够组件仅通过名字和HTML元素进行映射。
? 每个组件知道如何处理自己事件。因此我们只需要将组件放到页面上,编写事件处理器就行了。假如一个页面中存在20个能引发事件的不同的组件,我们除了进行将他们添加到页面上的工作外没有别的工作。但假如在struts中,我们可能需要建立20个不同的Action类或一个具备20个分支语句的Action 类,并要在XML配置中逐一添加。
? Wicket带给了我们考虑组件/事件重用的机会。而不用将注意力放到如何处理HTTP请求和回应上。
? 和struts相比使用Wicket会降低我们的代码量,这正是重用组件带来的益处。Wicket本身不使用任何的XML配置文档。只需要修改web容器的web.xml文档中的servlet声明部分。
假如我们曾编写过直接使用Windows API的GUI程序,并用过Visual Basic或Borland Delphi的话,下面的比较会更加让人印象深刻。使用struts开发就像使用Windows API相同:接收原始消息,解码原始消息,然后再处理这些消息。由于Windows API是基于消息循环工作的,所以系统除了消息回应外不期望任何的返回值。
从另一方面看,Dephi在TApplication类中隐藏了Windows消息循环,使研发人员围绕着TApplication类建立其他的类。原始的系统消息就这样被Dephi内建类接收,被内建类解析并被确定其接纳者。消息被转换为一个事件,并被传送到某个特定的对象。
如Windows应用程式相同,Wicket应用也具备服务于文本和HTML模板的资源文档。从这点看,Wicket象用Delphi做桌面开发相同被用来做web研发。
三、Servlet API和HTTP协议的抽象
Struts 没有隐藏Servlet API和HTTP协议的细节。为了使用Struts,我们必须乐于和HTTPServletRequest、HttpServletResponse 和HttpSession类打交道。并围绕着请求和回应建立应用。这便是任何Model2 MVC web框架和生俱来的弱点。
正如上面说的,Wicket隐藏了Servlet API和HTTP协议的细节。对于一些应用,我们甚至触及不到这些细节。甚至对于很复杂的应用,我们也仅使用适当的Wicket协议封装类。而经常用到的是java组件类、POJO业务模型、纯HTML标记文档。
四、状态管理
使用Struts开发,我们将获得全部的状态管理权,但Action是没有状态的,这非常容易引起错乱,需要开发人员非常小心的来处理Http Session的状态。
在状态管理上,Wicket能够作为一个不错的选择。Wicket框架默认代管任何的组件状态。这对于常见的应用,在状态管理上的代码量几乎为0。但是 Wicket也提供了一些API使我们进行标准状态管理和实现自己的状态管理。这样,即使特殊需要,我们也能够全权掌控状态管理。
五、配置
不言自明,Struts需要一个XML文档:定义对HTTP请求和响应的映射和任何的ActionForm对象等。这个文档可能很大而且复杂。而新版本的Struts提供了将这个文档分解为多个模块的方法,虽然这样能够将模块分类,但是这样同样要维护许多的小文档。采用多个配置文件的时候,在对已有系统进行维护的时候XML配置文件会带来额外的麻烦,需要找出url所对应的Action组件需要逐一查找每个xml配置文件,或者开发的时候就准备一份专门登记url的文档。
Wicket 无需配置文档。Wicket通过一个简单的应用配置类或通过编写web容器的web.xml文档中Servlet init参数来完成程式的初始化。而HTTP请求到组件事件的映射、组件如何输出HTML等被包含在了Wicket的应用逻辑里,从而极大地简化了配置。