版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
面向Java开发人员的Ajax:构developerWorks.
建动态的Java应用程序
Ajax为更好的Web应用程序铺平了道路
别:中级文档选项
PhilipMcCarthy(),软件开发顾问,独立征询顾问
2023年10月20日胭打印本页
在Web应用程序开发中,页面重载循环是最大的一个回将此页作为电子邮件
使用障碍,对于Java,”开发人员来说也是一个严峻的
发送
挑战。在这个系列中,作者PhilipMcCarthy介绍了
■="讨论
一种创建动态应用程序体验的开创性方式。Ajax(异步£样例代码
JavaScript和XML)是一种编程技术,它允许为基于
Java的Web应用程序把Java技术、XML和JavaScript组合起来,从而打
破页面重载的范式。
Ajax(即异步JavaScript和XML)是一种Web应用程序开发的手段,它采用
客户端脚本与Web服务器互换数据。所以,不必采用会中断交互的完整页面刷
新,就可以动态地更新Web页面。使用Ajax,可以创建更加丰富、更加动态
的Web应用程序用户界面,其即时性与可用性甚至可以接近本机桌面应用程
序。
Ajax不是一项技术,而更像是一个模式种辨认和描述有用的设计
技术的方式。Ajax是新奇的,由于许多开发人员才刚刚开始知道它,但是所有
实现Ajax应用程序的组件都己经存在若干年了。它目前受到重视是由于在
2023和2023年出现了一些基于Ajax技术的非常棒的动态WebUL最著名
的就是Google的GMail和Maps应用程序,以及照片共享站点Flickr。这
些用户界面具有足够的开创性,有些开发人员称之为“Web2.0",因此对Ajax
应用程序的爱好飞速上升。
在这个系列中,我将提供使用Ajax开发应用程序需要的所有工具。在第一篇
文章中,我将解释Ajax背后的概念,演示为基于Java的Web应用程序创建
Ajax界面的基本环节。我将使用代码示例演示让Ajax应用程序如此动态的服
务器端Java代码和客户端JavaScript。最后,我将指出Ajax方式的一些局
限性,以及在创建Ajax应用程序时应当考虑的一些更广的可用性和访问性问
题。
更好的购物车
可以用Ajax增强传统的Web应用程序,通过消除页面装入从而简化交互。为
了演示这一点,我采用一个简朴的购物车示例,在向里面添加项目时,它会动
态更新。这项技术假如整合到在线商店,那么用户可以连续地浏览和向购物车
中添加项目,而不必在每次点击之后都等候完整的页面更新。虽然这篇文章中
的有些代码特定于购物车示例,但是演示的技术可以应用于任何Ajax应用程
序。清单1显示了购物车示例使用的有关HTML代码,整篇文章中都会使用这
个HTMLo
清单1.购物车示例的有关片断
<!--Tabieofproductsfromstore*scatalog,onerowperitem-->
<th>Name</th><th>Description</th><th>Price</th><thx/th>
<tr>
<!--itemdetails-->
<td>Hat</td><td>Stylishbowlerhat</td><td>$19.99</td>
<td>
<!-ClickbuttontoadditemtocartviaAjaxrequest-->
<buttononclick="addToCart('hatOOl*)">AddtoCart</button>
</td>
</tr>
<!--Representationofshoppingcart,updatedasynchronously-->
<ulid="cart-contents">
<!--List-itemswillbeaddedhereforeachiteminthecart-->
</ul>
<!--Totalcostofitemsincartdisplayedinsidespanelement->
Totalcost:<spanid="total">$0.00</span>
Ajax往返过程
Ajax交互开始于叫作XMLHttpRequest的JavaScript对象。顾名思义,它
允许客户端脚本执行HTTP请求,并解析XML服务器响应。Ajax往返过程的
第一步是创建XMLHttpRequest的实例。在XMLHttpRequest对象上设立请
求使用的HTTP方法(GET或POST)以及目的URL。
现在,您还记得Ajax的第一个a是代表异步(asynchronous)吗?在
发送HTTP请求时,不想让浏览器挂着等候服务器响应。相反,您想让浏览器
继续对用户与页面的交互进行响应,并在服务器响应到达时再进行解决。为了
实现这个规定,可以在XMLHttpRequest上注册一个回调函数,然后异步地
分派XMLHttpRequest。然后控制就会返回浏览器,当服务器响应到达时,会
调用回调函数。
在JavaWeb服务器上,请求同其他HttpServletRequest同样到达。在解
析了请求参数之后,servlet调用必要的应用程序逻辑,把响应序列化成XML,
并把XML写入HttpServletResponseo
回到客户端时,现在调用注册在XMLHttpRequest上的回调函数,解决服务
器返回的XML文档。最后,根据服务器返回的数据,用JavaScript操纵页面
的HTMLDOM,把用户界面更新。图1是Ajax往返过程的顺序图。
图1.Ajax往返过程
现在您对Ajax往返过程有了一个高层面的结识。下面我将放大其中的每一环
节,进行更具体的观测。假如过程中迷了路,请回头看图1一一由于Ajax方
式的异步性质,所以顺序并非十分简朴。
□
分派XMLHttpRequest
我将从Ajax序列的起点开始:创建和分派来自浏览器的XMLHttpRequesto
不幸的是,不同的浏览器创建XMLHttpRequest的方法各不相同。清单2的
JavaScript函数消除了这些依赖于浏览器的技巧,它可以检测当前浏览器要使
用的对的方式,并返回一个可以使用的XMLHttpRequest。最佳是把它当作辅
助代码:只要把它拷贝到JavaScript库,并在需要XMLHttpRequest的时
候使用它就可以了。
清单2.创建跨浏览器的XMLHttpRequest
/*
*ReturnsanewXMLHttpRequestobject,orfalseifthisbrowser
*doesn'tsupportit
*/
functionnewXMLHttpRequest(){
varxmlreq=false;
if(window.XMLHttpRequest){
//CreateXMLHttpRequestobjectinnon-Microsoftbrowsers
xmlreq=newXMLHttpRequest。;
}elseif(window.Activexobject){
//CreateXMLHttpRequestviaMSActiveX
try{
//TrytocreateXMLHttpRequestinlaterversions
//ofinternetExplorer
xmlreq=newActiveXObject("Msxml2.XMLHTTP");
}catch(el){
//FailedtocreaterequiredActivexobject
try(
//Tryversionsupportedbyolderversions
//ofinternetExplorer
xmlreq=newActivexobject("Microsoft.XMLHTTP");
}catch(e2){
//UnabletocreateanXMLHttpRequestwithActiveX
)
}
}
returnxmlreq;
}
稍后我将讨论解决那些不支持XMLHttpRequest的浏览器的技术。目前,示
例假设清单2的newXMLHttpRequest函数总能返回XMLHttpRequest实
例。
返回示例的购物车场景,我想要当用户在目录项目上点击AddtoCart时启动
Ajax交互。名为addToCart()的onclick解决函数负责通过Ajax调用
来更新购物车的状态(请参阅清单1)。正如清单3所示,addToCart()需
要做的第一件事是通过调用清单2的newXMLHttpRequest0函数得
到XMLHttpRequest对象。接下来,它注册一个回调函数,用来接受服务器
响应(我稍后再具体解释这一步;请参阅清单6)o
由于请求会修改服务器上的状态,所以我将用HTTPPOST做这个工作。通
过POST发送数据规定三个环节。第一,需要打开与要通信的服务器资源
的POST连接一一在这个示例中,服务器资源是一个映射到
URLcart,do的servleto然后,我在XMLHttpRequest上设立一个头,
指明请求的内容是表单编码的数据。最后,我用表单编码的数据作为请求体发
送请求。
清单3把这些环节放在了一起。
清单3.分派AddtoCartXMLHttpRequest
/*
*Addsanitem,identifiedbyitsproductcode,totheshoppingcart
*itemcode-productcodeoftheitemtoadd.
*/
functionaddToCart(itemcode){
//ObtainanXMLHttpRequestinstance
varreq=newXMLHttpRequest。;
//Setthehandlerfunctiontoreceivecallbacknotifications
//fromtherequestobject
varhandlerFunction=getReadyStateHandler(req,updatecart);
req.onreadystatechange=handlerFunction;
//OpenanHTTPPOSTconnectiontotheshoppingcartservlet.
//Thirdparameterspecifiesrequestisasynchronous.
req.open("POST","cart.do",true);
//Specifythatthebodyoftherequestcontainsformdata
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
//SendformencodeddatastatingthatIwanttoaddthe
//specifieditemtothecart.
req.send("action=add&item="+itemCode);
)
这就是建立Ajax往返过程的第一部分,即创建和分派来自客户机的HTTP请
求。接下来是用来解决请求的Javaservlet代码。
□
servlet请求解决
用servlet解决XMLHttpRequest,与解决普通的浏览器HTTP请求同样。可
以用HttpServletRequest.getParameter()得到在POST请求体中发送的
表单编码数据。Ajax请求被放进与来自应用程序的常规Web请求同样
的HttpSession中。对于示例购物车场景来说,这很有用,由于这让我可以
把购物车状态封装在JavaBean中,并在请求之间在会话中维持这个状态。
清单4是解决Ajax请求、更新购物车的简朴servlet的一部分。Cartbean
是从用户会话中获得的,并根据请求参数更新它的状态。然后Cart被序列
化成XML,XML又被写入ServletResponseo重要的是把响应的内容类型设立
为application/xml,否则XMLHttpRequest不会把响应内容解析成XML
DOMo
清单4.解决Ajax请求的servlet代码
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)
throwsjava.io.lOException{
Cartcart=getCartFromSession(req);
Stringaction=req.getParameter("action");
Stringitem=req.getParameter("item");
if((action!=nultem!=null)){
//AddorremoveitemsfromtheCart
if("add".equals(action)){
cart.addltem(item);
}elseif("remove".equals(action)){
cart.removeitems(item);
)
}
//serializetheCart'sstatetoXML
Stringcartxml=cart.toXml();
//writeXMLtoresponse.
res.setContentType("application/xmlH);
res.getwriterO.write(cartxml);
}
清单5显示了Cart.toXml()方法生成的示例XML。它很简朴。请注
意cart元素的generated属性,它
是System.currentTimeMillis()生成的一个时间戳。
清单5.Cart对象的XML序列化示例
<?xmlversion="1.0"?>
<cartgenerated=n4"total="5171.95">
<itemcode="hat001">
<name>Hat</name>
<quantity>2</quantity>
</item>
<itemcode="cha001">
<name>Chair</name>
<quantity>l</quantity>
</item>
<itemcode="dog001">
<name>Dog</name>
<quantity>l</quantity>
</item>
</cart>
假如查看应用程序源代码(可以从W一节得到)中的Cart.java,可以
看到生成XML的方式只是把字符串添加在一起。虽然对这个示例来说足够了,
但是对于从Java代码生成XML来说则是最差的方式。我将在这个系列的下一
期中介绍一些更好的方式。
现在您已经知道了CartServlet响应XMLHttpRequest的方式。下一件事
就是返回客户端,查看如何用XML响应更新页面状态。
□
用JavaScript进行响应解决
XMLHttpRequest的readyState属性是一个数值,它指出请求生命周期的
状态。它从0(代表“未初始化”)变化到4(代表“完毕”)。每
次readyState变化时,readystatechange事件就触发,由
onreadystatechange属性指定的事件解决函数就被调用。
在清单3中已经看到了如何调用getReadyStateHandler()函数创建事
件解决函数。然后把这个事件解决函数分派给onreadystatechange属性。
getReadyStateHandler()运用了这样一个事实:函数是JavaScript中的一
级对象。这意味着函数可以是其他函数的参数,也可以创建和返回其他函数。
getReadyStateHandler()的工作是返回一个函数,检
查XMLHttpRequest是否已经完毕,并把XML响应传递给调用者指定的事件
解决函数。清单6是getReadyStateHandler()的代码。
清单6.getReadyStateHandler()函数
/*
*ReturnsafunctionthatwaitsforthespecifiedXMLHttpRequest
*tocomplete,thenpassesitsXMLresponsetothegivenhandlerfunction.
*req-TheXMLHttpRequestwhosestateischanging
*responsexmlHandler-FunctiontopasstheXMLresponseto
*/
functiongetReadyStateHandler(req,responsexmlHandler){
//Returnananonymousfunctionthatlistenstothe
//XMLHttpRequestinstance
returnfunction(){
//iftherequest'sstatusis"complete"
if(req.readystate==4){
//Checkthatasuccessfulserverresponsewasreceived
if(req.status==200){
//PasstheXMLpayloadoftheresponsetothe
//handlerfunction
responsexmlHandler(req.responseXML);
}else(
//AnHTTPproblemhasoccurred
alert("HTTPerror:"+req.status);
)
)
}
)
HTTP状态码
在清单6中,检
查XMLHttpRequest的status属
性以查看请求是否成功完毕。
status包含服务器响应的HTTP状态
码。在执行简朴的GET和POST请
=求时,可以假设任何大于200(0K)的
码都是错误。假如服务器发送重定向响
应(例如301或302),浏览器会透明
地进行重定向并从新的位置获取资源;
XMLHttpRequest看不到重定向状态
码。并且,浏览器会自动添加
Cache-Control:no-cache头到所
关于getReadyStateHandler()有XMLHttpRequest,这样客户代码永
getReadyStateHand1er()是段相远也不用解决304(未经修改)服务器
对复杂的代码,特别是假如您不习响应。
惯阅读JavaScript的话。但是通
过把这个函数放在JavaScript库中,就可以解决Ajax服务器响应,而不必
解决XMLHttpRequest的内部细节。重要的是要理解如何在自己的代码中使
用getReadyStateHandler()()
在清单3中看到了getReadyStateHandler()像这样被调用:
handlerFunction=getReadyStateHandler(req,updateCart)»在这个示例中,
getReadyStateHandler()返回的函数将检查在req变量中
的XMLHttpRequest是否已经完毕,然后用响应的XML调用名
为updateCart的函数。
提取购物车数据
清单7是updateCart()自身的代码。函数用DOM调用检查购物车的XML
文档,然后更新Web页面(请参阅清单1),反映新的购物车内容。这里的
重点是用来从XMLDOM提取数据的调用。cart元素的generated属性是
在Cart序列化为XML时生成的一个时间戳,检查它可以保证新的购物车数
据不会被旧的数据覆盖。Ajax请求天生是异步的,所以这个检查可以解决服务
器响应未按顺序到达的情况。
清单7.更新页面,反映购物车的XML文档
functionupdateCart(cartXML){
//Gettheroot"cart"elementfromthedocument
varcart=cartXML.getElementsByTagNameC'cart")[0];
//Checkthatamorerecentcartdocumenthasn*tbeenprocessed
//already
vargenerated=cart.getAttribute("generated");
if(generated>lastcartupdate){
lastcartupdate=generated;
//CleartheHTMLlistusedtodisplaythecartcontents
varcontents=document.getElementByid("cart-contents");
contents.innerHTML=;
//Loopovertheitemsinthecart
varitems=cart.getElementsByTagNameC'item");
for(varI=0;I<items.length;I++){
varitem=iterns[I];
//Extractthetextnodesfromthenameandquantityelements
varname=item.getElementsByTagName("name")[0]
.firstchild.nodevalue;
varquantity=item.getElementsByTagName("quantity")[0]
・firstchi1d.nodeVaiue;
//CreateandaddalistitemHTMLelementforthiscartitem
var1i=document.createElementC'li");
1i.appendchi1d(document.createTextNode(name+"x"+quantity));
contents.appendchi1d(1i);
)
}
//Updatethecart'stotalusingthevaluefromthecartdocument
document.getElementByld("total*').innerHTML=
cart.getAttribute("total");
)
到此,整个Ajax往返过程完毕了,但是您也许想让Web应用程序运营一下查
看实际效果(请参阅W一节)。这个示例非常简朴,有很多需要改善之
处。例如,我包含了从购物车中清除项目的服务器端代码,但是无法从UI访
问它。作为一个好的练习,请试着在应用程序现有的JavaScript代码之上构
建出可以实现这个功能的代码。
使用Ajax的挑战
就像任何技术同样,使用Ajax也有许多余错的也许性。我目前在这里讨论的
问题还缺少容易的解决方案,但是会随着Ajax的成熟而改善。随着开发人员
社区增长开发Ajax应用程序的经验,将会记录下最佳实践和指南。
XMLHttpRequest的可用性
Ajax开发人员面临的一个最大问题是:在没有XMLHttpRequest可用时该如
何响应?虽然重要的现代浏览器都支持XMLHttpRequest,但仍然有少数用户
的浏览器不支持,或者浏览器的安全设立阻止使用XMLHttpRequest。假如开发
的Web应用程序要部署在公司内部网,那么也许拥有指定支持哪种浏览器的权
力,从而可以认为XMLHttpRequest总能使用。但是,假如要部署在公共Web
上,那么就必须当心,假如假设XMLHttpRequest可用,那么就也许会阻止
那些使用旧的浏览器、残疾人专用浏览器和手持设备上的轻量级浏览器的用户
使用您的应用程序。
所以,您应当努力让应用程序“平稳降级”,在没有XMLHttpRequest支持
的浏览器中也可以工作。在购物车的示例中,把应用程序降级的最佳方式也许
是让AddtoCart按钮执行一个常规的表单提交,刷新页面来反映购物车更新
后的状态。Ajax的行为应当在页面装入的时候就通过JavaScript添加到页
面,只有在XMLHttpRequest可用时才把JavaScript事件解决函数附加到
每个AddtoCart按钮。另一种方式是在用户登录时检
测XMLHttpRequest是否可用,然后相应地提供应用程序的Ajax版本或基
于表单的普通版本。
可用性考虑
关于Ajax应用程序的某些可用性问题比较普遍。例如,让用户知道他们的输
入已经注册了也许是重要的,由于沙漏光标和spinning浏览器的常用反馈机
制"throbber”对XMLHttpRequest不合用。一种技术是用“Now
updating..."类型的信息替换Submit按钮,这样用户在等候响应期间就不会
反复单击按钮了。
另一个问题是,用户也许没有注意到他们正在查看的页面的某一部分已经更新
了。可以使用不同的可视技术,把用户的眼球带到页面的更新区域,从而缓解
这个问题。由Ajax更新页面导致的其他问题还涉及:“破坏了”浏览器的后
退按钮,地址栏中的URL也无法反映页面的整个状态,妨碍了设立书签。请参
阅参考资料一节,获得专门解决Ajax应用程序可用性问题的文章。
服务器负载
用Ajax实现代替普通的基于表单的UI,会大大提高对服务器发出的请求数
量。例如,一个普通的GoogleWeb搜索对服务器只有一个请求,是在用户提
交搜索表单时出现的。而GoogleSuggest试图自动完毕搜索术语,它要在用
户输入时向服务器发送多个请求。在开发Ajax应用程序时,要注意将要发送
给服务器的请求数量以及由此导致的服务器负荷。减少服务器负载的办法是,
在客户机上对请求进行缓冲并且缓存服务器响应(假如也许的话)。还应当尝
试将AjaxWeb应用程序设计为在客户机上执行尽也许多的逻辑,而不必联络
服务器。
解决异步
非常重要的是,要理解无法保证XMLHttpRequest会按照分派它们的顺序完
毕。事实上,应当假设它们不会按顺序完毕,并且在设计应用程序时把这一点
记在心上。在购物车的示例中,使用最后更新的时间戳来保证新的购物车数据
不会被旧的数据覆盖(请参阅清单7)o这个非常基本的方式可以用于购物
车场景,但是也许不适合其他场景。所以在设计时请考虑如何解决异步的服务
器响应。
结束语
现在您对Ajax的基本原则应当有了很好的理解,对参与Ajax交互的客户端
和服务器端组件也应当有了初步的知识。这些是基于Java的AjaxWeb应用
程序的构造块。止匕外,您应当理解了随着Ajax方式的一些高级设计问题。创
建成功的Ajax应用程序规定整体考虑,从UI设计到JavaScript设计,再
到服务器端架构;但是您现在应当已经武装了考虑其他这些方面所需要的核心
Ajax知识。
假如使用这里演示的技术编写大型Ajax应用程序的复杂性让您觉得恐慌,那
么有好消息给您。由于Struts、Spring和Hibernate这类框架的发展把Web
应用程序开发从底层ServletAPI和JDBC的细节中抽象出来,所以正在出现
简化Ajax开发的工具包。其中有些只侧重于客户端,提供了向页面添加可视
效果的简便方式,或者简化了对XMLHttpRequest的使用。有些则走得更远,
提供了从服务器端代码自动生成Ajax接口的方式。这些框架替您完毕了繁重
的任务,所以您可以采用更高级的方式进行Ajax开发。我在这个系列中将研
究其中的一些。
Ajax社区正在快速前进,所以会有大量有价值的信息涌现。在阅读这个系列的
下一期之前,我建议您参考参考资料一节中列出的文章,特别是假如您是
刚接触Ajax或客户端开发的话。您还应当花些时间研究示例源代码并考虑一
些增强它的方式。
在这个系列的下一篇文章中,我将进一步讨论XMLHttpRequestAPI,并推荐
一些从JavaBean方便地创建XML的方式。我还将介绍替代XML进行Ajax
数据传递的方式,例如JSON(JavaScriptObjectNotation)轻量级数据互换
格式。
下载
描述名字大小下载方法
Samp1ecodej-ajaxl.zip8KBHTTP
□
臼关了下载方法的1"
参考资料
学习
•您可以参阅本文在developerWorks全球站点上的英文原文。
•"BeyondIheDOM”(DetheElza,developerWorks,2023年5月):
进行XML文档访问的有用的JavaScript技术。
•“AJAX及使用E4X编写Web服务脚本,第1部分”(PaulFremantle
和AnthonyElder,developerWorks,2023年4月):用Ajax在支
持E4XJavaScript扩展的浏览器中进行SOAP调用。
•“Ajax:ANewApproachtoWebApplications”(JesseJamesGarrett,
AdaptivePath,2023年2月):介绍Ajax起源的短文。
•TheJava.BluePrinlsSolutionsCalalog:介绍了Ajax在几个常见Web
应用程序场景中的应用。
•AjaxP:包含多项改善Ajax应用程序的UI技术。
•XMLHttpRequestUsabilityGuidelines:对使用Ajax提高用户体验的
建议。
•AjaxMistakes:Ajax应用程序应当避免的可用性问题。
・Java技术专区:在这里可以找到关于Java编程的各个方面的文章。
获得产品和技术
•MozillaFirefox:DOMInspector和JavaScriptDebugger扩展消除
了许多Ajax开发的痛苦。
讨论
・参与论坛讨论。
・developerWorksblogs:力口入developerWorks社区。
面向Java开发人员的Ajax:Ajax的Java对象序列化
在Ajax应用程序中序列化数据的五种途径
0
别:中级
PhilipMcCarthy(),软件开发顾问,独立顾问
2023年10月24日
假如您正在使用异步JavaScript和XML(Ajax)进行Jav如Web开发,那么
您最关心的问题也许就是把数据从服务器传递给客户机。在面向Java开发
人员的Ajax系列的第二篇文章中,PhilipMcCarthy介绍了Java对象序列
化的五种方式,并提供了选择最适合应用程序的数据格式和技术所需要的所有
信息。
在这个系列的第一篇文章中,我介绍了Ajax的构造块:
•如何用JavaScriptXMLHttpRequest对象从Web页面向服务器发送
异步请求。
・如何用Javaservlet解决和响应请求(向客户机返回XML文档)。
・如何在客户端用响应文档更新页面视图。
这一次,我将继续讨论Ajax开发的基础知识,但是将侧重于许多JavaWeb开
发人员最关心的问题:为客户机生成数据。
多数Java开发人员已经把模型-视图-控制器(MVC)模式应用在他们的Web应
用程序上。在传统的Web应用程序中,视图组件由JSP或者其他表达技术(例
如Velocity模板)构成。这些表达组件动态地生成全新的HTML页面,替代
用户以前正在查看的页面,从而更新用户界面。但是,在JavaWeb应用程序
使用AjaxUI的情况下,基于从XMLHttpRequest的响应接受到的数据,
JavaScript客户端代码对于更新用户看到的内容负有最终责任。从服务器的角
度来看,视图成为它响应客户机请求而发送的数据表达。
这篇文章侧重于可以用来生成Java对象以数据为中心的视图的技术。我将演
示可以把JavaBeans变成XML文档的各种方法,并且讨论每种方法的优劣。
您将看到为什么XML并不总是最佳的途径:对于简朴的Ajax请求来说,传输
纯文本更好。最后,我将介绍JavaScript对象标注(JSON)»JS0N允许数据
以序列化的JavaScript对象图的形式传输,在客户端代码中解决序列化的
JavaScript对象图极为容易。
关于示例
我将使用一个示例应用程序和几个用例来演示这里讨论的技术特性和技术。图
1显示的极为简朴的数据模型可以表达示例用例。这个模型代表在线商店中的
顾客帐户。顾客拥有以前订单的集合,每个订单包含几个商品。
图1.简朴的对象模型
CustomerOrderItem
+usernameo*+id1*+id
+realname+date+name
+orders+cost+description
+items+price
虽然XMLHttpRequest对于发送数据使用的格式没有做任何限制,但是对于
多数目的来说,只发送传统的表单数据是适合的,所以我的讨论集中在服务器
的响应上。响应也可以有基于文本的格式,但是正如它的名字表达的,
XMLHttpRequest具有内置的解决XML响应数据的能力。这使XML成为Ajax
响应的默认选择,所以我们从XML格式开始讨论。
从Java类产生XML
把Ajax响应作为XML来传递有许多因素:每个支持Ajax的浏览器都有导航
XML文档的方法,也有许多服务器端技术可以解决XML数据。通过制定一个方
案,描述要互换的文档类型,在Ajax客户端和服务器端之间很容易定义合约,
并且假如服务器端架构采用面向服务的方式,那么使用XML也可以允许非
Ajax客户机使用您提供的数据。
我将考虑从Java对象产生XML数据的三种方法,并讨论每种方法的优劣。
自行进行序列化
一方面,可以从对象图以编程的方式生成XMLo这种方式可以简朴到只是在每
个JavaBean类中实现toXml()方法即可。然后就可以选择合适的XMLAPI,
让每个bean提供表达自己状态的元素,并递归地对自己的成员调用对象图。
显然,这种方式无法扩展到大量的类,由于每个类都需要专门编写自己的XML
生成代码。从好的方面来看,这是一个实现起来简朴的方式,没有额外的配置
支出或者更复杂的构建过程支出,任何JavaBean图都可以只用几个调用就变
成XML文档。
在本系列前一篇文章的示例代码中,我把XML标记字符串连接在一起,实
现了toXml。方法。上次我就提到过,这是个糟糕的方法,由于它把保证标
记配对、实体编码等工作的承担放在每个toXml()方法的代码中。在Java
平台上有几个XMLAPI可以替您做这些工作,这样您就可以把精力集中在XML
的内容上。清单1用JDOMAPI实现了在线商店示例中表达订单的类中
的toXml()(请参阅|»|1)o
清单1.Order类的toXml()的JD0M实现
publicElementtoXml(){
ElementelOrder=newElementC'order'*);
elOrder.setAttribute("id",id);
elOrder.setAttribute("costn,getFormattedCost());
ElementelDate=newElementC'date").addcontent(date);
elOrder.addContent(elDate);
ElementelItems=newElement("iterns");
for(lterator<ltem>iter=
items.iteratorC);iter.hasNextO;){
elItems.addContent(iter.next().toXml());
)
elorder.addcontent(elltems);
returnelOrder;
)
在这里可以看到用JDOM创建元素、使用属性和添加元素内容有多么简朴。递
归地调用复合JavaBean的toXml。方法是为了取得它们子图
的Element表达。例如,items元素的内容是通过调用Order聚合的每
个Item对象上的toXml()得到的。
一旦所有的JavaBean都实现了toXml()方法,那么把任意对象图序列化成
XML文档并返回给Ajax客户机就简朴了,如清单2所示。
清单2.从JDOM元素生成XML响应
publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)
throwsjava.io.lOException,ServletException{
Stringcustld=req.getParameter("username");
Customercustomer=getCustomer(custld);
ElementresponseElem=customer.toxml();
DocumentresponseDoc=newDocument(responseElem);
res.setContentType(napplication/xml");
newXMLOutputter().output(responseDoc,res.getwriter());
)
JDOM再次把工作变得非常简朴。只需要在对象图返回的XML元素外面包装一
个Document,然后用XMLOutputter把文档写入servlet响应即可。清单
3显示了用这种方式生成的XML示例,用
JDOMFormat.getPrettyFormat()对XMLOutputter进行初始化,格式化
得非常好。在这个示例中,顾客只做了一个订单,包含两个商品。
清单3.代表顾客的XML文档
<?xmlversion="1.0"encoding="UTF-8"?>
<customerusername="jimmy66u>
<realname>JamesHyrax</realname>
<orders>
<orderid="o-11123"cost="$349.98">
<date>08-26-2023</date>
<items>
<itemid="i-55768n>
<name>Oolong512MBCFcard</name>
<description>512MegabyteType1CompactFlashcard.
ManufacturedbyOolongindustries</description>
<price>$49.99</price>
</item>
<1ternid="i-74491n>
<name>FujakSuperpix72camera</name>
<description>7.2Megapixeldigitalcamerafeaturingsix
shootingmodesand3xopticalzoom,siIver.〈/description〉
<price>$299.99</price>
</item>
</items>
</order>
</orders>
</customer>
自行序列化的局限性
有趣的是,清单3中的代码展示了让JavaBean把自己序列化为XML的一个
重要局限性。假设要用这个文档表达顾客的订单历史视图。在这种情况下,不
太也许要显示每个历史订单中每个商品的完整说明,或者告诉顾客他或她自己
的姓名。但是假如应用程序有一个Productsearch类,它就是
以Itembean列表的形式返回搜索结果,那么在Item的XML表达中包
含说明也许会有帮助。并且,Item类上代表当前库存水平的额外字段,在产
品搜索视图中也许就是需要显示的有用信息。但是,不管当前的库存水平是否
与当前情况相关(比如对顾客的订单历史来说),这个字段都会从包
含Item的任何对象图中序列化出来。
从设计的角度来看,这是数据模型与视图生成耦合的经典问题。每个bean只
能用一种途径序列化自己,一成不变的方式意味着Ajax交互最终要互换它们
不需要互换的数据,因此导致客户端代码要从文档中找到需要的信息更加困难,
并且也会增长带宽消耗和客户端的XML解析时间。这种耦合的另一个后果就是
XML的语法不能脱离Java类独立变化。例如,对顾客文档的方案做修改,也
许会影响多个Java类,导致它们也不得不做修改和重新编译。
我稍后会解决这些问题,但是一方面来看一个对自行序列化方式的可伸缩性问
题的解决方案:XML绑定框架。
XML绑定框架
近些年来,已经开发了多个JavaAPI来简化XML文档到Java对象图的绑定
过程。多数都提供了XML编排和拆解;也就是说,它们可以在Java对象图和
XML之间执行双向会话。这些框架封装了XML解决的所有工作,这意味着应用
程序代码只需要解决普通的Java类。它们还希望提供有用的辅助功能,例如
文档验证。笼统来说,这些框架采用了两种不同的方式:代码生成和对象到XML
映射。我将分别解释这两种方式。
代码生成方式
使用代码生成的框架涉及XMLBeans、JAXB、Zeus和JBindoCastor也能使用
这项技术。这类框架的起点是描述文档数据类型的XML方案。使用框架提供的
工具,就可以生成代表这些方案定义类型的Java类。最后,用这些生成的类
编写应用程序,表达自己的模型数据,并通过框架提供的一些辅助机制把数据
序列化成XMLo
假如应用程序要使用大型XML语法,那么代码生成方式是个很好的方法。在数
十个类上编写定制XML序列化代码的可伸缩性问题由此消除。另一方面,也不
再需要定义自己的JavaBean。框架生成的Java类通常非常符合XML的结构,
所以对它们进行编码很难。并且,生成的类变成哑数据容器,由于一般不能向
它们添加行为。一般来说,在应用程序代码中要做些妥协,才干很好地解决方
案生成的类型。另一个缺陷是假如修改方案,会导致生成的类也要修改,所以
也就会对围绕它们编写的代码带来相应的影响。
这种类型的XML绑定框架在数据拆解时最有用(例如,使用XML文档并把它
们转化成Java对象)。除非拥有大型数据模型并且有也许从生成的类中获益,
否则基于代码生成的框架对于Ajax应用程序来说也许有很大的杀伤力。
映射方式
采用映射方式的框架涉及Castor和ApacheCommonsBetwixt0映射通常是比
代码生成更灵活和更轻量的解决方案。一方面,可以像通常同样编写JavaBean,
涉及任何行为以及任何自己喜欢的方便的方法。然后,在运营时,调用框架中
基于内省的编排器,并根据对象成员的类型、名称和值生成XML文档。通过定
义类的映射文献,可以覆盖默认的绑定策略,并就类在X
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 课程设计剪切板增强
- 2024上海房地产买卖合同
- 2024年厂房租赁合同范本
- 精密机械与仪器课程设计
- 华中师范大学《马克思主义经典著作》2021-2022学年第一学期期末试卷
- 2024自费出版图书的合同范本
- 华中师范大学《复调基础》2021-2022学年第一学期期末试卷
- 华中师范大学《地图学》2021-2022学年第一学期期末试卷
- 闹铃装置单片机课程设计
- 防水生产课程设计
- T-CRHA 046-2024 标准手术体位安置技术规范
- 阳光食品APP培训考核题库(含答案)食品生产企业端
- 中考数学专题训练一元二次方程(50道计算题)(无答案)
- 村卫生室静脉输液规范和安全管理制度
- 人教版高中化学选择性必修1第1章化学反应的热效应测试含答案
- 超声技能操作评分表
- 分子筛催化剂的研究进展
- 河南中职语文-基础模块上册-(高教版)第一单元测试题含答案
- 湖北省宜都市马家台矿区电石用、建筑石料用、水泥用石灰岩矿矿产资源开发利用与生态复绿方案
- DLT 817 立式水轮发电机检修规程
- 工程设计管理岗位面试问题
评论
0/150
提交评论