JSF和AJAX企业级开发之路

我的目在JSF和AJAX的整合。不管你选择什么版本的JSF,与AJAX的整合对于构建企业级应用程序来说是一个不错的选择。我会给大家展示这两种技术结合的方法,我特意增加了一些新内容——因为在这之前,已经有了JSF和AJAX的实际测试方法,但这种测试方法出现并不只局限于与JSF整合的AJAX应用,任何AJAX应用程序都可以使用.最后,我还会陈述一下如何评价JSF和AJAX的解决方案. 现在,我发现JSF与最初的2001年所处的情况惊人的相似——那个时就已经有许许多多的web框架,真可谓是百家争鸣,而JSF在其中脱颖而出,以绝对优势成为JCP标准.但现在,这种局面再次出现了.在过去的六年,我们始终紧跟时代的步伐,但仍然还有大量的web框架鏖战在我们周围,但是根据从采用JSF技术的网站数据以及供应商为之提供的工具和组件数量来看,JSF还是在不断增长且在市场上仍有一席之地,因此许多供应商也相继推出了JSF和AJAX整合方案.在今天下午2:30的小组讨论中,我和来自ICEsoft的Steve Maryka会一同出席,大家也许已经知道Steve已经推出一套相当漂亮的JSF和AJAX整合方案.届时我会以Sun代表身份出现,当然除Steve外,还有很多知名人士,我会将他们的姓名列在幻灯片上.但不管怎样,我只想给你们提供一些信息,以便当你看完这些不同的解决方案后,扪心自问:哪一个方案是最佳的?它有什么特性?这些特性可以满足我的企业要求吗? 

“企业级”已经是一个被过度滥用的术语了.那么按照我自己的理解,企业级指的是健壮,可伸缩,易于测试以及被业界证明可用性(industry proven)等.它需要被开发人员证明切实可行!JSF满足上述要求,因为刚才我所讲的大量的站点和大量的供应商支持足以证明这一点.另一个关于“企业级”的说法是:易于使用,易于开发,当然也包括易于测试.TDD(测试驱动开发)我的确喜欢,当我在领导团队开发一个JSF实现时,我们所做的一切都采用了TDD,并且效果显著.当然,“企业级的工具”也需要同时能够满足开发人员的需求.这一切往往在职场上扮演重要角色:你会雇用什么样的人才?他们所掌握的技能能够胜任这个开发工具吗?现存的开发工具是否又能满足他们的要求呢?并且最后一点我要强调的是:良好的可扩展性观念.当你所遇到的问题越来越多时,你所依赖的解决方案也要不断的提供抽象来解决这些不断增长的问题,此时JSF作为一个基于组件和多个扩展的解决方案,支持抽象和组件化满足了可扩展性.这就是我所定义的“企业级”概念. 

那么我所指的AJAX,也在这里告诉给大家吧:web应用程序通过使用异步机制与服务端进行交互,并且动态更新浏览器所显示页面的外观和行为.这么来定义AJAX我觉得还是有稍稍有点生硬.如果你与ICEsoft接触过,你会发现他们已经有了AJAX的“推”模式,使用了大量技术可以异步的将内容通过浏览器发送出去.大家熟知的Comet就是这种编程模式的一种实践,它在与AJAX整合时非常有用,不过今天我没有在幻灯片上提供任何关于它的信息,但是可以很明确地的说:Comet就是为与AJAX整合,当然也包括与JSF的整合.

好了,说完了的目的后,正式开始我们今天的议程吧.为什么JSF要与AJAX整合?为什么我会强调AJAX对于web应用程序来说是必须的?JSF和AJAX的整合方法有很多.其中JSF本身的设计和特性就使得它适合协同AJAX进行开发.下面是我们调查到的一些问题和解决方案.

一个解决这些问题的方案来自于Project Dynamic Faces(JSF的一个AJAX扩展)和MCP(Mozilla Control Program,使用JUnit或TestNG来自动测试web应用程序的一个包).这是一个很早就有的解决方案,当时我还在www.mozilla.org工作时已经有些Alpha级的技术来自动测试AJAX程序.现在我手头上有一些关于它的demo。

所有的web应用程序必须经过下列过程.为确保万无一失(motherhood applepie:美国黑话或政治家惯用的说语),你需要进行数据转换和数据验证,需要一种机制来指定页面流程(page flow),需要整合数据库.当然,你也许还会用持久层技术,比直接就可用的JAP和Hiberante.你还需要alphabet soup,国际化,本地化,以及易于访问.而这说到的最后一点,自AJAX它诞生以来,就一直是开发人员的痛.AJAX的反对者们大声嚷嚷:“好啊,你别想向政府部门卖出任何AJAX应用程序,因为有Section 508法案.”的确,有大量的实事摆在了面前,但不管怎么样,web应用程序必须是易于访问的.即使当你在制作页面的时候,你也需要考虑到对多语言的支持,以及基于CSS的样式设计.同样,它还需要保证,不管在单元测试还是系统测试级别上都要求是可测试的.最后一点就是用户体验了,所有这一切来来回回最终还是从开发人员到测试人员然后再到达最终用户.

