??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美日韩精品在线观看,国产精品网址,国产在线精品一区二区不卡了 http://www.aygfsteel.com/caizh2009/category/39395.html与大家共同成?/description>zh-cnFri, 05 Feb 2010 10:10:20 GMTFri, 05 Feb 2010 10:10:20 GMT60Ajax 单示?/title><link>http://www.aygfsteel.com/caizh2009/articles/311067.html</link><dc:creator>菜毛毛</dc:creator><author>菜毛毛</author><pubDate>Thu, 28 Jan 2010 05:36:00 GMT</pubDate><guid>http://www.aygfsteel.com/caizh2009/articles/311067.html</guid><wfw:comment>http://www.aygfsteel.com/caizh2009/comments/311067.html</wfw:comment><comments>http://www.aygfsteel.com/caizh2009/articles/311067.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/caizh2009/comments/commentRss/311067.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/caizh2009/services/trackbacks/311067.html</trackback:ping><description><![CDATA[<p><html xmlns="http://www.w3.org/1999/xhtml" ><br /> <head><br />    <title>xmlhttprequest ajax demo</title><br />     <script type ="text/javascript" language ="javascript" ><br />         var req; //定义变量Q用来创建xmlhttprequest对象<br />         function creatReq() // 创徏xmlhttprequest,ajax开?br />         {<br />             var url="ajaxServer.aspx"; //要请求的服务端地址<br />             if(window.XMLHttpRequest) //非IE览器及IE7(7.0及以上版?Q用xmlhttprequest对象创徏<br />             {<br />                 req=new XMLHttpRequest();<br />             }<br />             else if(window.ActiveXObject) //IE(6.0及以下版?览器用activexobject对象创徏,如果用户览器禁用了ActiveX,可能会失?            {<br />                 req=new ActiveXObject("Microsoft.XMLHttp");<br />             }<br />             <br />             if(req) //成功创徏xmlhttprequest<br />             {<br />                 req.open("GET",url,true); //与服务端建立q接(h方式post或getQ地址,true表示异步)<br />                 req.onreadystatechange = callback; //指定回调函数<br />                 req.send(null); //发送请?br />             }<br />         }<br />         <br />         function callback() //回调函数Q对服务端的响应处理Q监视response状?br />         {<br />             if(req.readystate==4) //h状态ؓ4表示成功<br />             {<br />                 if(req.status==200) //http状?00表示OK<br />                 {<br />                     Dispaly(); //所有状态成功,执行此函敎ͼ昄数据<br />                 }<br />                 else //httpq回状态失?br />                 {<br />                     alert("服务端返回状? + req.statusText);<br />                 }<br />             }<br />             else //h状态还没有成功Q页面等?br />             {<br />                 document .getElementById ("myTime").innerHTML ="数据加蝲?;<br />             }<br />         }<br />         <br />         function Dispaly() //接受服务端返回的数据Q对其进行显C?br />         {<br />             document .getElementById ("myTime").innerHTML =req.responseText;<br />         }<br />         <br />     </script><br /> </head><br /> <body><br />     <div id="myTime"></div><br />         <br />     <input id="Button1" type="button" value="Get Time"  onclick ="creatReq();"/><br /> </body><br /> </html></p> <p><br /> 对于Ajax需要注意执??序 </p> <p>对于input cd为text?动作?onChange() onPropertyChange() 后者比前者的反应 更加的敏感,有可能onChange()不会随着里面的改变而改变,但是onPropertyChange()肯定会随着value的?改变而改变?</p> <p>对于q回的|要把l果写在最后的条g都符合的情况下,是注意函数的位|?</p> <p>操作xml的时?用到的方?和以前操作xml的是一LQ如getElementsByTagName(),q有.firstChild.data,nodeValue. </p> <p>Ajax执行的顺序是open,onreadystatechange,send 都是Z的形式传输?/p> <p>对于servlet里面 注意 都是 用流的Ş式进?传输和取倹{resp.setContentType()Q里面得相应的设|方式?/p> <p> </p> <p>本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/zuowangxi/archive/2009/12/30/5104036.aspx</p> <img src ="http://www.aygfsteel.com/caizh2009/aggbug/311067.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/caizh2009/" target="_blank">菜毛毛</a> 2010-01-28 13:36 <a href="http://www.aygfsteel.com/caizh2009/articles/311067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Z HTTP 长连接的“服务器推”技?/title><link>http://www.aygfsteel.com/caizh2009/articles/279721.html</link><dc:creator>菜毛毛</dc:creator><author>菜毛毛</author><pubDate>Tue, 02 Jun 2009 15:46:00 GMT</pubDate><guid>http://www.aygfsteel.com/caizh2009/articles/279721.html</guid><wfw:comment>http://www.aygfsteel.com/caizh2009/comments/279721.html</wfw:comment><comments>http://www.aygfsteel.com/caizh2009/articles/279721.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/caizh2009/comments/commentRss/279721.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/caizh2009/services/trackbacks/279721.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="100%"> <h1>CometQ基?HTTP 长连接的“服务器推”技?/h1> <img class="display-img" height="6" alt="" src="http://www.ibm.com/i/c.gif" width="1" /></td> <td class="no-print" width="192"><img height="18" alt="developerWorks" src="http://www.ibm.com/developerworks/i/dw.gif" width="192" /></td> </tr> </tbody> </table> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr valign="top"> <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td> <td width="100%"> <table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0"> <tbody> <tr> <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td> <td> <table cellspacing="0" cellpadding="0" width="150" border="0"> <tbody> <tr> <td class="v14-header-1-small">文档选项</td> </tr> </tbody> </table> <table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td class="no-padding" width="150"> <table cellspacing="0" cellpadding="0" width="143" border="0"> <script language="JavaScript" type="text/javascript"> <!-- document.write('<tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" width="8" height="1" alt="" /></td><td width="16"><img alt="打印机的版面设|成横向打印模式" height="16" src="http://www.ibm.com/i/v14/icons/printer.gif" width="16" vspace="3" /></td><td width="122"><p><strong><a class="smallplainlink" href="javascript:print()">打印本页</a></strong></p></td></tr>'); //--> </script> <tbody> <tr valign="top"> <td width="8"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /></td> <td width="16"><img height="16" alt="打印机的版面设|成横向打印模式" src="http://www.ibm.com/i/v14/icons/printer.gif" width="16" vspace="3" /></td> <td width="122"> <p><strong><a class="smallplainlink" href="javascript:print()" cmimpressionsent="1">打印本页</a></strong></p> </td> </tr> <noscript></noscript> <form name="email" action="https://www.ibm.com/developerworks/secure/email-it.jsp" cm1="1"> <input type="hidden" value="很多应用譬如监控、即旉信、即时报Ll都需要将后台发生的变化实时传送到客户端而无dL不停地刷新、发送请求。本文首先介l、比较了常用?#8220;服务器推”ҎQ着重介l了 Comet Q?使用 HTTP 长连接、无L览器安装插g的两U?#8220;服务器推”ҎQ基?AJAX 的长轮询方式Q基?iframe ?htmlfile 的流方式。最后分析了开?Comet 应用需要注意的一些问题,以及如何借助开源的 Comet 框架Qpushlet 构徏自己?#8220;服务器推”应用? name="body" cM3 cm1="1" cm2="0" /><input type="hidden" value="CometQ基?HTTP 长连接的“服务器推”技? name="subject" cM3 cm1="1" cm2="1" /><input type="hidden" value="cn" name="lang" cM3 cm1="1" cm2="2" /> <script language="JavaScript" type="text/javascript"> <!-- document.write('<tr valign="top"><td width="8"><img src="http://www.ibm.com/i/c.gif" width="8" height="1" alt="" /></td><td width="16"><img src="http://www.ibm.com/i/v14/icons/em.gif" height="16" width="16" vspace="3" alt="此作为电子邮件发? /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><strong>此作为电子邮件发?/strong></a></p></td></tr>'); //--> </script> <tr valign="top"> <td width="8"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="8" /></td> <td width="16"><img height="16" alt="此作为电子邮件发? src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" /></td> <td width="122"> <p><a class="smallplainlink" href="javascript:document.email.submit();" cmimpressionsent="1"><strong>此作为电子邮件发?/strong></a></p> </td> </tr> <noscript></noscript> </form> </tbody> </table> </td> </tr> </tbody> </table> <!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--><br /> </td> </tr> </tbody> </table> <p>U别Q?中</p> <p><a cmimpressionsent="1">??/a> (<a href="mailto:zhouting@cn.ibm.com?subject=Comet:基于 HTTP 长连接的“服务器推”技术" cmimpressionsent="1">zhouting@cn.ibm.com</a>), 软g工程? IBM 中国软g开发技术实验室<br /> </p> <p>2007 q?8 ?31 ?/p> <blockquote>很多应用譬如监控、即旉信、即时报Ll都需要将后台发生的变化实时传送到客户端而无dL不停地刷新、发送请求。本文首先介l、比较了常用?#8220;服务器推”ҎQ着重介l了 Comet Q?使用 HTTP 长连接、无L览器安装插g的两U?#8220;服务器推”ҎQ基?AJAX 的长轮询方式Q基?iframe ?htmlfile 的流方式。最后分析了开?Comet 应用需要注意的一些问题,以及如何借助开源的 Comet 框架Qpushlet 构徏自己?#8220;服务器推”应用?/blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--> <p><a name="N10042"><span id="wmqeeuq" class="atitle">“服务器推”技术的应用</span></a></p> <table cellspacing="0" cellpadding="0" width="40%" align="right" border="0"> <tbody> <tr> <td width="10"><img height="1" alt="" src="http://www.ibm.com/i/c.gif" width="10" /></td> <td> <table cellspacing="0" cellpadding="5" width="100%" border="1"> <tbody> <tr> <td bgcolor="#eeeeee"> <p>误?<a cmimpressionsent="1">Ajax 技术资源中?/a>Q这是有?Ajax ~程模型信息的一站式中心Q包括很多文档、教E、论坛、blog、wiki 和新闅RQ?Ajax 的新信息都能在这里找到? <table cellspacing="0" cellpadding="0" width="80%" border="0"> <tbody> <tr> <td colspan="2"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="1" border="0" /> </td> </tr> <tr valign="top" align="center"> <td colspan="2"><img alt="" src="http://www.ibm.com/i/c.gif" width="5" border="0" /> </td> <td width="21"><a cmimpressionsent="1"><img height="16" alt="RSS" src="http://www.ibm.com/i/v14/buttons/feed.gif" width="16" border="0" /> </a></td> <td><a cmimpressionsent="1">订阅 Ajax 相关文章和教E的 RSS 提要</a> </td> </tr> <tr> <td colspan="2"><img height="5" alt="" src="http://www.ibm.com/i/c.gif" width="1" border="0" /> </td> </tr> </tbody> </table> </p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p>传统模式?Web pȝ以客L发出h、服务器端响应的方式工作。这U方式ƈ不能满很多现实应用的需求,譬如Q?/p> <ul> <li>监控pȝQ后台硬件热插拔、LED、温度、电压发生变化; <li>x通信pȝQ其它用L录、发送信息; <li>x报hpȝQ后台数据库内容发生变化Q?</li> </ul> <p>q些应用都需要服务器能实时地更新的信息传送到客户端,而无dL发出h?#8220;服务器推”技术在现实应用中有一些解x案,本文这些解x案分Zc:一c需要在览器端安装插gQ基于套接口传送信息,或是使用 RMI、CORBA q行q程调用Q而另一cd无须览器安装Q何插件、基?HTTP 长连接?/p> <p>?#8220;服务器推”应用?Web E序中,首先考虑的是如何在功能有限的览器端接收、处理信息:</p> <ol> <li>客户端如何接收、处理信息,是否需要用套接口或是使用q程调用。客L呈现l用L?HTML 面q是 Java applet ?Flash H口。如果用套接口和远E调用,怎么?JavaScript l合修改 HTML 的显C? <li>客户与服务器端通信的信息格式,采取怎样的出错处理机制? <li>客户端是否需要支持不同类型的览器如 IE、FirefoxQ是否需要同时支?Windows ?Linux q_?</li> </ol> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /> </td> <td valign="top" align="right"><a class="fbox" cmimpressionsent="1"><strong>回页?/strong></a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p><a name="N100BD"><span id="wmqeeuq" class="atitle">Z客户端套接口?#8220;服务器推”技?/span></a></p> <p><a name="N100C3"><span id="wmqeeuq" class="smalltitle">Flash XMLSocket</span></a></p> <p>如果 Web 应用的用h受应用只有在安装?Flash 播放器才能正常运行, 那么使用 Flash ?XMLSocket 也是一个可行的Ҏ?/p> <p>q种Ҏ实现的基是:</p> <ol> <li>Flash 提供?XMLSocket cR? <li>JavaScript ?Flash 的紧密结合:?JavaScript 可以直接调用 Flash E序提供的接口?</li> </ol> <p>具体实现ҎQ在 HTML 面中内嵌入一个用了 XMLSocket cȝ Flash E序。JavaScript 通过调用?Flash E序提供的套接口接口与服务器端的套接口进行通信。JavaScript 在收到服务器端以 XML 格式传送的信息后可以很Ҏ地控?HTML 面的内ҎC?/p> <p>关于如何L建充当了 JavaScript ?Flash XMLSocket 桥梁?Flash E序Q以及如何在 JavaScript 里调?Flash 提供的接口,我们可以参?AFLAXQAsynchronous Flash and XMLQ项目提供的 Socket Demo 以及 SocketJSQ请参见 <a cmimpressionsent="1">参考资?/a>Q?/p> <p>Javascript ?Flash 的紧密结合,极大增强了客L的处理能力。从 Flash 播放?V7.0.19 开始,已经取消?XMLSocket 的端口必d?1023 的限制。Linux q_也支?Flash XMLSocket Ҏ。但此方案的~点在于Q?/p> <ol> <li>客户端必d?Flash 播放器; <li>因ؓ XMLSocket 没有 HTTP 隧道功能QXMLSocket cM能自动穿q防火墙Q? <li>因ؓ是用套接口Q需要设|一个通信端口Q防火墙、代理服务器也可能对?HTTP 通道端口q行限制Q?</li> </ol> <p>不过q种Ҏ在一些网l聊天室Q网l互动游戏中已得到广泛用?/p> <p><a name="N100F3"><span id="wmqeeuq" class="smalltitle">Java Applet 套接?</span></a></p> <p>在客L使用 Java AppletQ通过 <code>java.net.Socket</code> ?<code>java.net.DatagramSocket</code> ?<code>java.net.MulticastSocket</code> 建立与服务器端的套接口连接,从而实?#8220;服务器推”?/p> <p>q种Ҏ最大的不在于 Java applet 在收到服务器端返回的信息后,无法通过 JavaScript L?HTML 面的内宏V?</p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /> </td> <td valign="top" align="right"><a class="fbox" cmimpressionsent="1"><strong>回页?/strong></a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p><a name="N1010A"><span id="wmqeeuq" class="atitle">Z HTTP 长连接的“服务器推”技?/span></a></p> <p><a name="N10110"><span id="wmqeeuq" class="smalltitle">Comet ?/span></a></p> <p>览器作?Web 应用的前収ͼ自n的处理功能比较有限。浏览器的发展需要客L升软gQ同时由于客L览器Y件的多样性,在某U意义上Q也影响了浏览器新技术的推广。在 Web 应用中,览器的主要工作是发送请求、解析服务器q回的信息以不同的风格显C。AJAX 是浏览器技术发展的成果Q通过在浏览器端发送异步请求,提高了单用户操作的响应性。但 Web 本质上是一个多用户的系l,对Q何用h_可以认ؓ服务器是另外一个用戗现?AJAX 技术的发展q不能解军_一个多用户?Web 应用中,更新的信息实时传送给客户端,从而用户可能在“q时”的信息下q行操作。?AJAX 的应用又使后台数据更新更加频J成为可能?/p> <br /> <a name="fig001"><strong>?1. 传统?Web 应用模型与基?AJAX 的模型之比较</strong></a><br /> <img alt="?1. 传统?Web 应用模型与基?AJAX 的模型之比较" src="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/fig001.jpg" /> <br /> <p>“服务器推”是一U很早就存在的技术,以前在实C主要是通过客户端的套接口,或是服务器端的远E调用。因为浏览器技术的发展比较~慢Q没有ؓ“服务器推”的实现提供很好的支持Q在U浏览器的应用中很难有一个完善的Ҏd?#8220;服务器推”q用于商业程序。最q几q_因ؓ AJAX 技术的普及Q以及把 IFrame 嵌在“htmlfile“?ActiveX lg中可以解?IE 的加载显C问题,一些受Ƣ迎的应用如 meeboQgmail+gtalk 在实C使用了这些新技术;同时“服务器推”在现实应用中实存在很多需求。因些原因,ZU浏览器?#8220;服务器推”技术开始受到较多关注,Alex RussellQDojo Toolkit 的项?LeadQ称q种Z HTTP 长连接、无d览器端安装插g?#8220;服务器推”技术ؓ“Comet”。目前已l出C一些成熟的 Comet 应用以及各种开源框Ӟ一?Web 服务器如 Jetty 也在为支持大量ƈ发的长连接进行了很多改进。关?Comet 技术最新的发展状况请参考关?Comet ?wiki?/p> <p>下面介l两U?Comet 应用的实现模型?/p> <p><a name="N1012A"><span id="wmqeeuq" class="smalltitle">Z AJAX 的长轮询Qlong-pollingQ方?/span></a></p> <p>?<a cmimpressionsent="1">?1</a> 所C,AJAX 的出C?JavaScript 可以调用 XMLHttpRequest 对象发出 HTTP hQJavaScript 响应处理函数Ҏ服务器返回的信息?HTML 面的显C行更新。?AJAX 实现“服务器推”与传l的 AJAX 应用不同之处在于Q?/p> <ol> <li>服务器端会阻塞请求直到有数据传递或时才返回? <li>客户?JavaScript 响应处理函数会在处理完服务器q回的信息后Q再ơ发求,重新建立q接? <li>当客L处理接收的数据、重新徏立连接时Q服务器端可能有新的数据到达Q这些信息会被服务器端保存直到客L重新建立q接Q客L会一ơ把当前服务器端所有的信息取回?</li> </ol> <br /> <a name="fig002"><strong>?2. Z长轮询的服务器推模型</strong></a><br /> <img alt="?2. Z长轮询的服务器推模型" src="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/fig002.jpg" /> <br /> <p>一些应用及CZ?“Meebo”, “Pushlet Chat” 都采用了q种长轮询的方式。相对于“轮询”QpollQ,q种长轮询方式也可以UCؓ“?#8221;QpullQ。因U方案基?AJAXQ具有以下一些优点:h异步发出Q无d装插ӞIE、Mozilla FireFox 都支?AJAX?/p> <p>在这U长轮询方式下,客户端是?XMLHttpRequest ?readystate ?4Q即数据传输l束Q时调用回调函数Q进行信息处理。当 readystate ?4 Ӟ数据传输l束Q连接已l关闭。Mozilla Firefox 提供了对 Streaming AJAX 的支持, ?readystate ?3 Ӟ数据仍在传输中)Q客L可以d数据Q从而无d闭连接,pd处理服务器端q回的信息。IE ?readystate ?3 Ӟ不能d服务器返回的数据Q目?IE 不支持基?Streaming AJAX?/p> <p><a name="N10154"><span id="wmqeeuq" class="smalltitle">Z Iframe ?htmlfile 的流QstreamingQ方?/span></a></p> <p>iframe 是很早就存在的一U?HTML 标记Q?通过?HTML 面里嵌入一个隐蔵Q然后将q个隐蔵帧的 SRC 属性设为对一个长q接的请求,服务器端p源源不断地往客户端输入数据?/p> <br /> <a name="fig003"><strong>?3. Z方式的服务器推模型</strong></a><br /> <img alt="?3. Z方式的服务器推模型" src="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/fig003.jpg" /> <br /> <p>上节提到?AJAX Ҏ是在 JavaScript 里处?XMLHttpRequest 从服务器取回的数据,然后 Javascript 可以很方便的L?HTML 面的显C。同L思\用在 iframe Ҏ的客LQiframe 服务器端q不q回直接昄在页面的数据Q而是q回对客L Javascript 函数的调用,?#8220;<code><script type="text/javascript">js_func(“data from server ”)</script></code>”。服务器端将q回的数据作为客L JavaScript 函数的参C递;客户端浏览器?Javascript 引擎在收到服务器q回?JavaScript 调用时就会去执行代码?/p> <p>?<a cmimpressionsent="1">?3</a> 可以看到Q每ơ数据传送不会关闭连接,q接只会在通信出现错误Ӟ或是q接重徏时关闭(一些防火墙常被讄Z弃过长的q接Q?服务器端可以讄一个超时时_ 时后通知客户端重新徏立连接,q关闭原来的q接Q?/p> <p>使用 iframe h一个长q接有一个很明显的不之处:IE、Morzilla Firefox 下端的进度栏都会昄加蝲没有完成Q而且 IE 上方的图标会不停的{动,表示加蝲正在q行。Google 的天才们使用一个称?#8220;htmlfile”?ActiveX 解决了在 IE 中的加蝲昄问题Qƈ这U方法用C gmail+gtalk 产品中。Alex Russell ?“What else is burried down in the depth's of Google's amazing JavaScript?”文章中介l了q种Ҏ。Zeitoun |站提供?comet-iframe.tar.gzQ封装了一个基?iframe ?htmlfile ?JavaScript comet 对象Q支?IE、Mozilla Firefox 览器,可以作ؓ参考。(请参?<a cmimpressionsent="1">参考资?/a>Q?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /> </td> <td valign="top" align="right"><a class="fbox" cmimpressionsent="1"><strong>回页?/strong></a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p><a name="N1017D"><span id="wmqeeuq" class="atitle">使用 Comet 模型开发自q应用</span></a></p> <p>上面介绍了两U基?HTTP 长连接的“服务器推”架构Q更多描qC客户端处理长q接的技术。对于一个实际的应用而言Q系l的E_性和性能是非帔R要的。将 HTTP 长连接用于实际应用,很多l节需要考虑?/p> <p><a name="N10186"><span id="wmqeeuq" class="smalltitle">不要在同一客户端同时用超q两个的 HTTP 长连?/span></a></p> <p>我们使用 IE 下蝲文g时会有这L体验Q从同一?Web 服务器下载文Ӟ最多只能有两个文g同时被下载。第三个文g的下载会被阻塞,直到前面下蝲的文件下载完毕。这是因?HTTP 1.1 规范中规定,客户端不应该与服务器端徏立超q两个的 HTTP q接Q?新的q接会被d。?IE 在实C严格遵守了这U规定?/p> <p>HTTP 1.1 对两个长q接的限Ӟ会对使用了长q接?Web 应用带来如下现象Q在客户端如果打开过两个?IE H口去访问同一个用了长连接的 Web 服务器,W三?IE H口?HTTP h被前两个H口的长q接d?/p> <p>所以在开发长q接的应用时Q?必须注意在用了多个 frame 的页面中Q不要ؓ每个 frame 的页面都建立一?HTTP 长连接,q样会阻塞其它的 HTTP hQ在设计上考虑让多?frame 的更新共用一个长q接?/p> <p><a name="N10194"><span id="wmqeeuq" class="smalltitle">服务器端的性能和可扩展?/span></a></p> <p>一?Web 服务器会为每个连接创Z个线E,如果在大型的商业应用中?CometQ服务器端需要维护大量ƈ发的长连接。在q种应用背景下,服务器端需要考虑负蝲均衡和集技术;或是在服务器端ؓ长连接作一些改q?/p> <p>应用和技术的发展L带来新的需求,从而推动新技术的发展。HTTP 1.1 ?1.0 规范有一个很大的不同Q?.0 规范下服务器在处理完每个 Get/Post h后会关闭套接口连接; ?1.1 规范下服务器会保持这个连接,在处理两个请求的间隔旉里,q个q接处于I闲状态?Java 1.4 引入了支持异?IO ?java.nio 包。当q接处于I闲Ӟ个连接分配的U程资源会返q到U程池,可以供新的连接用;当原来处于空闲的q接的客户发出新的请求,会从U程池里分配一个线E资源处理这个请求?q种技术在q接处于I闲的机率较高、ƈ发连接数目很多的场景下对于降低服务器的资源负载非常有效?/p> <p>但是 AJAX 的应用h的出现变得频J,?Comet 则会长时间占用一个连接,上述的服务器模型在新的应用背景下会变得非怽效,U程池里有限的线E数甚至可能会阻塞新的连接。Jetty 6 Web 服务器针?AJAX、Comet 应用的特点进行了很多创新的改q,请参考文?#8220;AJAXQComet and Jetty”Q请参见 <a cmimpressionsent="1">参考资?/a>Q?/p> <p><a name="N101A6"><span id="wmqeeuq" class="smalltitle">控制信息与数据信息用不同的 HTTP q接</span></a></p> <p>使用长连接时Q存在一个很常见的场景:客户端网需要关闭,而服务器端还处在d数据的堵塞状态,客户端需要及旉知服务器端关闭数据q接。服务器在收到关闭请求后首先要从d数据的阻塞状态唤醒,然后释放个客L分配的资源,再关闭连接?/p> <p>所以在设计上,我们需要客户端的控制h和数据请求用不同的 HTTP q接Q才能控制h不会被阻塞?/p> <p>在实CQ如果是Z iframe 方式的长连接,客户端页面需要用两?iframeQ一个是控制帧,用于往服务器端发送控制请求,控制h能很快收到响应,不会被堵塞;一个是昄帧,用于往服务器端发送长q接h。如果是Z AJAX 的长轮询方式Q客L可以异步地发Z?XMLHttpRequest hQ通知服务器端关闭数据q接?/p> <p><a name="N101B4"><span id="wmqeeuq" class="smalltitle">在客户和服务器之间保?#8220;心蟩”信息</span></a></p> <p>在浏览器与服务器之间l持一个长q接会ؓ通信带来一些不定性:因ؓ数据传输是随机的Q客L不知道何时服务器才有数据传送。服务器端需要确保当客户端不再工作时Q释放ؓq个客户端分配的资源Q防止内存泄漏。因此需要一U机制双方知道大家都在正常q行。在实现上:</p> <ol> <li>服务器端在阻塞读时会讄一个时限,时后阻塞读调用会返回,同时发给客户端没有新数据到达的心跳信息。此时如果客L已经关闭Q服务器往通道写数据会出现异常Q服务器端就会及旉放ؓq个客户端分配的资源? <li>如果客户端用的是基?AJAX 的长轮询方式Q服务器端返回数据、关闭连接后Q经q某个时限没有收到客L的再ơ请求,会认为客L不能正常工作Q会释放个客L分配、维护的资源? <li>当服务器处理信息出现异常情况Q需要发送错误信息通知客户端,同时释放资源、关闭连接?</li> </ol> <p><a name="N101C8"><span id="wmqeeuq" class="smalltitle">Pushlet - 开?Comet 框架</span></a></p> <p>Pushlet 是一个开源的 Comet 框架Q在设计上有很多值得借鉴的地方,对于开发轻量?Comet 应用很有参考h倹{?/p> <p><strong>观察者模?/strong> </p> <p>Pushlet 使用了观察者模型:客户端发送请求,订阅感兴的事gQ服务器端ؓ每个客户端分配一个会?ID 作ؓ标记Q事件源会把C生的事g以多播的方式发送到订阅者的事g队列里?/p> <p><strong>客户?JavaScript ?/strong> </p> <p>pushlet 提供了基?AJAX ?JavaScript 库文件用于实现长轮询方式?#8220;服务器推”Q还提供了基?iframe ?JavaScript 库文件用于实现流方式?#8220;服务器推”?/p> <p>JavaScript 库做了很多封装工作:</p> <ol> <li>定义客户端的通信状态:<code>STATE_ERROR</code>?code>STATE_ABORT</code>?code>STATE_NULL</code>?code>STATE_READY</code>?code>STATE_JOINED</code>?code>STATE_LISTENING</code>Q? <li>保存服务器分配的会话 IDQ在建立q接之后的每ơ请求中会附上会?ID 表明w䆾Q? <li>提供?<code>join()</code>?code>leave()</code>?code>subscribe()</code>?<code>unsubsribe()</code>?code>listen()</code> {?API 供页面调用; <li>提供了处理响应的 JavaScript 函数接口 <code>onData()</code>?code>onEvent()</code>… </li> </ol> <p>|页可以很方便地使用q两?JavaScript 库文件封装的 API 与服务器q行通信?/p> <p><strong>客户端与服务器端通信信息格式</strong> </p> <p>pushlet 定义了一套客户与服务器通信的信息格式,使用 XML 格式。定义了客户端发送请求的cdQ?code>join</code>?code>leave</code>?code>subscribe</code>?code>unsubscribe</code>?code>listen</code>?code>refresh</code>Q以及响应的事gcdQ?code>data</code>?code>join_ack</code>?code>listen_ack</code>?code>refresh</code>?code>heartbeat</code>?code>error</code>?code>abort</code>?code>subscribe_ack</code>?code>unsubscribe_ack</code>?</p> <p><strong>服务器端事g队列理</strong> </p> <p>pushlet 在服务器端?Java Servlet 实现Q其数据l构的设计框架仍可适用?PHP、C ~写的后台客L?/p> <p>Pushlet 支持客户端自己选择使用、拉Q长轮询Q、轮询方式。服务器端根据客户选择的方式在d事g队列QfetchEventsQ时q行不同的处理?#8220;轮询”模式?<code>fetchEvents()</code> 会马上返回?#8221;?#8220;?#8221;?#8220;模式使用d的方式读事gQ如果超Ӟ会发l客L发送一个没有新信息收到?#8220;heartbeat“事gQ如果是“?#8221;模式Q会?#8220;heartbeat”?#8220;refresh”事g一起传l客LQ通知客户端重新发求、徏立连接?/p> <p><strong>客户服务器之间的会话理</strong> </p> <p>服务端在客户端发?<code>join</code> hӞ会ؓ客户端分配一个会?IDQ?q传l客LQ然后客L通过此会?ID 标明w䆾发出 <code>subscribe</code> ?<code>listen</code> h。服务器端会为每个会话维护一个订阅的主题集合、事仉列?/p> <p>服务器端的事件源会把C生的事g以多播的方式发送到每个会话Q即订阅者)的事仉列里?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td><img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /><br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td><img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /><br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="middle"><img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /> </td> <td valign="top" align="right"><a class="fbox" cmimpressionsent="1"><strong>回页?/strong></a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p><a name="N10298"><span id="wmqeeuq" class="atitle">结</span></a></p> <p>本文介绍了如何在现有的技术基上选择合适的Ҏ开发一?#8220;服务器推”的应用,最优的Ҏq是取决于应用需求的本n。相对于传统?Web 应用Q?目前开?Comet 应用q是h一定的挑战性?/p> <p>“服务器推”存在q泛的应用需求,Z?Comet 模型适用于大规模的商业应用,以及方便用户构徏 Comet 应用Q最q几q_无论是服务器q是览器都出现了很多新技术,同时也出C很多开源的 Comet 框架、协议。需求推动技术的发展Q相?Comet 的应用会变得?AJAX 一h及?/p> <br /> <br /> <p><a name="resources"><span id="wmqeeuq" class="atitle">参考资?</span></a></p> <strong>学习</strong><br /> <ul> <li>developerWorks 文章“ <a cmimpressionsent="1">面向 Java 开发h员的 Ajax: 使用 Jetty ?Direct Web Remoting ~写可扩展的 Comet 应用E序</a>”Q受异步服务器端事g驱动?Ajax 应用E序实现较ؓ困难Q本文介l了一U结合?Comet 模式?Jetty 6 Continuations API 的解x法?br /> <br /> <li>“<a cmimpressionsent="1">Comet: Low Latency Data for the Browser</a>”QAlex Russell ?Dojo Toolkit 的项目主和 Dojo Foundation 的主席,他在q篇博客文章中提Z <em>Comet</em> q个术语?br /> <br /> <li>“<a cmimpressionsent="1">What else is burried down in the depth’s of Google’s amazing JavaScript?</a>”QAlex RusselQ?006 q?2 月)QAlex 在这文章里介绍了如何?#8220;htmlfile”ActiveX 控g解决 iframe h长连接时 IE 的加载显C问题?br /> <br /> <li><a cmimpressionsent="1">Comet wiki</a>Q提供了很多开?Comet 框架的链接?br /> <br /> <li><a cmimpressionsent="1">Jetty</a>QJetty 是一U开源的Z标准?Web 服务器,完全使用 Java 语言实现?br /> <br /> <li>“<a cmimpressionsent="1">Ajax, Comet and Jetty</a>”QGreg WilkinsQWebtideQ?006 q?1 月)QWilkins 的这份白皮书讨论了扩?Ajax q接?Jetty 架构Ҏ?br /> <br /> <li><a cmimpressionsent="1">Continuations</a>Q了解更多关?Jetty ?Continuations Ҏ的信息?br /> <br /> <li>“<a cmimpressionsent="1">pushlet</a>”Q开?comet 框架Q用了观察者模型。浏览器端提供了Z AJAX ?iframe ?JavaScript 库,服务器端使用 Java Servlet?br /> <br /> <li>“<a cmimpressionsent="1">How to implement COMET with PHP</a>”Q提供的 comet-iframe.tar.gz 使用 iframe/htmlfile 装了一?JavaScript comet 对象Q支?IE、Mozilla Firefox 览器?br /> <br /> <li>“<a cmimpressionsent="1">AFLAX</a>”QAsynchronous Flash and XMLQ提供了强大?Flash、Javascript 库和很多范例?br /> <br /> <li><a cmimpressionsent="1">developerWorks Ajax 技术资源中?/a>Q能扑ֈ更多关于 Ajax 技术的文章和教E?br /> <br /> <li><a cmimpressionsent="1">developerWorks Web 开发技术专?/a>Q提供了关于 Web 开发和架构斚w的大量文章?br /> <br /> <li><a cmimpressionsent="1">developerWorks Java 技术专?/a>Q提供了关于 Java ~程各个斚w的数癄文章?br /> <br /> <li>览 <a cmimpressionsent="1">技术书?/a>Q查阅有x文所qC题以及其他技术主题的书籍?</li> </ul> <p><br /> <strong>Pushlet - 开?Comet 框架</strong> <br /> Pushlet 是一个开源的 Comet 框架Q在设计上有很多值得借鉴的地方,对于开发轻量?Comet 应用很有参考h倹{?<br /> <br /> <strong>观察者模?/strong> <br /> Pushlet 使用了观察者模型:客户端发送请求,订阅感兴的事gQ服务器端ؓ每个客户端分配一个会?ID 作ؓ标记Q事件源会把C生的事g以多播的方式发送到订阅者的事g队列里?<br /> <br /> <strong>客户?JavaScript ?/strong> <br /> <br /> pushlet 提供了基?AJAX ?JavaScript 库文件用于实现长轮询方式?#8220;服务器推”Q还提供了基?iframe ?JavaScript 库文件用于实现流方式?#8220;服务器推”?<br /> </p> </td> </tr> </tbody> </table> <img src ="http://www.aygfsteel.com/caizh2009/aggbug/279721.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/caizh2009/" target="_blank">菜毛毛</a> 2009-06-02 23:46 <a href="http://www.aygfsteel.com/caizh2009/articles/279721.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>dwr实例2Q联菜单ƈ定默认|http://www.aygfsteel.com/caizh2009/articles/279694.html菜毛毛菜毛毛Tue, 02 Jun 2009 13:30:00 GMThttp://www.aygfsteel.com/caizh2009/articles/279694.htmlhttp://www.aygfsteel.com/caizh2009/comments/279694.htmlhttp://www.aygfsteel.com/caizh2009/articles/279694.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/279694.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/279694.html<%@ include file="/common/taglibs.jsp"%>

