构建动态Java程序.docx
- 文档编号:8204628
- 上传时间:2023-01-29
- 格式:DOCX
- 页数:11
- 大小:41.70KB
构建动态Java程序.docx
《构建动态Java程序.docx》由会员分享,可在线阅读,更多相关《构建动态Java程序.docx(11页珍藏版)》请在冰豆网上搜索。
构建动态Java程序
面向Java程序员的Ajax:
构建动态Java程序
2005-10-3109:
55作者:
PhilipMcCarthy出处:
IBMDeveloperwork责任编辑:
方舟
Ajax(即异步JavaScript和XML)是一种Web应用程序开发的手段,它采用客户端脚本与Web服务器交换数据。
所以,不必采用会中断交互的完整页面刷新,就可以动态地更新Web页面。
使用Ajax,可以创建更加丰富、更加动态的Web应用程序用户界面,其即时性与可用性甚至能够接近本机桌面应用程序。
Ajax不是一项技术,而更像是一个模式——一种识别和描述有用的设计技术的方式。
Ajax是新颖的,因为许多开发人员才刚刚开始知道它,但是所有实现Ajax应用程序的组件都已经存在若干年了。
它目前受到重视是因为在2004和2005年出现了一些基于Ajax技术的非常棒的动态WebUI,最著名的就是Google的GMail和Maps应用程序,以及照片共享站点Flickr。
这些用户界面具有足够的开创性,有些开发人员称之为“Web2.0”,因此对Ajax应用程序的兴趣飞速上升。
在这个系列中,我将提供使用Ajax开发应用程序需要的全部工具。
在第一篇文章中,我将解释Ajax背后的概念,演示为基于Java的Web应用程序创建Ajax界面的基本步骤。
我将使用代码示例演示让Ajax应用程序如此动态的服务器端Java代码和客户端JavaScript。
最后,我将指出Ajax方式的一些不足,以及在创建Ajax应用程序时应当考虑的一些更广的可用性和访问性问题。
更好的购物车
可以用Ajax增强传统的Web应用程序,通过消除页面装入从而简化交互。
为了演示这一点,我采用一个简单的购物车示例,在向里面添加项目时,它会动态更新。
这项技术如果整合到在线商店,那么用户可以持续地浏览和向购物车中添加项目,而不必在每次点击之后都等候完整的页面更新。
虽然这篇文章中的有些代码特定于购物车示例,但是演示的技术可以应用于任何Ajax应用程序。
清单1显示了购物车示例使用的有关HTML代码,整篇文章中都会使用这个HTML。
清单1.购物车示例的有关片断
<!
--Tableofproductsfromstore'scatalog,onerowperitem-->
<th>Name</th><th>Description</th><th>Price</th><th></th>
...
<tr>
<!
--Itemdetails-->
<td>Hat</td><td>Stylishbowlerhat</td><td>$19.99</td>
<td>
<!
--ClickbuttontoadditemtocartviaAjaxrequest-->
<buttononclick="addToCart('hat001')">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写入HttpServletResponse。
回到客户端时,现在调用注册在XMLHttpRequest上的回调函数,处理服务器返回的XML文档。
最后,根据服务器返回的数据,用JavaScript操纵页面的HTMLDOM,把用户界面更新。
图1是Ajax往返过程的顺序图。
图1.Ajax往返过程
现在您对Ajax往返过程有了一个高层面的认识。
下面我将放大其中的每一步骤,进行更详细的观察。
如果过程中迷了路,请回头看图1——由于Ajax方式的异步性质,所以顺序并非十分简单。
分派XMLHttpRequest
我将从Ajax序列的起点开始:
创建和分派来自浏览器的XMLHttpRequest。
不幸的是,不同的浏览器创建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(e1){
//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的newXMLHttpRequest()函数得到XMLHttpRequest对象。
接下来,它注册一个回调函数,用来接收服务器响应(我稍后再详细解释这一步;请参阅清单6)。
因为请求会修改服务器上的状态,所以我将用HTTPPOST做这个工作。
通过POST发送数据要求三个步骤。
第一,需要打开与要通信的服务器资源的POST连接——在这个示例中,服务器资源是一个映射到URLcart.do的servlet。
然后,我在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又被写入ServletResponse。
重要的是把响应的内容类型设置为application/xml,否则XMLHttpRequest不会把响应内容解析成XMLDOM。
清单4.处理Ajax请求的servlet代码
publicvoiddoPost(HttpServletRequestreq,HttpServletResponseres)
throwsjava.io.IOException{
Cartcart=getCartFromSession(req);
Stringaction=req.getParameter("action");
Stringitem=req.getParameter("item");
if((action!
=null)&&(item!
=null)){
//AddorremoveitemsfromtheCart
if("add".equals(action)){
cart.addItem(item);
}elseif("remove".equals(action)){
cart.removeItems(item);
}
}
//SerializetheCart'sstatetoXML
StringcartXml=cart.toXml();
//WriteXMLtoresponse.
res.setContentType("application/xml");
res.getWriter().write(cartXml);
}
清单5显示了Cart.toXml()方法生成的示例XML。
它很简单。
请注意cart元素的generated属性,它是System.currentTimeMillis()生成的一个时间戳。
清单5.Cart对象的XML序列化示例
<?
xmlversion="1.0"?
>
<cartgenerated="1123969988414"total="$171.95">
<itemcode="hat001">
<name>Hat</name>
<quantity>2</quantity>
</item>
<itemcode="cha001">
<name>Chair</name>
<quantity>1</quantity>
</item>
<itemcode="dog001">
<name>Dog</name>
<quantity>1</quantity>
</item>
</cart>
如果查看应用程序源代码(可以从下载一节得到)中的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(OK)的码都是错误。
如果服务器发送重定向响应(例如301或302),浏览器会透明地进行重定向并从新的位置获取资源;XMLHttpRequest看不到重定向状态码。
而且,浏览器会自动添加Cache-Control:
no-cache头到所有XMLHttpRequest,这样客户代码永远也不用处理304(未经修改)服务器响应。
关于getReadyStateHandler()
getReadyStateHandler()是段相对复杂的代码,特别是如果您不习惯阅读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.getElementsByTagName("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.getElementsByTagName("item");
for(varI=0;I<items.length;I++){
varitem=items[I];
//Extractthetextnodesfromthenameandquantityelements
varname=item.getElementsByTagName("name")[0].firstChild.nodeValue;
v
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 构建 动态 Java 程序