现在,各种不同整合JSF和AJAX的方法都是为了降低复杂度。我现在为这些解决方案亮起了红灯。(这些解决方案都)有很多的赞成和反对的声音,但亮起的红灯表明反对占了上风。那么我要说的第一个整合JSF的方式就是直接使用Naked AJAX(未经过任何封装的AJAX),你打算一切靠自己,什么都打算自己写! Frank Zammetti写了一本书,他发明了“Naked AJAX”这个术语,指的是你不使用任何AJAX框架,全部由自己亲自来完成。如果你这么做,你会深入的理解AJAX底层的技术,因此很可能你在职业上炙手可热并且这也一切也确实是你想要得到的话,那么我不得不说你太有才了。

你必须亲自处理所有的使用XMLHttpRequest的交互请求,这就要求你有扎实的JavaScript基本功,使用SetTimeout函数等以及一系列常人所不愿意使用的技术。到时候,你还不得不去解决跨浏览器之痛,而这种痛苦对于web开发人员来说已经持续多年,最后为了与它有一个了断,你还是陷入了开发自己框架的沼泽之中。

第二个解决方案显得更高级些,因为你使用了JavaScript框架。现在已经有大量可用的JS框架充斥在我们周围,比如Dojo,DWR,Prototype等,这些框架也是今天要讨论的内容。但使用这些JS框架的话,你仍然需要去为你的web应用程序编写代码,而且一旦在JSF中使用了某个JS框架(比如说Dojo)的话,你又要去编写那些侵入性代码了。

Struts组件编程必须限定在Action/ActionForm/JSP这三个框框中做文章,难度相对比较大,而Tapestry/JSF则没有太多这些技术框框限制,两者在组件编程方面更让编程者自由一些,方便一些,这也是组件型框架的优势吧。

Struts标签库

在Struts中,经常需要使用标签库来显示组件ActionForm中内容,这就涉及到一个结合的问题,标签库是别人写的,参考Struts的标签库用法,而组件是自己的,难度和麻烦就体现在这个结合点上。

JSF基本思路和Struts差不多,只不过换了不同标签库,也需要标签库+组件的结合思考,不过因为组件这里是通用组件,没有什么限制,所以这样比Struts要轻松一些。

Tapestry使用了组件库概念替代了标签库,没有标签库概念,这样就没有标签库和自己的组件需要结合的问题,都是组件的使用,组件中分Tapestry标准组件和自己定义的组件,这也是接触了Jsp体系的人学习Tapestry面临的一个思路转换。

具体以页面跳转为例子,页面跳转是靠链接 实现,链接是页面经常使用的元素。

Struts提供的html:link在频繁使用就特别不方便,尤其在传递多个参数时:其中html:link的page值,是跳转对方页面或 Action的path,这个path一般需要到struts-config.xml查找Action的相应path,一旦配置文件path值修改,涉及到这个所有相关页面都要修改。

JSF将链接概念划分两个方面:导航性质和事件激活,在导航方面还是需要到配置faces-config查询Navigation的from-outcome的值。

由于Tapestry没有标签库概念,只有组件或页面两个概念,因此,链接跳转目标要么是组件,要么是页面,简洁简单,它没有多余的path概念,就是组件名,也就是对象名称,组件名称和path名称合二为一。

总结

JSF在很大程度上类似Struts,而不是类似Tapestry,可以说是一种Struts 2.0,都是采取标签库+组件的形式,只是JSF的组件概念没有象Struts那样必须继承ActionForm的限制;JSF在事件粒度上要细腻,不象 Struts那样,一个表单一个事件,JSF可以细化到表单中的每个字段上。

JSF只有在组件和事件机制这个概念上类似Tapestry,但是不似Tapestry那样是一个完全组件的框架,所以,如果你做一个对页面要求灵活度相当高的系统,选用Tapestry是第一考虑。

Struts/JSF则适合在一般的数据页面录入的系统中,对于Struts和JSF的选用,我目前个人观点是:如果你是一个新的系统,可以直接从JSF开始;如果你已经使用Struts,不必转换,如果需要切换,可以将JSF和Tapestry一起考虑。

另外,JSF/Tapestry不只是支持Html,也支持多种客户端语言如WML或XUI等。