<title><fmt:message key="menu.admin" />-><fmt:message key="menu.admin.departmentsManager" /></title>

<link rel="stylesheet" type="text/css" media="all" href="<c:url value='/styles/default.css'/>" />
<link rel="stylesheet" type="text/css" media="all" href="<c:url value='/styles/helptip.css'/>" />
<link rel="stylesheet" type="text/css" media="print" href="<c:url value='/styles/print.css'/>" />

<c:if test="${not empty errorReason}">
   <div align="center" style="color: red">
       <c:if test="${errorReason=='updateConstraint'}">
         <fmt:message key="tcsBox.updateConstraint"/>
       </c:if>
       <c:if test="${errorReason=='addConstraint'}">
         <fmt:message key="tcsBox.addConstraint"/>
       </c:if>
   </div>
</c:if>
<html:form action="editBoxes.html?method=finishEdit" styleId="TcsboxForm" >

<table class="detail" valign="top"> 
<c:if test="${from == 'update' or param.handle =='update'}">
  <input type="hidden" value="update"  name="handle"/>
</c:if >
<c:if test="${from == 'add'}">
  <input type="hidden" value="add"  name="handle"/>
</c:if >  
<!-- <c:set var="pageButtons">
    <tr>
        <td height="50"></td>
        <td class="buttonBar">
         <c:if test="${from == 'update'}">
           <input type="submit" value='<fmt:message key="button.submit"/>' class="button" />
           <input type="hidden" value="update"  name="handle"/>
         </c:if >
         <c:if test="${from == 'add'}">
          <input type="submit" value='<fmt:message key="button.submit"/>' class="button" />
          <input type="hidden" value="add"  name="handle"/>
            </c:if >  
             <input type="reset" value='<fmt:message key="button.reset"/>' class="button"/>
               
                <input type="button" value='<fmt:message key="button.back"/>' class="button" onclick="history.back()"/>
        </td>
    </tr>