这三者之间关系:如果说Struts是左派;那Tapestry则是右派;而JSF则是中间派,中庸主义是SUN联盟的一贯策略。

当然,你也可以发表你在实践中这三者任何一个的使用感受,以使得后来者有一个比较。

  

现在,更高级别的JSF和AJAX整合方式到来了。确切的说,这种更加容易使用的解决方案就是在使用JSF基础上再加上AJAX扩展。我上面已经提到了,现在有很多的解决方案了,今天我要谈论的是其中之一的Project Dynamic Faces。当你在使用这些解决方案时,通常是不需要去了解任何JavaScript知识的,因为它已经为你封装好JavaScript的编程实现,你只需要正常使用JSF的API去编程,就能达到AJAX的效果。当然,你如果需要的话,Dynamic Faces也是允许你去手工编写JavaScript的,(通过自己编写的JavaScript)你可以实现更强大复杂的操作。据我所之Dynamic Faces是目前为止唯一一个可以正确处理JSF上下文敏感(context sensitive)的AJAX交互组件,原因是它充分利用了JSF1.2的优势(注:虽然专家组们在讨论JSF2.0规范,但现在实际使用的JSF最新版本是1.2)。现在我们来看一个demo,假设说你有一个数据列表,当你随便碰到某个单元格时(注:类似于操作Excel.当我们在使用Excel的时候,光标所移动到的任何单元则都是可以随便操作,并保存的),你想通过AJAX去处理你所指定的那个单元格时,所有的单元格的在页面渲染完后状态都是可随时存储的,便于随时修改,此时显示在页面的data table(数据表格)就是dataset所持有的数据呈现给外部的一个窗口;当你在修改完data table的某行记录或某行记录中的某列后,想postback一下(注:postback指的是用户返回到以前访问过的一个页面,与页面对应的视图已经存在,所以只需恢复它。在这种情况下,JSF 使用现有视图的状态信息重新构造它的状态。)这时你需要将data table设置成自身,从而可以感知到改动的数据.JSF1.2已经添加了一些新特性来支持这样的应用场合.这还得多亏我们的专家组成员Jacob Hookom,同时他也是Facelets的作者.(注:Facelets是用来建立JSF应用程序时的一个可供选择的表现层技术)

我之所以为Dynamic Faces亮起红灯(表示警告),是因为JSF1.2有这个特性,它才能实现这个功能,而且还不是很成熟。虽然它现在当已经加入到Sun Web Developer Pack中去了,不过仍然处于0.1版本,与其它你可能听说过的AJAX解决方案相比,缺乏大量的测试。

下一级别的的JSF和AJAX整合方案就是直接使用带AJAX的JSF组件。用这类组件,与使用普通的JSF组件没有什么两样,实际上它们已经将AJAX所做的事都全部为你封装好了。这些组件也许会通过phase listener,filter或者其它什么配置来处理AJAX请求,但不需要你亲自去处理。现在已经有一些不错的组件可以使用了,而且相当一部分还支持JSF1.1。这些组件中,有些是开源的,有些要付费的,总之这是一个相当大的市场,你可以登录www.jsfcentral.com,这是由另一名专家组成员Kito Mann运作的,里面有很多非常优秀的组件,并且你还可以从中了解目前JSF组件的市场行情。

退一步说,如果在众多JSF组件中,仍然没有让你感到满意的话,你就得亲自写代码了,要不然用DynaFacesr扩展也是可以的。

好了,到这里,当我在考虑JSF整合AJAX这部分的时候,一个大难题浮现在我脑中:是应该支持各种途径去使用AJAX(比如说允许自己编写客户端代码)呢,还是像通常的web应用程序那样,只采用UI标签方式呢?我的观点是,不支持,没有必要。关于这个点会在小组讨论中谈到。如果采用Dojo方式的话,你的大量ViewLogic(页面逻辑)绑定在客户端上,这样做也许只是将服务器变得负担轻一些;而使用GWT的话,你得将Java编译成JavaScript代码,但此时的JavaScript仍然运行在客户端,然后使用一个类似于RMI的机制通过服务器端来来回回不停的调用。但以上这些只是考虑了客户端这个方面!另一方面,你仍然可以使用基于服务端开发工具,去开发你的组件,然后markup(标记)在服务端上,这样就可以通过服务端呈现给客户端,这一类的解决方案的思想就是将UI组件的状态保存在服务端.我也觉得无论从成熟度,相应工具的支持程度还是可维护性上来说,这样做都有很大的优势.按照我的话来说,将大量的UI组件逻辑保存在服务器上,你会发现更加易去维护.