</c:set> -->
 
      <c:if test="${from=='update' or param.handle =='update'}">
        <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.tcs_box_id"/>
         </th>
         <td>
             <html:text property="tcs_box_id" styleId="tcs_box_id" readonly="true"></html:text>
         </td>
         </tr>
       </c:if>
     <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.code"/>
         </th>
         <td>
             <html:text property="tcs_box_code" styleId="tcs_box_code" ></html:text>
         </td>
     </tr>
      <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.tcs_box_name"/>
         </th>
         <td>
             <html:text property="tcs_box_name" styleId="tcs_box_name" ></html:text>
         </td>
     </tr>
     <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.companycode"/>
         </th>
         <td>
         <html:select property="company_code" styleId="company_code" onchange="changeCompany_Code(this)">
          <html:options collection="companyLst" property="code" labelProperty="name" />
         </html:select>
         </td>
     </tr>
     <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.burea"/>
         </th>
         <td>
         <html:select property="bureau_id"  styleId="bureau_id" >
          <html:options collection="bureauLst" property="code" labelProperty="name" />
         </html:select>
         </td>
     </tr>
    
      <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.district"/>
         </th>
         <td>
         <html:select property="district_id"  styleId="district_id" >
          <html:options collection="districtLst" property="code" labelProperty="name" />
         </html:select>
         </td>
     </tr>
    
     <tr>
         <th>
             <manhourpool:label key="TcsBoxForm.address"/>
         </th>
         <td>
    <html:text property="tcs_address" styleId="tcs_address" ></html:text>
         </td>
     </tr>
     <c:if test="${from=='update' or param.handle =='update'}">
          <tr>
          <th>
              <manhourpool:label key="chartem.state"/>
          </th>
          <td>
              <html:select property="state" >
                 <html:options collection="doms" property="column_value" labelProperty="description"/>
              </html:select>
          </td>
         </tr>
     </c:if>
</table>
<table align="center">
<!-- <c:out value="${pageButtons}"  escapeXml="false"/> --></table>
</html:form>


<script type='text/javascript' src='dwr/interface/bureauManager.js'></script>
<script type='text/javascript' src='dwr/interface/districtManager.js'></script>
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
<script type="text/javascript">
   var bureau_on_load=true;
   var bureau_id='<c:out value="${tcsBoxForm.bureau_id}"/>';
   window.onload=function(){
     window.changeCompany_Code(document.all.company_code);
 var ppage = window.parent.document.frames['theiframtwo'];
 if('<c:out value="${handlesucc}" />'){
  ppage.document.getElementById('viewBoxes').submit();
 }
   }
   function changeCompany_Code(sel_obj)
   {
     var company_code=sel_obj.value;
    
     if(company_code=='')
        return;
     var param =new Object();
     param.company_code=company_code;
     bureauManager.getBureauListInDwr(param,showBureau);
     districtManager.getDistrictBycompany(company_code,showDistrict);
     
   }
  
   function showBureau(bureaus)
   {
 //     var bureau_id=$('bureau_id').value;
 //     if(window.bureau_on_load)
 //     {
 //       bureau_id='<c:out value="${param.bureau_id}"/>';
 //       window.bureau_on_load=false;
//      }
      DWRUtil.removeAllOptions('bureau_id');
      var op=document.createElement('option');
      op.value='';
      op.text='<fmt:message key="task.default" />';
      $('bureau_id').options.add(op);
     
      DWRUtil.addOptions('bureau_id',bureaus,'bureau_id','bureau_name');
      for(var i=0;i<$('bureau_id').options.length;i++)
      {
        if($('bureau_id').options[i].value==bureau_id)
        {
          $('bureau_id').selectedIndex=i;
          break;
        }
      }
   }
  
  
   function showDistrict(dis)
   { 
  
   var dis_code=$('district_id').value;
   if(window.isOnload)
   {
     dis_code='<c:out value="${taskInfoForm.district_id}"/>';
     window.isOnload=false;
   }
     DWRUtil.removeAllOptions('district_id');
     var op=document.createElement('option');
     op.value='';
     op.text='<fmt:message key="task.default" />';
     $('district_id').options.add(op);
     DWRUtil.addOptions('district_id',dis,'code','name');
     for(var i=0;i<$('district_id').options.length;i++)
     {
      if($('district_id').options[i].value==dis_code)
      {
        $('district_id').selectedIndex=i;
        break;
      }
     }
   }
</script>



菜毛毛 2009-06-02 21:30 发表评论
]]>
DWRU联菜单实例http://www.aygfsteel.com/caizh2009/articles/279693.html菜毛毛菜毛毛Tue, 02 Jun 2009 13:28:00 GMThttp://www.aygfsteel.com/caizh2009/articles/279693.htmlhttp://www.aygfsteel.com/caizh2009/comments/279693.htmlhttp://www.aygfsteel.com/caizh2009/articles/279693.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/279693.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/279693.html面Q?br /> <script type='text/javascript' src='dwr/interface/timeLimitMVManager.js'></script>
<script type='text/javascript' src='dwr/engine.js'></script>
<script type='text/javascript' src='dwr/util.js'></script>
<tr>
         <th>
             <fmt:message key="timelimitmv.tyep.name"/>
         </th>
         <td>
          <select name="match_type_work_char_id" onchange="changeType(this)" id="match_type_work_char_id">
                      <option value=""><fmt:message key="msgtem.default" /></option>
       <option value="1"><fmt:message key="timelimitmv.type1"/></option>
       <option value="2"><fmt:message key="timelimitmv.type2"/></option>
       <option value="4"><fmt:message key="timelimitmv.type4"/></option>
             </select>

    
         </td>
     </tr>
    
     <tr>
         <th>
             <fmt:message key="timelimitmv.value.name"/>
         </th>
         <td>
          <select name="begin_value" id="begin_value">
       <option value="1" ><fmt:message key="timelimitmv.type1"/></option>
       <option value="2"><fmt:message key="timelimitmv.type2"/></option>
       <option value="4"><fmt:message key="timelimitmv.type4"/></option>
             </select>

    
         </td>
     </tr>

function changeType(sel_obj)
   {
     var match_type_work_char_id=sel_obj.value;
    
     if(match_type_work_char_id=='')
        return;
     timeLimitMVManager.getVNByTN(match_type_work_char_id,showValue);
     
   }
  
   function showValue(dis)
   { 
  
  
     DWRUtil.removeAllOptions('begin_value');
     DWRUtil.addOptions('begin_value',dis,'begin_value','value_name');
   
   }
 dwr.xmlQ?br />  <allow>
        <create creator="spring" javascript="timeLimitMVManager">
           <param name="beanName" value="timeLimitMVManager"/>   --由SPRINGq行理的MANAGER名称--
           <include method="getVNByTN"/>  --暴露l页面的Ҏ--
        </create> 
    </allow>

managerҎQ?br /> public List getVNByTN(String match_type_work_char_id) {
  // TODO Auto-generated method stub
  List obs=null;
  if(match_type_work_char_id!=null){
  if(match_type_work_char_id.equals("1")){
   obs=timeLimitMVDAO.getSBLXById();
  }
  if(match_type_work_char_id.equals("2")){
   obs=timeLimitMVDAO.getKUPPById();
  }
  if(match_type_work_char_id.equals("4")){
   obs=timeLimitMVDAO.getCXBZById();
  }
  }
  return obs;
 }

菜毛毛 2009-06-02 21:28 发表评论
]]>
DWR学习http://www.aygfsteel.com/caizh2009/articles/279570.html菜毛毛菜毛毛Tue, 02 Jun 2009 05:56:00 GMThttp://www.aygfsteel.com/caizh2009/articles/279570.htmlhttp://www.aygfsteel.com/caizh2009/comments/279570.htmlhttp://www.aygfsteel.com/caizh2009/articles/279570.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/279570.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/279570.html以下三篇文章,由林信良台湾的技术作家写?
DWR 入門與應用(一Q?
http://blog.csdn.net/caterpillar_here/archive/2006/09/06/1186566.aspx
DWR 入門與應用(二):
http://blog.csdn.net/caterpillar_here/archive/2006/09/18/1239538.aspx
DWR 入門與應用(三):
http://blog.csdn.net/caterpillar_here/archive/2006/09/30/1311605.aspx

DWR.xml配置文g说明?doc
DWRW记.doc
DWR技术分?doc
DWR开发培?ppt
DWR学习.doc
打包下蝲 http://www.javaeye.com/topic/32782

DWR学习 http://www.javaeye.com/topic/16424

DWR应用ȝ http://www.javaeye.com/topic/33678



菜毛毛 2009-06-02 13:56 发表评论
]]>
DWR 入門與應用(三)http://www.aygfsteel.com/caizh2009/articles/279569.html菜毛毛菜毛毛Tue, 02 Jun 2009 05:54:00 GMThttp://www.aygfsteel.com/caizh2009/articles/279569.htmlhttp://www.aygfsteel.com/caizh2009/comments/279569.htmlhttp://www.aygfsteel.com/caizh2009/articles/279569.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/279569.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/279569.html來寫個AJAX版的聊天室吧Q先看看直接使用AJAX要如何做刎ͼ首先需要一個簡單的聊天室Servlet…
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 package onlyfun.caterpillar; import java.io.IOException;import java.io.PrintWriter;import java.util.LinkedList;import java.util.List; import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;  public class ChatRoomServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {     private static LinkedList<Message> messages = new LinkedList<Message>();          public ChatRoomServlet() {    super();   }        private List<Message> addMessage(String text) {        if (text != null && text.trim().length() > 0) {            messages.addFirst(new Message(text));            while (messages.size() > 10) {                messages.removeLast();            }        }         return messages;    }     private List<Message> getMessages() {        return messages;    }      protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        List<Message> list = null;                if("send".equals(request.getParameter("task"))) {             list = addMessage(request.getParameter("msg"));        }        else if("query".equals(request.getParameter("task"))){             list = getMessages();        }         PrintWriter out = response.getWriter();        response.setContentType("text/xml");        response.setHeader("Cache-Control", "no-cache");         out.println("<response>");        for(int i = 0; i < list.size(); i++) {            String msg = list.get(i).getText();            out.println("<message>" + msg + "</message>");        }        out.println("</response>");  }             } 


Message物g如下…
1234567891011121314151617181920212223 package onlyfun.caterpillar; public class Message {    private long id = System.currentTimeMillis();    private String text;        public Message(String newtext) {        text = newtext;        if (text.length() > 256) {            text = text.substring(0, 256);        }        text = text.replace('<', '[');        text = text.replace('&', '_');    }     public long getId() {        return id;    }     public String getText() {        return text;    }} 


Servlet接受a息新增與查詢,判斷的方式是檢查請求參數task是send或query?