因此,对于上述问题的一种解决办法是,把JSF当作web应用程序开发的基础,并且你只需要在此基础上略施小计就可以得到AJAX支持.JSF的AJAX扩展就是这么实现的,我现在将一些熟悉的扩展列出来:Dynamic Faces,ICEfaces,AJAX for JSF(现在和JBoss搭上了伙,成为了RichFaces),BackBase还JackBe..总之,在www.jsfmatrix.net站点可以看到这些解决方案之间的比较.另一个不错的解决办法来自于JCP,我们会将现在上面列出的那些扩展中先进的思想提交给JSF专家组,并且我们正准做出更多的努力,但现在无法透露太多。(看来JCP的专家组们还是没有改变办事过于拖拉的毛病,因此估计官方的JSF和AJAX方案一时半会是出不来了。)

那么为什么从设计的角度就要将JSF和AJAX整合在一起呢?因为JSF天生有着Swing的特性,如果你喜欢采用基于组件的面向对象方式进行编程,你会发现JSF的设计就是为AJAX而准备的.一些JSF的特性使得AJAX变得更加友好并进一步扩展了JSF UI组件模型;一个建立在servlet之上,定义良好的请求处理生存周期(request processing life cycle)管理着WebRequest各种状态(phase)下不同的生存周期,比起单纯的request, response要丰富的多,甚至我感觉这一点在脱离JSF仍然十分有用.那就是我们打算让JSF2.0应用程序以更加偏重于client-centric方式,来贯穿整个JSF生存周期,甚至到时候要不要JSF组件都说不定了,但验证和类型转换等这类东西还是需要的.

另一个特性就是灵活和可扩展的组件呈现模型(Rendering Model).Rendering的概念源于组件,你可以用render kits(套件)去丰富基于JavaScript的应用程序,与HTML4.01相比,它的内容更加丰富。各种各样的render kits为你隐藏了复杂的底层细节,帮助你实现网站的多种版本。这里还有一个关于封装的概念:JavaScript的封装不应该交给页面的编写人员,应该交给组件开发人员,最终所有的JSF组件统一管理在一起,更加方便透明的保持客户端与服务器之间的同步。

现在我们来看一些典型的AJAX问题与解答:

1.跨浏览器问题,通过封装好的JavaScript框架已经很可做到这一点了

2.本地化和国际化问题,用JSF就可以搞定了,AJAX根本不需要参与

3.Shell remoting的机制就是专门用来管理脚本,它用一种安全的方式为你的组件提供存放在class path外面的JavaScript脚本.

4.如果你觉得你写了太多的XMLHttpRequest来来回回与服务器进行交互的话,你可以使用Dynamic Faces的批处理事件(或找一个具备批处理事件的类似替换物),一次性将所有的事件发送完成.

5.使用XML作为(AJAX与服务器交互后的返回的)传输数据的话,要求对于某些HTML元素做一些额外的优化工作.比如说,  是HTML的一个实体,但它在XML中却什么都不是.当XMLHttpRequest的responseXML包含 的话,Mozilla浏览器将无法正常解析XML,它会认为这是一个无效的实体,因此,我不知道你们是不是也觉得这算是Mozilla的一个Bug呢?此时你必要按照某种方式去定义那些东西,并且确保这类问题通过JSF和AJAX的方案来解决.

为现有的或即将立项的JSF应用程序插上AJAX翅膀,我个人觉得对于应用程序来说非常棒.我想我们应该可以做到让一个已经完成的项目AJAX化(AJAXify),并且如果是新的项目的话,保证还能从中得到更多的好处.这一切还得再次得归功Jacob Hookom天才的理念。我觉得他的Project Dynamic Faces为开发人员朝着AJAX方向前进了一小步.真的!!!就两个JSP Tag和两个JavaScript Function需要你掌握,但就是这小小的一步,你也已经可以从中得到很多AJAX特性了.

因此,这里有一个基本的概念.将JSF的生存周期通过AJAX暴露给浏览器,并且你想通过AJAX来操作整个View或其中的某个部分,从而达到更新一块单独的View区域或某个组件的目的,或者干脆越过AJAX来刷新整个页面也能实现。有时候,你希望通过使用AJAX可以越过JSF的生存周期,来取得一些控制级别并且你还可以让服务器(在不刷新页面的情况下)来改变当前页面的外观或行为.通常这对于Swing或其它native UI Tookit开人员来说,很好理解:当前窗体的部分外观或行为被更新过了,服务器当然只会去对那部分作一下修改,犯不着整个窗体都重新更新一遍。现在将这个观念带回到Web开发中来,页面的部分内容或行为改变了,你重绘(repaint)一下不就得了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值