Servlet會以XML傛_目前List當中的訊息,客戶端可以查詢或插入新訊息時Q取得目前List中的a息Q接著在web.xml中設定一?#8230;
12345678910111213141516171819202122 <?xml version="1.0" encoding="UTF-8"?><web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  <servlet>    <description>    </description>    <display-name>    ChatRoomServlet</display-name>    <servlet-name>ChatRoomServlet</servlet-name>    <servlet-class>    onlyfun.caterpillar.ChatRoomServlet</servlet-class>  </servlet>   <servlet-mapping>    <servlet-name>ChatRoomServlet</servlet-name>    <url-pattern>/ChatRoomServlet</url-pattern>  </servlet-mapping>  <session-config>    <session-timeout>            30        </session-timeout>  </session-config>  </web-app>


在網頁中Q用者可以在輸入a息後按下按鈕送出資訊Q並在XML回應取得時,訊息以一列一列的表格方式示ZQ另外還a定了週期性的輪詢Q即使不輸入新訊息,也可以週期性的取得新的聊天a息…
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5"><title>Chat Room</title> <script type="text/javascript">var xmlHttp; function createXMLHttpRequest() {    if (window.ActiveXObject) {        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");    }     else if (window.XMLHttpRequest) {        xmlHttp = new XMLHttpRequest();    }} function sendMessage() {  var msg = document.getElementById("text").value;    if(msg == "") {    refreshMessage();    return;  }    var param = "task=send&msg=" + msg;  ajaxRequest(param);  document.getElementById("text").value = "";} function queryMessage() {  var param = "task=query";  ajaxRequest(param);} function ajaxRequest(param) {  var url = "ChatRoomServlet?timestamp" + new Date().getTime();    createXMLHttpRequest();  xmlHttp.onreadystatechange = refreshMessage;    xmlHttp.open("POST", url, true);  xmlHttp.setRequestHeader("Content-Type",           "application/x-www-form-urlencoded;");    xmlHttp.send(param);}  function refreshMessage() {  if(xmlHttp.readyState == 4) {        if(xmlHttp.status == 200) {          var messages = xmlHttp.responseXML.getElementsByTagName("message");            var table_body = document.getElementById("dynamicUpdateArea");      var length = table_body.childNodes.length;      for (var i = 0; i < length; i++) {        table_body.removeChild(table_body.childNodes[0]);      }            var length = messages.length;          for(var i = length - 1; i >= 0 ; i--) {              var message = messages[i].firstChild.data;              var row = createRow(message);                      table_body.appendChild(row);                                  }      setTimeout("queryMessage()", 2000);        }  }} function createRow(message) {    var row = document.createElement("tr");    var cell = document.createElement("td");    var cell_data = document.createTextNode(message);    cell.appendChild(cell_data);    row.appendChild(cell);    return row;} </script> </head><body> <p>  Your Message:  <input id="text"/>  <input type="button" value="Send"      onclick="sendMessage()"/></p> <p>Messages:</p>    <table align="left">        <tbody id="dynamicUpdateArea"></tbody>    </table> </body></html>


單抓個畫?#8230; 


直接用AJAXQ後端用JSP/ServletQ您要對請求參數做些判斷Q看看是新增a息或查詢,並要自行輸出XMLQ有的沒?#8230;

ҎDWR的話Q就很簡單了Q寫個簡單的Java物g…
1234567891011121314151617181920212223 package onlyfun.caterpillar; import java.util.LinkedList;import java.util.List; public class Chat {  private static LinkedList<Message> messages = new LinkedList<Message>();   public List addMessage(String text) {    if (text != null && text.trim().length() > 0) {      messages.addFirst(new Message(text));      while (messages.size() > 10) {        messages.removeLast();      }    }     return messages;  }   public List getMessages() {    return messages;  }} 


接著…在dwr.xml中開放一?#8230;
12345678910111213 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr>  <allow>     <create creator="new" javascript="Chat">      <param name="class" value="onlyfun.caterpillar.Chat"/>    </create>        <convert converter="bean" match="onlyfun.caterpillar.Message"/>        </allow></dwr>


使用者取得訊息時Q是直接傛_List物gQ而List中裝的是Message物gQMessage物g是自a物Ӟcontervera定?beanQ表CDWR會自動將Message的getter名稱轉換為傳回客戶端的JavaScript物g中的屬性,例如Message中有 getText()Q則在客戶端可以用message.text這樣的方式來存取?

接著是簡單的客戶端網?#8230;
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5"><title>Insert title here</title> <script src="dwr/interface/Chat.js" type="text/javascript"></script><script src="dwr/engine.js" type="text/javascript"></script><script src="dwr/util.js" type="text/javascript"></script> <script type="text/javascript">function sendMessage() {    var text = DWRUtil.getValue("text");    DWRUtil.setValue("text", "");    Chat.addMessage(text, gotMessages);} function gotMessages(messages) {    var chatlog = "";    for (var data in messages) {        chatlog = "<div>" + messages[data].text +            "</div>" + chatlog;    }    DWRUtil.setValue("chatlog", chatlog);  setTimeout("queryMessage()", 2000);} function queryMessage() {  Chat.getMessages(gotMessages);}</script> </head><body> <p>  Your Message:  <input id="text"/>  <input type="button" value="Send"      onclick="sendMessage()"/></p> <p>Messages:</p><div id="chatlog"></div> </body></html>


當List物g傛_時,它成為gotMessages(messages)中的messages物gQ而messages物g中包?Message物g轉換後對應的JavaScript物gQ由於我們已E設定了ConverterQ所以可以用messages[data].text?取得傛_的訊?#8230;

單抓個畫?#8230;


本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/caterpillar_here/archive/2006/09/30/1311605.aspx



菜毛毛 2009-06-02 13:54 发表评论
]]>
DWR 入門與應用(二)http://www.aygfsteel.com/caizh2009/articles/279568.html菜毛毛菜毛毛Tue, 02 Jun 2009 05:54:00 GMThttp://www.aygfsteel.com/caizh2009/articles/279568.htmlhttp://www.aygfsteel.com/caizh2009/comments/279568.htmlhttp://www.aygfsteel.com/caizh2009/articles/279568.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/279568.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/279568.html假設您要從資料n中查詢出一些字Ԍ然後填寫到表單的下拉選單中?

例如一個示意的JavaE式如下Q?
12345678 package onlyfun.caterpillar; public class Option {  public String[] getOptions() {                // 實際上這些字串是從資料庫中查到的啦…    return new String[] {"良葛?, "毛美?, "c_?};   }} 


傛_的字串陣列,您要填寫C拉選單中Q當Ӟ首先我們要在dwr.xml中開發這個物?#8230;
12345678910 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr>  <allow>    <create creator="new" javascript="OPT">        <param name="class" value="onlyfun.caterpillar.Option"/>    </create>    </allow></dwr>


這是我們的E頁…
123456789101112131415 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5"><script src="option.js" type="text/javascript"></script><script src="dwr/interface/OPT.js" type="text/javascript"></script><script src="dwr/engine.js" type="text/javascript"></script><script src="dwr/util.js" type="text/javascript"></script> </head> <body>    達R: <select id="opts"></select></body></html>


傛_的字串陣列會填入opts這個select中,我們的option.js如下…
12345678 window.onload = function() {    OPT.getOptions(populate);  }; function populate(list){    DWRUtil.removeAllOptions("opts");    DWRUtil.addOptions("opts", list);} 


夠簡單了…不需要解釋了…

看一下結?#8230; 


好啦Q我知道有h在說了,這個程式有夠無?#8230;

改一下!是個不錯的例了,例如連動方塊Q唔Q在Ajax in action中叫啥?Dynamic double comboQ?#8230;

假設一個會d資料庫中查詢資料的JavaE式C意如下Q?
123456789101112131415161718192021222324252627282930 package onlyfun.caterpillar; import java.util.Map;import java.util.TreeMap; public class Bike {  private Map<String, String[]> bikes;    public Bike() {    bikes = new TreeMap<String, String[]>();    bikes.put("2000", new String[] {"2000 T1", "2000 T2", "2000 T3"});    bikes.put("2001", new String[] {"2001 A1", "2001 A2"});    bikes.put("2002", new String[] {"2002 BW1", "2002 BW2", "2002 BW"});    bikes.put("2003", new String[] {"2003 S320"});    bikes.put("2004", new String[] {"2004 TA1", "2004 TA2", "2004 TA3"});  }    public String[] getYears() {    String[] keys = new String[bikes.size()];    int i = 0;    for(String key : bikes.keySet()) {      keys[i++] = key;    }    return keys;   }    public String[] getBikes(String year) {    return bikes.get(year);  }} 


getYears()跟getBkies()分別表示產品的年份跟型號Q這邊用Map模擬Q實際上資料是來自資料n的查詢?

一樣的Q在dwr.xml中設定:
12345678910 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr>  <allow>    <create creator="new" javascript="Bike" scope="application">        <param name="class" value="onlyfun.caterpillar.Bike"/>    </create>  </allow></dwr>


我們會有個腳t車q䆾與型號查詢頁面:
123456789101112131415 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5"><title>Insert title here</title>  <script type='text/javascript' src='dwr/interface/Bike.js'></script>  <script type='text/javascript' src='dwr/engine.js'></script>  <script type='text/javascript' src='dwr/util.js'></script>  <script type='text/javascript' src='bike.js'></script></head><body onload="refreshYearList();">  q䆾Q?lt;select id="years" onchange="refreshBikeList();"></select><br/><br/>  型號Q?lt;select id="bikes"></select><br/></body></html>


注意Q在選完W一個年份後Q會觸發onchange事gQ接著第二個下拉選單會自動填上應q䆾的型號,而不是按鈕按下,再去取得W二個下拉選單,然後refresh...blah...blah...

bike.js如下…
12345678910111213141516171819 function refreshYearList() {    Bike.getYears(populateYearList);} function populateYearList(list){    DWRUtil.removeAllOptions("years");    DWRUtil.addOptions("years", list);    refreshBikeList();} function refreshBikeList() {    var year = $("years").value;    Bike.getBikes(year, populateBikeList);} function populateBikeList(list){    DWRUtil.removeAllOptions("bikes");    DWRUtil.addOptions("bikes", list);} 


一樣很單…

看個無聊的畫面…XD

 

本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/caterpillar_here/archive/2006/09/18/1239538.aspx



菜毛毛 2009-06-02 13:54 发表评论
]]>
DWR 入門與應用(一Q?/title><link>http://www.aygfsteel.com/caizh2009/articles/279567.html</link><dc:creator>菜毛毛</dc:creator><author>菜毛毛</author><pubDate>Tue, 02 Jun 2009 05:53:00 GMT</pubDate><guid>http://www.aygfsteel.com/caizh2009/articles/279567.html</guid><wfw:comment>http://www.aygfsteel.com/caizh2009/comments/279567.html</wfw:comment><comments>http://www.aygfsteel.com/caizh2009/articles/279567.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/caizh2009/comments/commentRss/279567.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/caizh2009/services/trackbacks/279567.html</trackback:ping><description><![CDATA[<p>Java 開發人員與網頁設ah員的樑 DWR…呃!我懶得寫介?#8230;直接來看看可以做什麼吧Q?#8230; </p> <p>請先?http://getahead.ltd.uk/dwr/ 下載 dwr.jarQ放到WEB-INF/lib?#8230; </p> <p>負K處理客戶端請求,並呼叫Java物g的是DWRServletQDWR其實也有些Model 2的味道,只是View的這一層比較弱Q因為放到客戶端的JavaScript應用E式?#8230; </p> <p>在web.xml中加入DWRServlet… <br /> 1234567891011121314151617181920212223 <?xml version="1.0" encoding="UTF-8"?><web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">  <display-name>  ajaxDWR</display-name>  <servlet>    <servlet-name>dwr-invoker</servlet-name>    <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>    <init-param>      <description>      </description>      <param-name>debug</param-name>      <param-value>true</param-value>    </init-param>  </servlet>  <servlet-mapping>    <servlet-name>dwr-invoker</servlet-name>    <url-pattern>/dwr/*</url-pattern>  </servlet-mapping></web-app> </p> <p><br /> 接下來寫個簡單的Hello吧! <br /> 1234567 package onlyfun.caterpillar; public class Hello {  public String hello(String name) {      return "哈囉Q? + name + "Q您的第一個DWRQ?;    }}  </p> <p><br /> 客戶端要呼叫這個Java物gQ傳i它參數Q而後傛_一個字Ԍ客戶端再示這個字Ԍ奇Q其實是要告aDWRServlet這g事,這需要一個dwr.xmlQ?<br /> 1234567891011 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr>  <allow>    <create creator="new" javascript="Hello">      <param name="class" value="onlyfun.caterpillar.Hello" />    </create>  </allow></dwr> </p> <p><br /> creatora定為newQ表CZ用Hello的無參數建構子來生成物gQjavascripta定為HelloQ表C客戶端JavaScriptE式可以使用Hello來呼叫對應的onlyfun.caterpillar.Hello物g?</p> <p>來寫個客戶端的網頁,當中有一個入欄?#8230; <br /> 12345678910111213141516171819 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5">  <title>W一個DWRE式</title>  <script type='text/javascript' src='dwr/interface/Hello.js'></script>  <script type='text/javascript' src='dwr/engine.js'></script>  <script type='text/javascript' src='dwr/util.js'></script>  <script type='text/javascript' src='hello.js'></script></head><body> <input id="user" type="text" /><input type='button' value='哈囉' onclick='hello();' />  <div id="result"></div> </body></html> </p> <p><br /> dwr/interface/Hello.js是由DWRServletҎdwr.xml中的a定生成的,engine.js負K客戶端伺服端溝通,util.js是一些好用的JavaScriptE式Q可以讓您少寫很多JavaScript?</p> <p>hello.js是我們自a的函式Q按下按鈕後Q會呼叫當中的hello()函式Q?<br /> 12345678 function hello() {    var user = $('user').value;    Hello.hello(user, callback);} function callback(msg) {   DWRUtil.setValue('result', msg);}  </p> <p><br /> ${'user'}取得輸入Ƅ位的DOM物gQvalue取得當中的欄位|而後呼叫Hello.hello()Q並value當作參數傳?#8230; i果是呼叫Server端的Hello Java物gQ當i果傛_後,會呼叫JavaScript的callback函式QDWRUtil的setValue()Ҏ會將傛_的msga定i指?id的DOMQ結果就?#8230;啥!AJAX的功能在?#8230;這個而言是發出非同步請求,而回應不用Refresh頁面啦!  </p> <p><br /> 好啦Q這個無聊的Hello DWR可以做啥Q?#8230;XD </p> <p>已經可以讓您做個簡單的文字提示功能?#8230;像這?#8230; <br /> http://caterpillar.onlyfun.net/Gossip/index.html </p> <p>把滑鼠指到書的照片上Q會示提示文字Q這些提示文字本n不是存在E頁上的Q而是在Server端,當滑鼠指到書上時Q會用Request objectLQ然後顯C在框框?#8230; </p> <p>當然Q我的網站只支援PHPQ所以那不是DWR完成的功能,而且我是直接用Request object跟DOML慢刻?#8230;初學者來說已E有些麻煩了…XD </p> <p>不過Q用DWR可以很單完成這個功?#8230; </p> <p>先寫個Java別吧!會抓properties檔案中的文字a息Q例?#8230; <br /> 123456789101112131415 package onlyfun.caterpillar; import java.util.ResourceBundle; public class Book {  private ResourceBundle resource;    public Book() {    resource = ResourceBundle.getBundle("book");   }          public String getDescription(String key) {    return resource.getString(key);  }}  </p> <p><br /> 從程式中q道,它會Lbook_zh_TW.properties的資料,這不是重點啦Q只是Java的一個功能,我們要看的是DWRQ不過先把book_zh_TW.properties準備?#8230; <br /> 123 java=Java 學習{記的介?… BlaBla...spring=Spring 技術手冊的介紹…BlaBla...ajax=Ajax in action 中文版的介紹… </p> <p><br /> 唔!裏頭是中文字Q自qnative2ascii轉換?#8230;這也不是重點…我們是要看DWR怎麼做到文字提示功能… </p> <p>一樣的…要開N個Book物gQ在dwr.xml?#8230; <br /> 1234567891011 <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr>  <allow>  <create creator="new" javascript="Book" scope="application">            <param name="class" value="onlyfun.caterpillar.Book"/>        </create>    </allow></dwr> </p> <p><br /> scopea定為applicationQ表C這個Book物g在整個應用程式階D都z著?</p> <p>然後Q客戶端寫個網?#8230; <br /> 12345678910111213141516171819202122232425262728293031323334353637383940 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=BIG5">  <script type='text/javascript' src='dwr/interface/Book.js'></script>  <script type='text/javascript' src='dwr/engine.js'></script>  <script type='text/javascript' src='dwr/util.js'></script>  <script type='text/javascript' src='book.js'></script><title>個h著/譯作</title></head><body>       <div id="ajax" onmouseover="getBookData(this);" onmouseout="clearData();"><a ><small><img style="border: 0px solid ; width: 80px; height: 110px; float: left;" alt="Ajax in action 中文? title="Ajax in action 中文? src="images/ajax_in_action_c.jpg" hspace="10" vspace="2"></small></a></div>       <div id="spring" onmouseover="getBookData(this);" onmouseout="clearData();"><a ><small><img style="border: 0px solid ; width: 80px; height: 110px; float: left;" alt="Spring 技術手? title="Spring 技術手? src="images/SpringTech_S.jpg" hspace="10" vspace="2"></small></a></div>       <div id="java" onmouseover="getBookData(this);" onmouseout="clearData();"><a ><small><img style="border: 0px solid ; width: 80px; height: 110px; float: left;" alt="Java 學習{記" title="Java 學習{記" src="images/JavaGossip_Cover_Small.jpg" hspace="10" vspace="2"></small></a></div>     <br/><br/><br/><br/><br/><br/>     <div id="info"></div> </body></html> </p> <p><br /> 重點在於onmouseover跟onmouseoutQ滑鼠移入與Ud時會呼叫的函式,還有最下面的infoQ抓回來的書c介Ҏ攑ֈ當中… </p> <p>book.js如下Q簡單的?#8230; <br /> 1234567891011 function getBookData(ele) {  Book.getDescription(ele.id, setBookData);} function setBookData(description) {  DWRUtil.setValue('info', description);} function clearData() {  DWRUtil.setValue('info', '');}  </p> <p><br /> E式很簡單,我懶得解釋了…XD </p> <p>看一下畫面好?#8230;這是滑鼠Ud Ajax in action中文?上的介紹畫面… </p> <p><br /> 本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/caterpillar_here/archive/2006/09/06/1186566.aspx</p> <img src ="http://www.aygfsteel.com/caizh2009/aggbug/279567.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/caizh2009/" target="_blank">菜毛毛</a> 2009-06-02 13:53 <a href="http://www.aygfsteel.com/caizh2009/articles/279567.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>面向 Java 开发h员的 Ajax: 使用 Jetty ?Direct Webhttp://www.aygfsteel.com/caizh2009/articles/268972.html菜毛毛菜毛毛Tue, 05 May 2009 06:49:00 GMThttp://www.aygfsteel.com/caizh2009/articles/268972.htmlhttp://www.aygfsteel.com/caizh2009/comments/268972.htmlhttp://www.aygfsteel.com/caizh2009/articles/268972.html#Feedback0http://www.aygfsteel.com/caizh2009/comments/commentRss/268972.htmlhttp://www.aygfsteel.com/caizh2009/services/trackbacks/268972.html转蝲IBM开发社?br /> 受异步服务器端事仉动的 Ajax 应用E序实现较ؓ困难Qƈ且难于扩展。Philip McCarthy 在其q受Ƣ迎?pd文章 中介l了一U行之有效的ҎQ结合?Comet 模式Q将数据推到客户机)?Jetty 6 ?Continuations APIQ将 Comet 应用E序扩展到大量客h中)。您可以方便地在 Direct Web Remoting (DWR) 2 中将 Comet ?Continuations ?Reverse Ajax 技术结合用?

作ؓ一U广泛 用的 Web 应用E序开发技术,Ajax 牢固立了自qCQ随之而来的是一些通用 Ajax 使用模式。例如,Ajax l常用于对用戯入作出响应,然后使用从服务器获得的新数据修改面的部分内宏V但是,有时 Web 应用E序的用L面需要进行更C响应服务器端发生的异步事Ӟ而不需要用h?—?例如Q显C到?Ajax 聊天应用E序的新消息Q或者在文本~辑器中昄来自另一个用L改变。由于只能由览器徏?Web 览器和服务器之间的 HTTP q接Q服务器无法在改动发生时变?“推?#8221; l浏览器?/p>

Ajax 应用E序可以使用两种基本的方法解册一问题Q一U方法是览器每隔若q秒旉向服务器发出轮询以进行更斎ͼ另一U方法是服务器始l打开与浏览器的连接ƈ在数据可用时发送给览器。长期连接技术被UCؓ CometQ请参阅 参考资?/a>Q。本文将展示如何l合使用 Jetty servlet 引擎?DWR h效地实现一?Comet Web 应用E序?/p>

Z么?CometQ?/span>

? 询方法的主要~点是:当扩展到更多客户机时Q将生成大量的通信量。每个客h必须定期讉K服务器以查更斎ͼqؓ服务器资源添加了更多负荷。最坏的一U情 冉|对不频繁发生更新的应用程序用轮询,例如一U?Ajax 邮g Inbox。在q种情况下,相当数量的客h轮询是没有必要的Q服务器对这些轮询的回答只会? “没有产生新数?#8221;。虽然可以通过增加轮询的时间间隔来减轻服务器负P但是q种Ҏ会生不良后果,卛_gq客hҎ务器事g的感知。当Ӟ很多应用E? 序可以实现某U权衡,从而获得可接受的轮询方法?/p>

管如此Q吸引h们?Comet {略的其中一个优Ҏ其显而易见的高效性。客h不会像用轮询方法那L成烦人的通信量,q且事g发生后可立即发布l客h。但是保持长期连接处于打开 状态也会消耗服务器资源。当{待状态的 servlet 持有一个持久性请求时Q该 servlet 会独占一个线E。这限?Comet 对传l? servlet 引擎的可伸羃性,因ؓ客户机的数量会很快超q服务器栈能有效处理的线E数量?/p>



回页?/strong>


Jetty 6 有何不同

Jetty 6 的目的是扩展大量同步q接Q?Java™ 语言的非d I/OQ?code>java.nioQ库q用一个经q优化的输出~冲架构Q参?参考资?/a>Q。Jetty qؓ处理长期q接提供了一些技巧:该特性称?Continuations? 我将使用一个简单的 servlet ?Continuations q行演示Q这?servlet 接受请求,{待处理Q然后发送响应。接下来Q我展C当客户机数量超q服务器提供的处理线E后发生的状c最后,我将使用 Continuations 重新实现 servletQ您了?Continuations 在其中扮演的角色?/p>

Z便于理解下面的示例,我将?Jetty servlet 引擎限制在一个单h处理U程?a >清单 1 展示?jetty.xml 中的相关配置。我实际上需要在 ThreadPool 使用三个U程QJetty 服务器本w用一个线E,另一U程q行 HTTP q接器,侦听到来的请求。第三个U程执行 servlet 代码?/p>
清单 1. 单个 servlet U程?Jetty 配置
                
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
"http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.Server">
<Set name="ThreadPool">
<New class="org.mortbay.thread.BoundedThreadPool">
<Set name="minThreads">3</Set>
<Set name="lowThreads">0</Set>
<Set name="maxThreads">3</Set>
</New>
</Set>
</Configure>

接下来,Z模拟对异步事件的{待Q?a >清单 2 展示?BlockingServlet ?service() ҎQ该Ҏ?Thread.sleep() 调用在线E结束之前暂?2000 毫秒的时间。它q在执行开始和l束时输出系l时间。ؓ了区别输出和不同的请求,q将作ؓ标识W的h参数记录在日志中?/p>
清单 2. BlockingServlet
                
public class BlockingServlet extends HttpServlet {

public void service(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {

String reqId = req.getParameter("id");

res.setContentType("text/plain");
res.getWriter().println("Request: "+reqId+"\tstart:\t" + new Date());
res.getWriter().flush();

try {
Thread.sleep(2000);
} catch (Exception e) {}

res.getWriter().println("Request: "+reqId+"\tend:\t" + new Date());
}
}

现在可以观察?servlet 响应一些同步请求的行ؓ?a >清单 3 展示了控制台输出Q五个?lynx 的ƈ行请求。命令行启动五个 lynx q程Q将标识序号附加在请?URL 的后面?


清单 3. ?BlockingServlet q发h的输?/strong>
                

$ for i in 'seq 1 5' ; do lynx -dump localhost:8080/blocking?id=$i & done
Request: 1 start: Sun Jul 01 12:32:29 BST 2007
Request: 1 end: Sun Jul 01 12:32:31 BST 2007

Request: 2 start: Sun Jul 01 12:32:31 BST 2007
Request: 2 end: Sun Jul 01 12:32:33 BST 2007

Request: 3 start: Sun Jul 01 12:32:33 BST 2007
Request: 3 end: Sun Jul 01 12:32:35 BST 2007

Request: 4 start: Sun Jul 01 12:32:35 BST 2007
Request: 4 end: Sun Jul 01 12:32:37 BST 2007

Request: 5 start: Sun Jul 01 12:32:37 BST 2007
Request: 5 end: Sun Jul 01 12:32:39 BST 2007

清单 3 中的输出和预期一栗因?Jetty 只可以用一个线E执?servlet ?service() Ҏ。Jetty 对请求进行排列,q按序提供服务。当针对某请求发出响应后立xC时间戳Q一?end 消息Q,servlet 接着处理下一个请求(后箋?start 消息Q。因此即使同时发Z个请求,其中一个请求必ȝ?8 U钟的时间才能接?servlet 处理?/p>

h意,?servlet 被阻塞时Q执行Q何操作都无济于事。这D代码模拟了h{待来自应用E序不同部分的异步事件。这里用的服务器既不是 CPU 密集型也不是 I/O 密集型:只有U程池耗尽之后才会对请求进行排队?

现在Q查?Jetty 6 ?Continuations Ҏ如何ؓq类情Ş提供帮助?a >清单 4 展示?清单 2 中?Continuations API 重写后的 BlockingServlet。我稍后解释这些代码?/p>
清单 4. ContinuationServlet
                
public class ContinuationServlet extends HttpServlet {

public void service(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {

String reqId = req.getParameter("id");

Continuation cc = ContinuationSupport.getContinuation(req,null);

res.setContentType("text/plain");
res.getWriter().println("Request: "+reqId+"\tstart:\t"+new Date());
res.getWriter().flush();

cc.suspend(2000);

res.getWriter().println("Request: "+reqId+"\tend:\t"+new Date());
}
}

清单 5 展示了对 ContinuationServlet 的五个同步请求的输出Q请?清单 3 q行比较?/p>
清单 5. ?ContinuationServlet 的五个ƈ发请求的输出
                
$ for i in 'seq 1 5' ; do lynx -dump localhost:8080/continuation?id=$i & done

Request: 1 start: Sun Jul 01 13:37:37 BST 2007
Request: 1 start: Sun Jul 01 13:37:39 BST 2007
Request: 1 end: Sun Jul 01 13:37:39 BST 2007

Request: 3 start: Sun Jul 01 13:37:37 BST 2007
Request: 3 start: Sun Jul 01 13:37:39 BST 2007
Request: 3 end: Sun Jul 01 13:37:39 BST 2007

Request: 2 start: Sun Jul 01 13:37:37 BST 2007
Request: 2 start: Sun Jul 01 13:37:39 BST 2007
Request: 2 end: Sun Jul 01 13:37:39 BST 2007

Request: 5 start: Sun Jul 01 13:37:37 BST 2007
Request: 5 start: Sun Jul 01 13:37:39 BST 2007
Request: 5 end: Sun Jul 01 13:37:39 BST 2007

Request: 4 start: Sun Jul 01 13:37:37 BST 2007
Request: 4 start: Sun Jul 01 13:37:39 BST 2007
Request: 4 end: Sun Jul 01 13:37:39 BST 2007

清单 5 中有两处需要重Ҏ意。首先,每个 start 消息出现两次Q先不要着急。其ơ,更重要的一点,h现在不需排队p够ƈ发处理,注意所?start ?end 消息的时间戳是相同的。因此,每个h的处理时间不会超q两U,即只运行一?servlet U程?/p>



回页?/strong>


Jetty Continuations 机制原理

理解?Jetty Continuations 机制的实现原理,您就能够解释 清单 5 中的现象。要使用 ContinuationsQ必d Jetty q行配置Q以使用?SelectChannelConnector 处理h。这个连接器构徏?java.nio API 之上Q因此它能够不用消耗每个连接的U程可以持有开攄q接。当使用 SelectChannelConnector ӞContinuationSupport.getContinuation() 提供一?SelectChannelConnector.RetryContinuation 实例。(然而,您应该只针对 Continuation 接口q行~码Q请参阅 Portability and the Continuations API。)当对 RetryContinuation 调用 suspend() Ӟ它将抛出一个特D的q行时异?—? RetryRequest —?该异常将传播?servlet 以外q过qo器链传回Qƈ?SelectChannelConnector 捕获?但是发生该异怹后ƈ没有响应发送给客户机,h被放到处于等待状态的 Continuation 队列中,?HTTP q接仍然保持打开状态。此Ӟh提供服务的线E将q回 ThreadPoolQ用以ؓ其他h提供服务?

可移植性和 Continuations API

我提到过应该使用 Jetty ?SelectChannelConnector 来启?Continuations 功能。然而,Continuations API 仍然可用于传l的 SocketConnectorQ这U情况下 Jetty 回退C同的 Continuation 实现Q该实现使用 wait()/notify() Ҏ。您的代码仍然可以编译和q行Q但是却失去了非d Continuations 的优炏V如果您希望l箋使用?Jetty 服务器,您应该考虑~写自己?Continuation 包装器,在运行时期用反检?Jetty Continuations 库是否可用。DWR ׃用了q种{略?/p>

暂停的请求将一直保持在{待状态的 Continuation 队列Q直到超出指定的旉Q或者当?resume() Ҏ?Continuation 调用 resume() ӞE后详l介l)。出CqCQ意一U条件时Q请求将被重新提交到 servletQ通过qo器链Q。事实上Q整个请求被重新q行处理Q直到首ơ调?suspend()。当执行W二ơ发?suspend() 调用ӞRetryRequest 异常不会被抛出,执行照常q行?

现在应该可以解释 清单 5 中的输出了。每个请求依ơ进?servlet ?service() Ҏ后,发?start 消息q行响应Q?code>Continuation ?suspend() Ҏ引发 servlet 异常Q将释放U程使其处理下一个请求。所有五个请求快速通过 service() Ҏ的第一部分Qƈq入{待状态,q且所?start 消息在几毫U内输出。两U后Q当过 suspend() 的时限后Q将从等待队列中索第一个请求,q将光新提交给 ContinuationServlet。第二次输出 start 消息Q立卌回对 suspend() 的第二次调用Qƈ且发?end 消息q行响应。然后将在此执行 servlet 代码来处理队列中的下一个请求,以此cL?/p>

因此Q在 BlockingServlet ?ContinuationServlet 两种情况中,h被放入队列中以访问单?servlet U程。然而,虽然 servlet U程执行期间 BlockingServlet 发生两秒暂停Q?code>SelectChannelConnector 中的 ContinuationServlet 的暂停发生在 servlet 之外?code>ContinuationServlet 的d吐量更高一些,因ؓ servlet U程没有大部分旉用在 sleep() 调用中?/p>



回页?/strong>


?Continuations 变得有用

现在您已l了解到 Continuations 能够不消耗线E就可以暂停 servlet hQ我需要进一步解?Continuations API 以向您展C如何在实际应用中用?/p>

resume() Ҏ生成一?suspend()。可以将它们视ؓ标准?Object wait()/notify() 机制?Continuations {h体。就是说Q?code>suspend() ?ContinuationQ因此也包括当前Ҏ的执行)处于暂停状态,直到出旉Q或者另一个线E调?resume()?code>suspend()/resume() 对于实现真正使用 Continuations ?Comet 风格的服务非常关键。其基本模式是:从当前请求获?ContinuationQ调?suspend()Q等待异步事件的到来。然后调?resume() q生成一个响应?

然而,?Scheme q种语言中真正的语言U别?continuations 或者是 Java 语言?wait()/notify() 范例不同的是Q对 Jetty Continuation 调用 resume() q不意味着代码会从中断的地方l执行。正如您刚刚看到的,实际上和 Continuation 相关的请求被重新处理。这会生两个问题:重新执行 清单 4 中的 ContinuationServlet 代码Q以及丢q态:卌?suspend() 时丢׃用域内所有内宏V?/p>

W一个问题的解决Ҏ是?isPending() Ҏ。如?isPending() q回gؓ trueQ这意味着之前已经调用q一?suspend()Q而重新执行请求时q没有发生第二次 suspend() 调用。换a之,Ҏ isPending() 条g在执?suspend() 调用之前q行代码Q这样将保Ҏ个请求只执行一ơ。在 suspend() 调用h{幂性之前,最好先对应用程序进行设计,q样即调用两次也不会出现问题,但是某些情况下无法?isPending() Ҏ?code>Continuation 也提供了一U简单的机制来保持状态:putObject(Object) ?getObject() Ҏ。在 Continuation 发生暂停Ӟ使用q两U方法可以保持上下文对象以及需要保存的状态。您q可以用这U机制作为在U程之间传递事件数据的方式Q稍后将演示q种Ҏ?/p>



回页?/strong>


~写Z Continuations 的应用程?/span>

? 为实际示例场景,我将开发一个基本的 GPS 坐标跟踪 Web 应用E序。它在不规则的旉间隔内生成随机的l纬度值对。发挥一下想象力Q生成的坐标值可能就是͘q的一个公pR站、随w携带着 GPS 讑֤的马拉松选手、汽车拉力赛中的汽R或者运输中的包裏Vo人感兴趣的是我将如何告诉览器这个坐标?a >?1 展示了这个简单的 GPS 跟踪器应用程序的cdQ?/p>
?1. 昄 GPS 跟踪器应用程序主要组件的cd
GPS 跟踪器组件的 UML cd

首先Q应用程序需要某U方法来生成坐标。这由 RandomWalkGenerator 完成。从一对初始坐标对开始,每次调用它的U有 generateNextCoord() ҎӞ从该位|移动随机指定的距离Qƈ新的位|作?GpsCoord 对象q回。初始化完成后,RandomWalkGenerator 生成一个线E,该线E以随机的时间间隔调?generateNextCoord() Ҏq将生成的坐标发送给M注册?addListener() ?CoordListener 实例?a >清单 6 展示?RandomWalkGenerator 循环的逻辑Q?/p>
清单 6. RandomWalkGenerator's run() Ҏ
                
public void run() {

try {
while (true) {
int sleepMillis = 5000 + (int)(Math.random()*8000d);
Thread.sleep(sleepMillis);
dispatchUpdate(generateNextCoord());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

CoordListener 是一个回调接口,仅仅定义 onCoord(GpsCoord coord) Ҏ。在本例中,ContinuationBasedTracker cd?CoordListener?code>ContinuationBasedTracker 的另一个公有方法是 getNextPosition(Continuation, int)?a >清单 7 展示了这些方法的实现Q?/p>
清单 7. ContinuationBasedTracker l构
                
public GpsCoord getNextPosition(Continuation continuation, int timeoutSecs) {

synchronized(this) {
if (!continuation.isPending()) {
pendingContinuations.add(continuation);
}

// Wait for next update
continuation.suspend(timeoutSecs*1000);
}

return (GpsCoord)continuation.getObject();
}


public void onCoord(GpsCoord gpsCoord) {

synchronized(this) {
for (Continuation continuation : pendingContinuations) {

continuation.setObject(gpsCoord);
continuation.resume();
}

pendingContinuations.clear();
}
}

当客h使用 Continuation 调用 getNextPosition() ӞisPending Ҏ检查此时的h是否是第二次执行Q然后将它添加到{待坐标?Continuation 集合中。然后该 Continuation 被暂停。同ӞonCoord —?生成新坐标时被调用 —?循环遍历所有处于等待状态的 ContinuationQ对它们讄 GPS 坐标Qƈ重新使用它们。之后,每个再次执行的请求完?getNextPosition() 执行Q从 Continuation ?GpsCoord q将其返回给调用者。注意此处的同步需求,是ؓ了保?pendingContinuations 集合中的实例状态不会改变,q确保新增的 Continuation 在暂停之前没有被处理q?/p>

最后一个难Ҏ servlet 代码本nQ如 清单 8 所C:


清单 8. GPSTrackerServlet 实现
                
public class GpsTrackerServlet extends HttpServlet {

private static final int TIMEOUT_SECS = 60;
private ContinuationBasedTracker tracker = new ContinuationBasedTracker();

public void service(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {

Continuation c = ContinuationSupport.getContinuation(req,null);
GpsCoord position = tracker.getNextPosition(c, TIMEOUT_SECS);

String json = new Jsonifier().toJson(position);
res.getWriter().print(json);
}
}

如您所见,servlet 只执行了很少的工作。它仅仅获取了请求的 ContinuationQ调?getNextPosition()Q将 GPSCoord 转换?JavaScript Object Notation (JSON)Q然后输出。这里不需要防止重新执行,因此我不必检?isPending()?a >清单 9 展示了调?GpsTrackerServlet 的输出,同样Q有五个同步h而服务器只有一个可用线E:


Listing 9. Output of GPSTrackerServlet
                
$ for i in 'seq 1 5' ; do lynx -dump localhost:8080/tracker & done
{ coord : { lat : 51.51122, lng : -0.08103112 } }
{ coord : { lat : 51.51122, lng : -0.08103112 } }
{ coord : { lat : 51.51122, lng : -0.08103112 } }
{ coord : { lat : 51.51122, lng : -0.08103112 } }
{ coord : { lat : 51.51122, lng : -0.08103112 } }

q个CZq不引h注意Q但是提供了概念证明。发求后Q它们将一直保持打开的连接直至生成坐标,此时快速生成响应。这?Comet 模式的基本原理,Jetty 使用q种原理在一个线E内处理 5 个ƈ发请求,q都?Continuations 的功功?/p>



回页?/strong>


创徏一?Comet 客户?/span>

现在您已l了解了如何使用 Continuations 在理Z创徏非阻?Web 服务Q您可能想知道如何创建客L代码来用这U功能。一?Comet 客户机需要完成以下功能:

  1. 保持打开 XMLHttpRequest q接Q直到收到响应?/li>
  2. 响应发送到合适的 JavaScript 处理E序?/li>
  3. 立即建立新的q接?/li>
更高U的 Comet 讄用一个连接将数据从不同服务推入浏览器Qƈ且客h和服务器配有相应的\由机制。一U可行的Ҏ是根据一U?JavaScript 库,例如 DojoQ编写客L代码Q这提供基?Comet 的请求机Ӟ其Ş式ؓ dojo.io.cometd?

然而,如果服务器?Java 语言Q?DWR 2 可以同时在客h和服务器上获?Comet 高支持Q这是一U不错的ҎQ参?参考资?/a>Q。如果您q不了解 DWR 的话Q请参阅本系列第 3 部分 “l合 Direct Web Remoting 使用 Ajax”。DWR 透明地提供了一U?HTTP-RPC 传输层,您?Java 对象公开l网l中 JavaScript 代码的调用。DWR 生成客户端代理,自动封送和解除送数据,处理安全问题Q提供方便的客户端实用工具库Qƈ可以在所有主要浏览器上工作?





回页?/strong>


DWR 2: Reverse Ajax

DWR 2 最新引入了 Reverse Ajax 概念。这U机制可以将服务器端事g “推入” 到客h。客L DWR 代码透明地处理已建立的连接ƈ解析响应Q因此从开发h员的角度来看Q事件是从服务器?Java 代码L地发布到客户Z?/p>

DWR l过配置之后可以使用 Reverse Ajax 的三U不同机制。第一U就是较为熟悉的轮询Ҏ。第二种UCؓ piggybackQ? q种机制q不创徏M到服务器的连接,相反Q将一直等待直臛_生另一?DWR 服务Qpiggybacks 使事件等待该h的响应。这使它h较高的效率,但也意味着客户Z仉知被gq到直到发生另一个不相关的客h调用。最后一U机制用长期的? Comet 风格的连接。最妙的是,当运行在 Jetty 下时QDWR 能够自动ƈ切换Z?ContiuationsQ实现非d Comet?/p>

我将?GPS CZ中结合?Reverse Ajax ?DWR 2。通过q种演示Q您对 Reverse Ajax 的工作原理有更多的了解?/p>

此时不再需要?servlet。DWR 提供了一个控制器 servletQ它在 Java 对象之上直接转交客户求。同样也不需要显式地处理 ContinuationsQ因?DWR 在内部q行处理。因此我只需要一个新?CoordListener 实现Q将坐标更新发布到到M客户机浏览器上?/p>

ServerContext 接口提供?DWR ?Reverse Ajax 功能?code>ServerContext 可以察觉到当前查看给定页面的所?Web 客户机,q提供一?ScriptSession q行怺通信?code>ScriptSession 用于?Java 代码?JavaScript 片段推入到客h?a >清单 10 展示?ReverseAjaxTracker 响应坐标通知的方式,q用它们生成对客户?updateCoordinate() 函数的调用。注意对 DWR ScriptBuffer 对象调用 appendData() 自动把 Java 对象送给 JSONQ如果用合适的转换器)?/p>
清单 10. ReverseAjaxTracker 中的通知回调Ҏ
                
public void onCoord(GpsCoord gpsCoord) {

// Generate JavaScript code to call client-side
// function with coord data
ScriptBuffer script = new ScriptBuffer();
script.appendScript("updateCoordinate(")
.appendData(gpsCoord)
.appendScript(");");

// Push script out to clients viewing the page
Collection<ScriptSession> sessions =
sctx.getScriptSessionsByPage(pageUrl);

for (ScriptSession session : sessions) {
session.addScript(script);
}
}

接下来,必须?DWR q行配置以感?ReverseAjaxTracker 的存在。在大型应用E序中,可以使用 DWR ?Spring 集成提供 Spring 生成?bean。但是,在本例中Q我仅?DWR 创徏了一?ReverseAjaxTracker 新实例ƈ其攑ֈ application 范围中。所有后l请求将讉Kq个实例?/p>

我还需告诉 DWR 如何数据从 GpsCoord beans 送到 JSON。由?GpsCoord 是一个简单对象,DWR 的基于反的 BeanConverter 可以完成此功能?a >清单 11 展示?ReverseAjaxTracker 的配|:


清单 11. ReverseAjaxTracker ?DWR 配置
                
<dwr>
<allow>
<create creator="new" javascript="Tracker" scope="application">
<param name="class" value="developerworks.jetty6.gpstracker.ReverseAjaxTracker"/>
</create>

<convert converter="bean" match="developerworks.jetty6.gpstracker.GpsCoord"/>
</allow>
</dwr>

create 元素?javascript 属性指定了 DWR 用于跟t器公开?JavaScript 对象的名字,在本例中Q我的客L代码没有使用该属性,而是数据从跟踪器推入到其中。同? Q还需?web.xml q行额外的配|,以针?Reverse Ajax 配置 DWRQ如 清单 12 所C:


清单 12. DwrServlet ?web.xml 配置
                
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>
org.directwebremoting.servlet.DwrServlet
</servlet-class>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

W一?servlet init-paramQ?code>activeReverseAjaxEnabled 激z轮询和 Comet 功能。第二个 initApplicationScopeCreatorsAtStartup 通知 DWR 在应用程序启动时初始?ReverseAjaxTracker。这在?bean 生成W一个请求时改写延迟初始化(lazy initializationQ的常规行ؓ —?在本例中q是必须的,因ؓ客户Z会主动对 ReverseAjaxTracker 调用Ҏ?/p>

最后,我需要实现调用自 DWR 的客L JavaScript 函数。将向回调函?—?updateCoordinate() —?传?GpsCoord Java bean ?JSON 表示Q由 DWR ?BeanConverter 自动序列化。该函数从坐标中提?longitude ?latitude 字段Qƈ通过调用 Document Object Model (DOM) 它们附加到列表中?a >清单 13 展示了这一q程Q以及页面的 onload 函数?code>onload 包含?dwr.engine.setActiveReverseAjax(true) 的调用,通知 DWR 打开与服务器的持久连接ƈ{待回调?/p>
清单 13. ?Reverse Ajax GPS 跟踪器的客户端实?/strong>
                
window.onload = function() {
dwr.engine.setActiveReverseAjax(true);
}

function updateCoordinate(coord) {
if (coord) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(
coord.longitude + ", " + coord.latitude)
);
document.getElementById("coords").appendChild(li);
}
}

不?JavaScript 更新面
如果希望最化应用E序中用的 JavaScript 代码的数量,可以使用 ScriptSession ~写 JavaScript 回调Q将 ScriptSession 实例装?DWR Util 对象中。该cd提供直接操作览?DOM 的简?Java ҎQƈ在后台自动生成所需的脚本?

现在我可以将览器指向跟t器面QDWR 在生成坐标数据时把数据推入客户机。该实现输出生成坐标的列表,??2 所C:


?2. ReverseAjaxTracker 的输?/strong>
列出生成坐标的简?Web 面

可以看到Q?Reverse Ajax 创徏事g驱动?Ajax 应用E序非常单。请CQ正是由?DWR 使用?Jetty ContinuationsQ当客户机等待新事g到来时不会占用服务器上面的线E?/p>

此时Q集成来?Yahoo! ?Google 的地N仉常简单。通过更改客户端回调,可轻村֜坐标传送到地图 APIQ而不是直接附加到面中?a >?3 展示?DWR Reverse Ajax GPS 跟踪器在此类地图lg上标l随\U:


Figure 3. h地图 UI ?ReverseAjaxTracker
地图昄路线跟踪生成的坐? src=




回页?/strong>


l束?/span>

? q本文,您了解了如何l合使用 Jetty Continuations ?Comet Z仉?Ajax 应用E序提供高效的可扩展解决Ҏ。我没有l出 Continuations 可扩展性的具体数字Q因为实际应用程序的性能取决于多U变化的因素。服务器g、所选择的操作系l、JVM 实现、Jetty 配置以及应用E序的设计和通信量配|文仉会媄?Jetty Continuations 的性能。然而,Webtide ?Greg WilkinsQ主要的 Jetty 开发h员)曄发布了一份关?Jetty 6 的白皮书Q对使用 Continuations 和没有? Continuations ?Comet 应用E序的性能q行了比较,该程序同时处?10000 个ƈ发请求(参阅 参考资?/a>Q。在 Greg 的测试中Q?Continuations 能够减少U程消耗,q同时减了过 10 倍的栈内存消耗?/p>

? q看C使用 DWR ?Reverse Ajax 技术实C仉?Ajax 应用E序是多么简单。DWR 不仅省去了大量客L和服务器端编码,而且 Reverse Ajax q从代码中将完整的服务器-推送机制抽象出来。通过更改 DWR 的配|,您可以自由地?Comet、轮询,甚至?piggyback Ҏ之间q行切换。您可以Ҏq行实验Qƈ扑ֈ适合自己应用E序的最x能{略Q同时不会媄响到自己的代码?/p>

如果希望对自q Reverse Ajax 应用E序q行实验Q下载ƈ研究 DWR 演示E序的代码(DWR 源代码发行版的一部分Q参?参考资?/a>Q将非常有帮助。如果希望亲自运行示例,q可获得本文使用的示例代码(参见 下蝲Q?/p>




回页?/strong>


下蝲

描述名字大小下蝲Ҏ
CZ代码 jetty-dwr-comet-src.tgz 8KB HTTP
关于下蝲Ҏ的信?/a>


参考资?

学习

获得产品和技?/strong>

讨论
查看 developerWorks blogsQ加?developerWorks C֌?

菜毛毛 2009-05-05 14:49 发表评论
]]>
վ֩ģ壺 ¡| | ǭ| | | | Ұ| ɽ| ̫| ׯ| | ͼʲ| | ˫| ŷ| ʯ| ¤| | ʹ| | Ҫ| | | | Ȫ| | ƽ| | ˮ| | ٹ| | | | ҵ| ¤| | | | | ˿|