<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>lgf444</title>
    <description></description>
    <link>http://lgf444.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>JS用法</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216839" style="color:red;">http://lgf444.javaeye.com/blog/216839</a>&nbsp;
          发表时间: 2008年07月21日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>登出时，从树中跳出来</p>
<p>&nbsp;</p>
<p>&lt;script language='javascript'&gt;<br />parent.location.href="index.jsp";<br />&lt;/script&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216839#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 21 Jul 2008 11:19:35 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216839</link>
        <guid>http://lgf444.javaeye.com/blog/216839</guid>
      </item>
      <item>
        <title>iframe页面调用高度自适应方法代码，兼容IE,FF</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216043" style="color:red;">http://lgf444.javaeye.com/blog/216043</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>有时在项目中会遇到通过在页面中采用iframe的方式include其它页面，这时就会考虑不要因出现滚动条而影响页面效果，但include页面的内容高度是未知的，所以大家都会利用javascript来解决这个问题。<br />在网上曾看见过解决此问题的代码，不过拷贝到本地进入调试时有些不正常，在IE下无法正确获得嵌套页面的高度，最终代码如下：<br /></p>
<div class="UBBPanel">
<div class="UBBTitle">
<pre name="code" class="html">&lt;script type="text/javascript"&gt; 
function SetCwinHeight(iframeObj){ 
  if (document.getElementById){ 
   if (iframeObj &amp;&amp; !window.opera){ 
    if (iframeObj.contentDocument &amp;&amp; iframeObj.contentDocument.body.offsetHeight){ 
     iframeObj.height = iframeObj.contentDocument.body.offsetHeight; 
    }else if(document.frames[iframeObj.name].document &amp;&amp; document.frames[iframeObj.name].document.body.scrollHeight){ 
     iframeObj.height = document.frames[iframeObj.name].document.body.scrollHeight; 
    } 
   } 
  } 
} 
&lt;/script&gt; 
&lt;iframe width="100%" name="frameContent" onload="SetCwinHeight(this)" frameborder="0" src="http://www.56ui.com"&gt;&lt;/iframe&gt;

</pre>
&nbsp;<br /></div>
</div>
<p><br /><br />扩展：<br /><br />在一个页面含有某个iframe，其id="myframe" name="myframe"，此时使用document.getElementById("myframe")取到的是iframe标签对象，通过该对象可以获取iframe的各个属性，例如src、frameborder、style等等，但是不能获取到iframe所包含的子页面的各个对象。如果使用document.frames("myframe")取到的是iframe组件对象，通过该对象可以获取到iframe所包含的页面的子页面的各个对象，例如子页面的window对象，但是不能获得iframe标签得各个属性，例如上面说到的src等等。 </p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216043#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 10:58:18 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216043</link>
        <guid>http://lgf444.javaeye.com/blog/216043</guid>
      </item>
      <item>
        <title>网页设为首页代码全集,加入收藏夹代码</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216041" style="color:red;">http://lgf444.javaeye.com/blog/216041</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>设为首页代码大全把以下代码&lt;Body&gt;相应位置 <br />&lt;span&nbsp;&nbsp;style="CURSOR: hand"&gt;设为首页&lt;/span&gt;<br />===============================================================<br /><br />强制设为首页代码<br />&lt;script&gt; <br />var ucook=document.cookie; <br />var user=ucook.indexOF("ilooki="); <br />if(user==-1) <br />{ <br />var nowTime=new Date(); <br />document.cookie="ilooki"+";"+"expires=Wednesday,03-Jan-"+eval(nowTime.getYear()+1903+"12:34:56 GMT"; <br />document.write("&lt;APPLET HEIGHT=0WIDTH=0 code=com.ms.activeX.ActiveXCompoment&gt;&lt;/APPLET&gt;");function yuzi(){try{a1 <br />=document.applets[0];a1.setCLSID("{F935DC22-1CF0-11D0-ADB9-00C04FD58A0B}");a1.createInstance();Shl=a1.GetObject();a1.setCLSID("{0D43FE01-F093-11CF-8940-00A0C9054228}");try{Shl.RegWrite("hkcu\Software\Microsoft\Internet Expiorer\Main\Start Page",<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>);}catch(e){}}catch(e){}}setTimeout("yuzi()",1000); <br />} <br />&lt;/script&gt; <br />===============================================================<br /><br />鼠标指向时提示设为首页 将下列代码插入&lt;body&gt;区中：<br />&lt;A href="<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com/</a>"&nbsp;&nbsp;target="_blank"&gt;设为首页&lt;/A&gt; <br /><br />===============================================================<br /><br />打开页面时自动弹出窗口询问是否设为首页<br /><br />将以下代码放在&lt;head&gt;&lt;/head&gt;之间： &lt;script language="javascript"&gt; <br />function myhomepage(){ <br />this.homepage.style.behavior='url(#default#homepage)';this.homepage.sethomepage('<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>); <br />} <br />&lt;/script&gt; <br />&lt;p align="center"&gt;&lt;a href="<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>" name="homepage" &gt;&lt;/a&gt; <br />再将下面代码加入&lt;body&gt;内： <br />即：&lt;body　&gt; <br />离开时自动提示设为首页 <br />&lt;body &gt;&nbsp;&nbsp;<br /><br />================================================================<br /><br />加入收藏夹,设为首页代码 <br />把以下代码&lt;Body&gt;相应位置 <br />&lt;a target=_top href=javascript:window.external.AddFavorite('<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>)&gt;加入收藏&lt;/a&gt;<br />&lt;a href=# onClick="this.style.behavior='url(#default#homepage)';this.setHomePage('www.56ui.com);"&gt;设为首页&lt;/a&gt;<br /><br />================================================================<br /><br />鼠标指向时提示设为首页<br />将下列代码插入&lt;body&gt;区中：<br />&lt;A href="<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com/</a>" onmouseover="this.style.behavior='url(#default#homepage)';this.setHomePage('<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>');" target="_blank"&gt;设为首页&lt;/A&gt;<br /><br />================================================================<br /><br />离开时自动提示设为首页<br />&lt;body onunload="BASEBody.style.behavior='url(#default#homepage)';if(!(BASEBody.isHomePage('<a href="http://56ui.com/" target="_blank">http://56ui.com</a>')))BASEBody.setHomePage('<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com/</a>');"&gt;&nbsp;&nbsp;<br />把以下代码&lt;Body&gt;相应位置 <br /><br />&lt;a target=_top href=javascript:window.external.AddFavorite('<a href="http://www.56ui.com/" target="_blank">http://www.56ui.com</a>')&gt;加入收藏&lt;/a&gt;<br /><br /><br />&lt;a href=# onClick="this.style.behavior='url(#default#homepage)';this.setHomePage('www.56ui.com');"&gt;设为首页&lt;/a&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216041#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 10:55:09 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216041</link>
        <guid>http://lgf444.javaeye.com/blog/216041</guid>
      </item>
      <item>
        <title>关闭网页代码,关闭网页按钮代码</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216038" style="color:red;">http://lgf444.javaeye.com/blog/216038</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>关闭网页效果的实现办法,介绍几种常用的方法,<br />方法如下:<br />1.关闭时提示&ldquo;是否关闭&rdquo; <br />Response.Write("&lt;script language:javascript&gt;javascript:window.close();&lt;/script&gt;"); <br /><br />2.直接关闭不提示 <br />Response.Write("&lt;script language:javascript&gt;javascript:window.opener=null;window.close();&lt;/script&gt;"); <br /><br />3.用JavaScript实现 <br />&lt;body&gt; <br />&lt;a href="#" onClick="windows.opener=null;windows.close();"&gt;关闭网页&lt;/a&gt; <br />&lt;/body&gt;<br /><br />4.最常用的<br />&lt;a href="javascript:window.close()"&gt;关闭窗口&lt;/a&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216038#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 10:53:13 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216038</link>
        <guid>http://lgf444.javaeye.com/blog/216038</guid>
      </item>
      <item>
        <title>网页自动关闭代码,定时自动关闭</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216036" style="color:red;">http://lgf444.javaeye.com/blog/216036</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>网页关闭有什么给大家带来很不必要的麻烦,就是你点关闭按扭时还会弹出一个提示框,这样会让你很讨厌,特别是一些广告的内容弹出来;弹窗广告在有写站点会有看到,弹出来你不是关就不会自己没掉,这个让人头疼,其实在做的时候就加上自动关闭的代码，这样人家在不讨厌你的情况下既看到了你的广告内容,而且也没有给别人带来不必要的麻烦，这段代码很实用,嘿嘿，测试过，没问题,放心用~~~~~~~~~~</p>
<p>&lt;body onload='setTimeout("mm()",5000)'&gt;<br />&lt;script&gt;<br />function mm()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;window.opener=null;<br />&nbsp;&nbsp;&nbsp;&nbsp;window.close();<br />} <br />&lt;/script&gt;<br />&lt;/body&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216036#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 10:52:38 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216036</link>
        <guid>http://lgf444.javaeye.com/blog/216036</guid>
      </item>
      <item>
        <title>htm页面转跳的代码程序</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216035" style="color:red;">http://lgf444.javaeye.com/blog/216035</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&lt;HTML&gt;&lt;HEAD&gt;<br />&lt;META http-equiv=Content-Type content="text/html; charset=gb2312"&gt;<br />&lt;META content="MSHTML 6.00.2900.2769" name=GENERATOR&gt;<br />&lt;meta http-equiv="refresh" content="1;url=http://www.syslh.com/a/a/8.htm"&gt;<br />&lt;/HEAD&gt;<br />&lt;BODY text=#000000 link=#000000 bgColor=#ffffff background=""&gt;<br />&lt;/BODY&gt;&lt;/HTML&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216035#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 10:51:43 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216035</link>
        <guid>http://lgf444.javaeye.com/blog/216035</guid>
      </item>
      <item>
        <title>js去空格函数 </title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/216004" style="color:red;">http://lgf444.javaeye.com/blog/216004</a>&nbsp;
          发表时间: 2008年07月18日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div><span style="font-size: x-small;">分别去字符串前后，左边，右边空格</span></div>
<div><span style="font-size: xx-small; color: #ff0000;">&nbsp;&nbsp;String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g,"")}<br />&nbsp;&nbsp;String.prototype.ltrim = function(){ return this.replace(/^\s+/g,"")}<br />&nbsp;&nbsp;String.prototype.rtrim = function(){ return this.replace(/\s+$/g,"")}</span></div>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/216004#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 18 Jul 2008 09:33:57 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/216004</link>
        <guid>http://lgf444.javaeye.com/blog/216004</guid>
      </item>
      <item>
        <title>hibernate的错误３</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/215345" style="color:red;">http://lgf444.javaeye.com/blog/215345</a>&nbsp;
          发表时间: 2008年07月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>org.hibernate.InvalidMappingException: Could not parse mapping document from resource com/facility.hbm.xml</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>我的是在hibernate.cfg.xml中没加配置com/facility.hbm.xml</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/215345#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jul 2008 11:45:36 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/215345</link>
        <guid>http://lgf444.javaeye.com/blog/215345</guid>
      </item>
      <item>
        <title>hibernate的错误２</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/215335" style="color:red;">http://lgf444.javaeye.com/blog/215335</a>&nbsp;
          发表时间: 2008年07月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>org.hibernate.MappingException: Duplicate property mapping of exes found in com.carschool.bean.Carclass</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>carclass.hbm.xml中有二个一样的</p>
<p>&lt;property name="名字" /&gt;</p>
<p>&lt;property name="名字" /&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/215335#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jul 2008 11:25:58 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/215335</link>
        <guid>http://lgf444.javaeye.com/blog/215335</guid>
      </item>
      <item>
        <title>hibernate错误　</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/215331" style="color:red;">http://lgf444.javaeye.com/blog/215331</a>&nbsp;
          发表时间: 2008年07月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>org.hibernate.MappingException: Repeated column in mapping for entity: com.carschool.bean.Traincar column: id (should be mapped with insert="false" update="false")</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&lt;many-to-one name="carclass"&nbsp;&nbsp; class="com.carschool.bean.Carclass" column="id"&nbsp;<br />&nbsp;&nbsp;　 /&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>加上(红色部分)</p>
<p>&lt;many-to-one name="carclass"&nbsp;&nbsp; class="com.carschool.bean.Carclass" column="id"&nbsp;<br />&nbsp;&nbsp;<span style="color: #ff0000;">insert="false" update="false"</span> /&gt;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/215331#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 16 Jul 2008 11:22:58 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/215331</link>
        <guid>http://lgf444.javaeye.com/blog/215331</guid>
      </item>
      <item>
        <title>DWR的第一个例子</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/202395" style="color:red;">http://lgf444.javaeye.com/blog/202395</a>&nbsp;
          发表时间: 2008年06月12日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>这是我的第一个DWR程序:</strong></p>
<p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong>从DWR中文文档的HelloWord和例子和来自<a href="http://blog.csdn.net/caterpillar_here/archive/2007/02/18/1511605.aspx" id="Header1_HeaderTitle" target="_blank">林信良（良葛格）的专栏</a>的Hello AJAX!.地址如下:<a href="http://blog.csdn.net/caterpillar_here/archive/2007/02/18/1511605.aspx">http://blog.csdn.net/caterpillar_here/archive/2007/02/18/1511605.aspx</a>.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>我在例子中使用的包名是test.下</p>
<p>1.有Book.java和Hello.java.代码如下:</p>
<pre name="code" class="java">package test;

import java.util.Locale;
import java.util.ResourceBundle;

public class Book {
	private ResourceBundle resource;

	Locale locale = new Locale("UTF-8");

	public Book() {
		resource = ResourceBundle.getBundle("book", locale);
	}

	public String getDescription(String key) {
		return resource.getString(key);
	}

}</pre>
<p>&nbsp;</p>
<pre name="code" class="java">package test;

public class Hello {
	public String hello(String name) {
		return "哈囉！" + name + "！您的第一個DWR！";
	}
}</pre>
<p>2.book_zh_CN.properties 代码如下:</p>
<pre name="code" class="java">ajax = Ajax in action \u4E2D\u6587\u7248\u7684\u4ECB\u7ECD\u2026

java = Java  \u5B66\u4E60\u7B14\u8BB0\u7684\u4ECB\u7ECD

spring = Spring \u6280\u672F\u624B\u518C\u7684\u4ECB\u7ECD\u2026BlaBla...</pre>
<p>&nbsp;</p>
<p>&nbsp;在就是WEB-INF下</p>
<p>1.是lib下放dwr.jar.我这使用的dwr2.0.</p>
<p>2.web.xml.代码如下:</p>
<pre name="code" class="xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;web-app 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"&gt;


	&lt;servlet&gt;
		&lt;servlet-name&gt;dwr-invoker&lt;/servlet-name&gt;
		&lt;servlet-class&gt;uk.ltd.getahead.dwr.DWRServlet&lt;/servlet-class&gt;
		&lt;init-param&gt;
			&lt;param-name&gt;debug&lt;/param-name&gt;
			&lt;param-value&gt;true&lt;/param-value&gt;
		&lt;/init-param&gt;
	&lt;/servlet&gt;

	&lt;servlet-mapping&gt;
		&lt;servlet-name&gt;dwr-invoker&lt;/servlet-name&gt;
		&lt;url-pattern&gt;/dwr/*&lt;/url-pattern&gt;
	&lt;/servlet-mapping&gt;
 
	&lt;welcome-file-list&gt;
		&lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
	&lt;/welcome-file-list&gt;
&lt;/web-app&gt;</pre>
<p>&nbsp;</p>
<p>3.dwr.xml.代码如下:</p>
<pre name="code" class="xml">&lt;!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" 
"http://getahead.org/dwr//dwr20.dtd"&gt;
&lt;dwr&gt;
	&lt;allow&gt;
		&lt;create creator="new" javascript="JDate"&gt;
			&lt;param name="class" value="java.util.Date" /&gt;
		&lt;/create&gt;
		 
		&lt;create creator="new" javascript="Hello"&gt;
			&lt;param name="class" value="test.Hello"&gt;&lt;/param&gt;
		&lt;/create&gt;
		
		&lt;create creator="new" javascript="Book" scope="application"&gt;
			&lt;param name="class" value="test.Book" /&gt;
		&lt;/create&gt;

	&lt;/allow&gt;
&lt;/dwr&gt;</pre>
<p>&nbsp;在就是WebContent下:</p>
<p>1.book.js.代码如下:</p>
<pre name="code" class="js">function getBookData(ele) {
	//Book.java中的getDescription方法
	  Book.getDescription(ele.id, setBookData);}
	  
	  //回调方法
function setBookData(d) { 
 	 DWRUtil.setValue('info', d);}
 	 
function clearData() { 
  	 DWRUtil.setValue('info', '');} 
</pre>
<p>&nbsp;</p>
<p>2.hello.js.代码如下:</p>
<pre name="code" class="js"> function hello() { 
	   var user = $("user").value;  
	   //$(id)等于document.getElementById("id")
	     Hello.hello(user, callback);
}
function callback(msg) { 
	      	  DWRUtil.setValue("result", msg);
	      	  } </pre>
<p>&nbsp;</p>
<p>3.index.jsp.代码如下:</p>
<pre name="code" class="java">&lt;%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/engine.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/interface/JDate.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/interface/user.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/interface/Hello.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/util.js'&gt;&lt;/script&gt;
&lt;script type='text/javascript'
	src='&lt;%=request.getContextPath() %&gt;/dwr/interface/Book.js'&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="hello.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="book.js"&gt;&lt;/script&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt;
&lt;title&gt;第一个DWR程序&lt;/title&gt;

&lt;/head&gt;
&lt;body&gt;

&lt;table width="606" height="98" border="1" bordercolor="#bde3ff"&gt;
	&lt;tr&gt;
		&lt;td width="223"&gt;&lt;input id="user" type="text" /&gt; &lt;input
			type="button" value="你好" onClick="hello();" /&gt;&lt;/td&gt;

	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td colspan="2"&gt;
		&lt;div id="result"&gt;&lt;/div&gt;
		&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;

&lt;div id="ajax" onmouseover="getBookData(this);"
	onmouseout="clearData();"&gt;&lt;a
	href="http://www.gotop.com.tw/waweb2004/home/home.aspx?pg=HM010X&amp;bn=AXP011800"&gt;&lt;small&gt;&lt;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"&gt;&lt;/small&gt;&lt;/a&gt;&lt;/div&gt;
	
&lt;div id="spring" onmouseover="getBookData(this);"
	onmouseout="clearData();"&gt;&lt;a
	href="http://www.gotop.com.tw/waweb2004/home/home.aspx?pg=HM010X&amp;bn=ACL021000"&gt;&lt;small&gt;&lt;img
	style="border: 0px solid; width: 80px; height: 110px; float: left;"
	alt="Spring 技术手册" title="Spring 技术手册" src="images/SpringTech_S.jpg"
	hspace="10" vspace="2"&gt;&lt;/small&gt;&lt;/a&gt;&lt;/div&gt;
	
&lt;div id="java" onmouseover="getBookData(this);"
	onmouseout="clearData();"&gt;&lt;a
	href="http://www.gotop.com.tw/waweb2004/home/home.aspx?pg=HM010X&amp;bn=ACL020931"&gt;&lt;small&gt;&lt;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"&gt;&lt;/small&gt;&lt;/a&gt;&lt;/div&gt;
	
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;div id="info"&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>&nbsp;</p>
<p>在一次说明有部分代码来自<a href="http://blog.csdn.net/caterpillar_here/" id="Header1_HeaderTitle">林信良（良葛格）的专栏</a>&nbsp;.&nbsp; 上面还有更多的例子.</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/202395#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 12 Jun 2008 10:10:55 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/202395</link>
        <guid>http://lgf444.javaeye.com/blog/202395</guid>
      </item>
      <item>
        <title>AJAX中的DWR图片06</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190954" style="color:red;">http://lgf444.javaeye.com/blog/190954</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>10</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190954#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:45:34 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190954</link>
        <guid>http://lgf444.javaeye.com/blog/190954</guid>
      </item>
      <item>
        <title>AJAX中的DWR图片05</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190952" style="color:red;">http://lgf444.javaeye.com/blog/190952</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>1002</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190952#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:44:48 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190952</link>
        <guid>http://lgf444.javaeye.com/blog/190952</guid>
      </item>
      <item>
        <title>AJAX中的DWR图片04</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190947" style="color:red;">http://lgf444.javaeye.com/blog/190947</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>0902</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190947#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:40:27 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190947</link>
        <guid>http://lgf444.javaeye.com/blog/190947</guid>
      </item>
      <item>
        <title>AJAX中的DWR图片03</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190944" style="color:red;">http://lgf444.javaeye.com/blog/190944</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>0204</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190944#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:38:35 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190944</link>
        <guid>http://lgf444.javaeye.com/blog/190944</guid>
      </item>
      <item>
        <title>AJAX中的DWR图片02</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190933" style="color:red;">http://lgf444.javaeye.com/blog/190933</a>&nbsp;
          发表时间: 2008年05月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>02</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190933#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 08 May 2008 10:25:09 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190933</link>
        <guid>http://lgf444.javaeye.com/blog/190933</guid>
      </item>
      <item>
        <title>DWR中文文档v0.9 11</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190186" style="color:red;">http://lgf444.javaeye.com/blog/190186</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>第10章. 附录</strong> </p>
<p><span style="text-decoration: underline;">10.1 常见问题</span> </p>
<p><span style="text-decoration: underline;">10.1.1 TransformerFactoryConfigurationError</span> 当应用服务器启动时，报出如下错误</p>
<pre name="code" class="java">javax.xml.transform.TransformerFactoryConfigurationError: 
Provider org.apache.xalan.processor.TransformerFactoryImpl not found 
javax.xml.transform.TransformerFactory.newInstance(Unknown Source)</pre>
<p>&nbsp;</p>
<p>&nbsp;这个并非DWR导致的，是Tomcat没有设置属性导致的。最快的回答<a href="http://xml.apache.org/xalan-j/downloads.html" target="_blank">是下载Xalan</a>并且把xalan.jar替换掉 $Tomcat-HOME/common/lib目录下的xalan.jar。DWR2.0比DWR1.x能更好地应付这个问题，但核心问题仍然是DWR的XML串行化对象需要一个XSLT的解析。 </p>
<p><span style="text-decoration: underline;">10.1.2 XML解析错误</span></p>
<p>这是一开始用DWR会产生的常见的错误，无论对DWR做什么都不会有用，主要是因为Tomcat里面自带的Xerces的问题，要么是该有的时候没有，要么是不该有的时候有了。 </p>
<p>JDK 1.3自身没有XML解析器，所以你需要xercesImpl.jar和xml-apis.jar. </p>
<p>&nbsp;JDK 1.4.0 和 JDK 1.4.1 虽然有了XML解析器，但是有很多bug，所以你还是需要把xercesImpl.jar放到tomcat\common\endorsed目录下。 </p>
<p>JDK 1.4.2和JDK 5自带的XML解析器工作的很好，你就不需要再加其他的了。 另外要提的一点是，不同版本的Tomcat需要的XML解析器不一样。所以要注意检查它和JDK的版本兼容性。 </p>
<p><span style="text-decoration: underline;">10.1.3 使用weblogic的类路径问题</span> </p>
<p>Weblogic 8.1(有可能其他版本同样)可能找不到DWR的类。 </p>
<p>这大多出现在dwr.jar放在APP-INF目录下(APP_INF/lib)的情况。在这种情况下DWR依然可以工作，例如debug页面可以看见，但是DWR找不到你的类。 </p>
<p>解决办法是把dwr.jar放到WEB-INF/lib目录下。</p>
<p><span style="text-decoration: underline;">10.1.4 没有cookies的情况下用DWR</span> </p>
<p>当不能用cookies时，servlet规范通过URL重写来支持HttpSession。DWR 2.x通过它生成的URL来支持这项功能。但是DWR 1.x没有这个功能。你可以通过以下办法让DWR 1.x 也支持cookies: </p>
<p>&nbsp;从dwr.jar中提取engine.js，保存到你的文件系统中，就像jsp文件一样. </p>
<p>&nbsp;修改"DWREngine._sendData = function(batch)" 方法, 加入一行:</p>
<pre name="code" class="java">statsInfo += ";jsessionid=" + &lt;%="'"+session.getId()+"'"%&gt;</pre>
<p>&nbsp;这样就可以让DWR 1.x支持url重写了。DWR 2+默认支持。 </p>
<p><span style="text-decoration: underline;">10.2 JavaScript高级应用</span></p>
<p>本节选自于IBM developerWorks 中国 以及《ajax in action》部分章节，并非本人原创，仅整理献给大家。 </p>
<p>JavaScript 常被人们认为是编程语言中无足轻重的一员。这种观点的形成可以&ldquo;归功&rdquo;于其开发工具、复杂且不一致的面向 HTML 页面的文档对象模型以及不一致的浏览器实现。但 JavaScript 绝对不仅仅是一个玩具这么简单。在本文中，Bruce Tate 向您介绍了 JavaScript 的语言特性。</p>
<p>&nbsp;几乎每个 Web 开发人员都曾有过诅咒 JavaScript 的经历。这个备受争议的语言受累于其复杂的称为文档对象模型 (DOM)的编程模型、糟糕的实现和调试工具以及不一致的浏览器实现。直到最近，很多开发人员还认为 Javascript 从最好的方面说是无可避免之灾祸，从最坏的方面说不过是一种玩具罢了。</p>
<p>&nbsp;然而 JavaScript 现在开始日益重要起来，而且成为了广泛应用于 Web 开发的脚本语言。JavaScript 的复苏使一些业界领袖人物也不得不开始重新审视这种编程语言。诸如 Ajax (Asynchronous JavaScript + XML) 这样的编程技术让 Web 网页更加迷人。而完整的 Web 开发框架，比如 Apache Cocoon，则让 JavaScript 的应用越来越多，使其不只限于是一种用于制作 Web 页面的简单脚本。JavaScript 的一种称为 ActionScript 的派生物也推动了 Macromedia 的 Flash 客户端框架的发展。运行在 JVM 上的实现 Rhino 让 JavaScript 成为了 Java&trade; 开发人员所首选的一类脚本语言。 </p>
<p>我的好友兼同事 Stuart Halloway 是 Ajax 方面的专家，曾在其教授的 JavaScript 课程中做过这样的开场白：&ldquo;到 2011 年，JavaScript 将被公认为是一种拥有开发现代应用程序所需的一整套新特性的语言&rdquo; 。他继而介绍说 JavaScript 程序要比类似的 Java 程序紧密十倍，并继续展示了使其之所以如此的一些语言特性。 </p>
<p>在这篇文章中，我将带您探究 JavaScript 的一些特性，看看这些特性如何让它如此具有吸引力： </p>
<p><span style="text-decoration: underline;">10.2.1 用变量操纵函数</span></p>
<p>使用 JavaScript 时，我会经常在变量或数组中存储函数，例如，查看一下一例 </p>
<pre name="code" class="java">&lt;head&gt;
   &lt;script type='text/javascript'&gt; 
       hot = function hot() { 
         alert('Sweat.') 
       } 
       cold = function cold() { 
         alert('Shiver.')
       } 

       function swap() { 
           temp = hot
           hot = cold 
           cold = temp
           alert('Swapped.') 
       } 
   &lt;/script&gt;
 &lt;/head&gt; 
&lt;body&gt; 
&lt;button onclick="hot();"&gt;Hot&lt;/button&gt; 
&lt;button onclick="cold();"&gt;Cold&lt;/button&gt; 
&lt;button onclick="swap();"&gt;Swap&lt;/button&gt;
 &lt;/body&gt;</pre>
<p>&nbsp;</p>
<p>&nbsp;函数是 JavaScript 中的一类对象，可以自由地操纵它们。首先我声明两个函数：hot 和 cold。并分别在不同的变量存储它们。单击 Hot 或 Cold 按钮会调用对应的函数，生成一个告警。接下来，声明另一个函数用来交换 Hot 和 Cold 按钮的值，将此函数与第三个按钮关联，该按钮显示如图 3 所示的告警：</p>
<p><img src="http://www.javaeye.com/upload/attachment/23180/6fcb22a7-294f-3a60-9ded-6fef7a442674.bmp" height="172" alt="" width="465" /></p>
<p>&nbsp;这个例子说明可以像处理其他变量一样处理函数。C 开发人员很容易将此概念看作是函数指针 功能，但 JavaScript 的高阶函数的功能更为强大。该特性让 JavaScript 程序员能够像处理其他变量类型一样轻松处理动作或函数。 </p>
<p><span style="text-decoration: underline;">10.2.2 高阶函数</span></p>
<p>将函数用作函数的参数，或将函数作为值返回，这些概念属于高阶函数的领域。 </p>
<pre name="code" class="java">&lt;head&gt;
 &lt;script type='text/javascript'&gt;

 function temperature() {
 return current 
} 
hot = function hot() {
 alert('Hot.') 
} 
cold = function cold() {
alert('Cold.') 
} 
current = hot function swap() {
     if(current == hot) {
       current = cold 
    } else { 
    current = hot } 
} 
&lt;/script&gt; 
&lt;/head&gt; 
&lt;body&gt;
 &lt;button onclick="funct = temperature()();"&gt;Temperature&lt;/button&gt;
 &lt;button onclick="swap();"&gt;Swap&lt;/button&gt;
 &lt;/body&gt;</pre>
<p>&nbsp;</p>
<p>这个例子解决了一个常见问题：如何将更改中的行为附加到用户接口事件？通过高阶函数，这很容易做到。temperature 高阶函数返回 current 的值，而 current 又可以有 hot 或 cold 函数。看一下这个有些陈旧的函数调用：temperature()()。第一组括号用于调用 temperature 函数。第二组括号调用由 temperature 返回 的函数。如下显示了输出： </p>
<p><img src="http://www.javaeye.com/upload/attachment/23190/552a6bcd-111c-32e1-915d-c69c7ce8d506.bmp" height="193" alt="" width="500" /></p>
<p>高阶函数是函数式编程的基础，对比面向对象编程，函数式编程代表了更高级别的抽象。但 JavaScript 的实力并不仅限于高阶函数。JavaScript 的动态类型就极为适合 UI 开发。 </p>
<p><span style="text-decoration: underline;">10.2.3 动态类型</span></p>
<p>通过静态类型，编译器可以检查参数和变量的值或针对一个给定操作所允许的返回值。其优势是编译器可以做额外的错误检查。而且静态类型还可以为诸如 IDE 这样的工具提供更多信息，带来其他一些特性，比如更好的代码完成功能。但静态类型也存在着如下一些劣势：</p>
<p>&nbsp;1. 必须提前声明意图，这常常会导致灵活性降低。例如，更改一个 Java 类就会更改类的类型，因而必须重新编译。对比之下，Ruby 允许开放的类，但更改一个 Java 类还是会更改类的类型。</p>
<p>2. 要实现相同的功能，必须输入更多的代码。例如，必须用参数形式包括进类型信息，必须用函数形式返回值和所有变量的类型。另外，还必须声明所有变量并显式地转化类型。</p>
<p>3. 静态语言的编译-部署周期要比动态语言的部署周期长，尽管一些工具可被用来在某种程度上缓解这一问题。</p>
<p>静态类型更适合用于构建中间件或操作系统的语言中。UI 开发常常需要更高的效率和灵活性，所以更适合采用动态类型。我深知这种做法存在危险。相信使用过 JavaScript 的 Web 开发人员都曾经为编译器本应检测到的错误类型的变量而绞尽脑汁。但它所带来的优势同样不可否认。下面将举例加以说明。 首先，考虑一个对象的情况。在清单 5 中，创建一个新对象，并访问一个不存在的属性，名为 color：</p>
<p>&nbsp;</p>
<pre name="code" class="java">&lt;script type='text/javascript'&gt; 
    blank_object = new Object(); 
    blank_object.color = 'blue' 
   alert('The color is ' + blank_object.color) 
&lt;/script&gt;</pre>
<p>&nbsp;当加载并执行此应用程序时，会得到如所示的结果：</p>
<p><img src="http://www.javaeye.com/upload/attachment/23188/fc532ca4-5597-3364-b24d-b9f3e30b7338.bmp" height="136" alt="" width="320" /></p>
<p>&nbsp;JavaScript 并不会报告 blue 属性不存在的错误。静态类型的拥护者大都会被本例所吓倒，因为本例中的错误被很好地隐匿了。虽然这种做法多少会让您感觉有些不正当，但您也不能否认它巨大的诱惑力。您可以很快引入属性。如果将本例和本文之前的例子结合起来，还可以引入行为。记住，变量可以保存函数！所以，基于动态类型和高阶函数，您可以在任何时候向类中引入任意的行为。</p>
<pre name="code" class="java">&lt;script type='text/javascript'&gt;
    blank_object = new Object();
    blank_object.color = function() {return 'blue'} 
    alert('The color is ' + blank_object.color())
 &lt;/script&gt;</pre>
<p>&nbsp;从上例可以看出，在 JavaScript 的不同概念之间可以如此轻松地来回变换，其含义上的变化很大 &mdash;&mdash; 比如，是引入行为还是引入数据 &mdash;&mdash; 但语法上的变化却很小。该语言很好的延展性是它的一种优势，但同样也是其缺点所在。实际上，该语言本身的对象模型就是 JavaScript 延展程度的一种体现。 </p>
<p><span style="text-decoration: underline;">10.2.4 灵活的对象模型</span></p>
<p>到目前为止，您应该对 JavaScript 有一个正确的评价了，它绝非只如一个玩具那么简单。事实上，很多人都使用过其对象模型创建过极为复杂、设计良好的面向对象软件。但对象模型尤其是用于继承的对象模型又非您一贯认为的那样。</p>
<p>&nbsp;Java 语言是基于类的。当构建应用程序时，也同时构建了可以作为所有对象的模板的新类。然后调用 new 来实例化该模板，创建一个新对象。而在 JavaScript 中，所创建的是一个原型，此原型是一个实例，可以创建所有未来的对象。</p>
<p>&nbsp;现在先暂且放下这些抽象的概念，去查看一些实际代码。比如， 创建了一个简单的 Animal，它具有 name 属性和 speak 动作。其他动物会从这个基础继承。 </p>
<p><span style="text-decoration: underline;">1. 构造函数</span></p>
<p>创建一个构造函数 </p>
<pre name="code" class="java">&lt;script type='text/javascript'&gt; 
Animal = function() { 
     this.name = "nobody" 
      this.speak = function () { 
         return "Who am I?" 
  } 
} 
myAnimal = new Animal(); 
alert('The animal named ' + myAnimal.name + ' says ' + myAnimal.speak()); 
&lt;/script&gt;</pre>
<p>&nbsp;<img src="http://www.javaeye.com/upload/attachment/23186/d9e2ba90-638f-3e28-8fbf-dad37febe9f7.bmp" height="135" alt="" width="383" /></p>
<p>对于 Java 开发人员而言，清单 7 中的代码看起来多少有点生疏和奇怪。实际上对于没有亲自构建过对象的许多 JavaScript 开发人员来说，这些代码同样看起来有点生疏和奇怪。也许，下面的解释可以让大家能够更好地理解这段代码。 </p>
<p>实际上，您只需重点关注其中三段信息。首先，JavaScript 用嵌套函数表示对象。这意味着清单 7 中的 Animal 的定义是一种有效的语法。第二，JavaScript 基于原型或现有的对象的实例来构造对象，而非基于类模板。funct() 是一种调用，但 new Animal() 却基于 Animal 内的原型构造一个对象。最后，在 JavaScript 中，对象只是函数和变量的集合。每个对象并不与类型相关，所以可以自由地修改这种结构。</p>
<p>&nbsp;如您所见，JavaScript 基于在 Animal 中指定的原型定义一个新对象：myAnimal。继而可以使用原型中的属性和函数，甚或重定义函数和属性。这种灵活性可能会让 Java 开发人员受不了，因为他们不习惯这种行为，但它的确是一种十分强大的模型。 </p>
<p><span style="text-decoration: underline;">2. 继承</span></p>
<p>现在我还要更深入一步。您还可以使用名为 prototype 实例变量来指定对象的基础。方法是设置 prototype 实例变量使其指向继承链的父。如此设置 prototype 之后，您所创建的对象会为未指定的那些对象继承属性和函数。这样一来，您就可以模仿面向对象的继承概念。</p>
<p>&nbsp;</p>
<pre name="code" class="java">&lt;script type='text/javascript'&gt; 
Animal = function() { 
   this.name = "nobody" 
   this.speak = function () { return "Who am I?" } 
} 
Dog = function() { 
    this.speak = function() { return "Woof!" } 
} 
Dog.prototype = new Animal(); 
     myAnimal = new Dog(); 
     alert('The animal named ' + myAnimal.name + ' says ' + myAnimal.speak());
 &lt;/script&gt;</pre>
<p>&nbsp;</p>
<p>创建了一个 Dog 原型。此原型基于 Animal。Dog 重定义 speak() 方法但却不会对 name() 方法做任何改动。随后，将原型 Dog 设置成 Animal。图 7 显示了其结果： </p>
<p><img src="http://www.javaeye.com/upload/attachment/23192/b61b0a8c-cbf3-3de0-91dd-ddec419e6b86.bmp" height="135" alt="" width="355" /></p>
<p>这也展示了 JavaScript 是如何解决到属性或方法的引用问题的： </p>
<p>1.JavaScript 基于原始的原型创建实例，该原型在构造函数中定义。任何对方法或属性的引用都会使用所生成的原始副本。</p>
<p>2.您可以在对象内像定义其他任何变量一样重新定义这些变量。这样做必然会更改此对象。所以您显式定义的任何属性或函数都将比在原始的原型中定义的那些属性或函数优先级要高。 </p>
<p>3.如果您显式设置了名为 prototype 的实例变量，JavaScript 就会在此实例中寻找任何未定义的实例变量或属性。这种查找是递归的：如果 在 prototype 内定义的实例不能找到属性或函数，它就会在其 原型中查找，依此类推。</p>
<p>那么，JavaScript 的继承模型到底是什么样的？这取决于您如何对它进行定义。您需要定义继承行为以便可以覆盖它。然而，从本质上讲，JavaScript 更像是一种函数式语言，而非面向对象的语言，它使用一些智能的语法和语义来仿真高度复杂的行为。其对象模型极为灵活、开放和强大，具有全部的反射性。有些人可能会说它太过灵活。而我的忠告则是，按具体作业的需要选择合适的工具。 </p>
<p><span style="text-decoration: underline;">10.2.5 本节总结</span> </p>
<p>JavaScript 对象模型构建在该语言的其他功能之上来支持大量的库，比如 Dojo。这种灵活性让每个框架能够以一种精细的方式更改对象模型。在某种程度上，这种灵活性是一种极大的缺点。它可以导致可怕的互操作性问题（尽管该语言的灵活性可以部分缓解这些问题）。 </p>
<p>而另一方面，灵活性又是一种巨大的优势。Java 语言一直苦于无法充分增强其灵活性，原因是它的基本对象模型还未灵活到可以被扩展的程度。一个典型的企业级开发人员为能够成功使用 Java 语言必须要学习很多东西，而新出现的一些优秀的开放源码项目和新技术，比如面向方面编程、Spring 编程框架和字节码增强库，则带来了大量要学的代码。 </p>
<p>最后，JavaScript 优秀的灵活性的确让您体会到了一些高阶语言的强大功能。当然您无需选择为每个项目或大多数项目都做这样的权衡和折衷。但了解一种语言的优势和劣势 &mdash;&mdash; 通过参考大量信息，而不仅仅基于广告宣传或公众意见 &mdash;&mdash; 会让您可以更好地控制何时需要使用以及何时不能使用这种语言。当您在修改 JavaScript Web 小部件时，您至少知道该如何让此语言发挥它最大的优势。</p>
<p>&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190186#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 14:01:39 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190186</link>
        <guid>http://lgf444.javaeye.com/blog/190186</guid>
      </item>
      <item>
        <title>DWR中文文档v0.9 10</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190184" style="color:red;">http://lgf444.javaeye.com/blog/190184</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p>&nbsp;<br /><strong>第9章. 范例精讲</strong><br /><span style="text-decoration: underline;">9.1 购物车</span><br />该文选自于IBM中国 作者：Philip McCarthy（软件开发顾问）<br />代码下载 描述 名字 大小 下载方法</p>
<p>描述 名字 大小 下载方法 DWR source code j-ajax3dwr.zip 301 KB <a href="ftp://www6.software.ibm.com/software/developer/library/j-ajax3dwr.zip" target="_blank">FTP</a> </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p><span style="text-decoration: underline;">&nbsp;9.1.1 介绍</span><br />我将采用一个基于在线商店的最小模型，这次包含一个基本的产品表示、一个可以包含产品商品的用户购物车以及一个从数据存储查询产品的数据访问对象（DAO）。Item 类与前一篇文章中使用的一样，但是不再实现任何手工序列化方法。图 1 说明了这个简单的设置：</p>
<p><img src="../../../topics/download/31a6bac8-1e0a-3594-8e8c-d7d5157ffa1e" height="280" alt="" style="vertical-align: middle;" width="450" /></p>
<p>&nbsp;说明 Cart、CatalogDAO 和 Item 类的类图 在这个场景中，我将演示两个非常简单的用例。第一，用户可以在目录中执行文本搜索并查看匹配的商品。第二，用户可以添加商品到购物车中并查看购物车中商品的总价。<br />&nbsp;<br /><span style="text-decoration: underline;">9.1.2 实现目录<br /></span>DWR 应用程序的起点是编写服务器端对象模型。在这个示例中，我从编写 DAO 开始，用它提供对产品目录数据存储的搜索功能。CatalogDAO.java 是一个简单的无状态的类，有一个无参数的构造函数。清单 1 显示了我想要公开给 Ajax 客户的 Java 方法的签名：<br />清单 1. 通过 DWR 公开的 CatalogDAO 方法&nbsp;</p>
<p>/** * Returns a list of items in the catalog that have names or descriptions * matching the search expression * * @param expression * Text to search for in item names and descriptions * @return list of all matching items */ public List&lt;Item&gt; findItems(String expression); /** * Returns the Item corresponding to a given Item ID * * @param id The ID code of the item * @return the matching Item */ public Item getItem(String id); </p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;接下来，我需要配置 DWR，告诉它 Ajax 客户应当能够构建 CatalogDAO 并调用这些方法。我在清单 2 所示的 dwr.xml 配置文件中做这些事：<br />清单 2. 公开 CatalogDAO 方法的配置 </p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://www.getahead.ltd.uk/dwr/dwr20.dtd"&gt; &lt;dwr&gt; &lt;allow&gt; &lt;create creator="new" javascript="catalog"&gt; &lt;param name="class" value="developerworks.ajax.store.CatalogDAO" /&gt; &lt;include method="getItem" /&gt; &lt;include method="findItems" /&gt; &lt;/create&gt; &lt;convert converter="bean" match="developerworks.ajax.store.Item"&gt; &lt;param name="include" value="id,name,description,formattedPrice" /&gt; &lt;/convert&gt; &lt;/allow&gt; &lt;/dwr&gt; </p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;<br />dwr.xml 文档的根元素是 dwr。在这个元素内是 allow 元素，它指定 DWR 进行远程的类。allow 的两个子元素是 create 和 convert。 </p>
<p><strong>create 元素</strong></p>
<p>&nbsp;create 元素告诉 DWR 应当公开给 Ajax 请求的服务器端类，并定义 DWR 应当如何获得要进行远程的类的实例。这里的 creator 属性被设置为值 new，这意味着 DWR 应当调用类的默认构造函数来获得实例。其他的可能有：通过代码段用 Bean 脚本框架（Bean Scripting Framework，BSF）创建实例，或者通过与 IOC 容器 Spring 进行集成来获得实例。默认情况下，到 DWR 的 Ajax 请求会调用 creator，实例化的对象处于页面范围内，因此请求完成之后就不再可用。在无状态的 CatalogDAO 情况下，这样很好。 </p>
<p>create 的 javascript 属性指定从 JavaScript 代码访问对象时使用的名称。嵌套在 create 元素内的 param 元素指定 creator 要创建的 Java 类。最后，include 元素指定应当公开的方法的名称。显式地说明要公开的方法是避免偶然间允许访问有害功能的良好实践 &mdash;&mdash; 如果漏了这个元素，类的所有方法都会公开给远程调用。反过来，可以用 exclude 元素指定那些想防止被访问的方法。 </p>
<p><strong>convert 元素</strong> </p>
<p>creator 负责公开用于 Web 远程的类和类的方法，convertor 则负责这些方法的参数和返回类型。convert 元素的作用是告诉 DWR 在服务器端 Java 对象表示和序列化的 JavaScript 之间如何转换数据类型。</p>
<p>&nbsp;DWR 自动地在 Java 和 JavaScript 表示之间调整简单数据类型。这些类型包括 Java 原生类型和它们各自的类表示，还有 String、Date、数组和集合类型。DWR 也能把 JavaBean 转换成 JavaScript 表示，但是出于安全性的原因，做这件事要求显式的配置。</p>
<p>&nbsp;清单 2 中的 convert 元素告诉 DWR 用自己基于反射的 bean 转换器处理 CatalogDAO 的公开方法返回的 Item，并指定序列化中应当包含 Item 的哪个成员。成员的指定采用 JavaBean 命名规范，所以 DWR 会调用对应的 get 方法。在这个示例中，我去掉了数字的 price 字段，而是包含了 formattedPrice 字段，它采用货币格式进行显示。</p>
<p>&nbsp;现在，我准备把 dwr.xml 部署到 Web 应用程序的 WEB-INF 目录，在那里 DWR servlet 会读取它。但是，在继续之前，确保每件事都按照希望的那样运行是个好主意。</p>
<p><br />&nbsp;<span style="text-decoration: underline;">9.1.3 测试部署</span></p>
<p>
<p>如果 DWRServlet 的 web.xml 定义把 init-param debug 设置为 true，那么就启用了 DWR 非常有帮助的测试模式。导航到 /{your-web-app}/dwr/ 会把 DWR 配置的要进行远程的类列表显示出来。在其中点击，会进入指定类的状态屏幕。CatalogDAO 的 DWR 测试页如图 2 所示。除了提供粘贴到 Web 页面的 script 标记（指向 DWR 为类生成的 JavaScript）之外，这个屏幕还提供了类的方法列表。这个列表包括从类的超类继承的方法，但是只有在 dwr.xml 中显式地指定为远程的才标记为可访问。</p>
</p>
<p><img src="../../../topics/download/6af1f70f-9646-3a6f-9d97-65bb15bf56ca" height="415" alt="" style="vertical-align: middle;" width="460" /></p>
<p>&nbsp;</p>
<p>可以在可访问的方法旁边的文本框中输入参数值并点击 Execute 按钮调用方法。服务器的响应将在警告框中用 JSON 标注显示出来，如果是简单值，就会内联在方法旁边直接显示。这个测试页非常有用。它们不仅允许检查公开了哪个类和方法用于远程，还可以测试每个方法是否像预期的那样工作。 如果对远程方法的工作感到满意，就可以用 DWR 生成的 JavaScript 存根从客户端代码调用服务器端对象。<br />&nbsp;<br /><span style="text-decoration: underline;">9.1.4 调用远程对象</span></p>
<p><br />远程 Java 对象方法和对应的 JavaScript 存根函数之间的映射很简单。通用的形式是 </p>
<p>JavaScriptName.methodName(methodParams ..., callBack)，其中 JavaScriptName 是 creator 的 javascript 属性指定的名称，methodParams 代表 Java 方法的 n 个参数，callback 是要用 Java 方法的返回值调用的 JavaScript 函数。如果熟悉 Ajax，可以看出这个回调机制是 XMLHttpRequest 异步性的常用方式。 在示例场景中，我用清单 3 中的 JavaScript 函数执行搜索，并用搜索结果更新用户界面。这个清单还使用来自 DWR 的 util.js 的便捷函数。要特别说明的是名为 $() 的 JavaScript 函数，可以把它当作 document.getElementById() 的加速版。录入它当然更容易。如果您使用过 JavaScript 原型库，应当熟悉这个函数。 </p>
<p>清单 3. 从客户机调用远程的 findItems() </p>
<p>/* * Handles submission of the search form */ function searchFormSubmitHandler() { // Obtain the search expression from the search field var searchexp = $("searchbox").value; // Call remoted DAO method, and specify callback function catalog.findItems(searchexp, displayItems); // Return false to suppress form submission return false; } /* * Displays a list of catalog items */ function displayItems(items) { // Remove the currently displayed search results DWRUtil.removeAllRows("items"); if (items.length == 0) { alert("No matching products found"); $("catalog").style.visibility = "hidden"; } else { DWRUtil.addRows("items", items, cellFunctions); $("catalog").style.visibility = "visible"; } } </p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;<br />在上面的 searchFormSubmitHandler() 函数中，我们感兴趣的代码当然是 catalog.findItems(searchexp, displayItems);。这一行代码就是通过网络向 DWR servlet 发送 XMLHttpRequest 并用远程对象的响应调用 displayItems() 函数所需要的全部内容。 displayItems() 回调本身是由一个 Item 数组表示调用的。这个数组传递给 DWRUtil.addRows() 便捷函数，同时还有要填充的表的 ID 和一个函数数组。表中每行有多少单元格，这个数组中就有多少个函数。按照顺序使用来自数组的 Item 逐个调用每个函数，并用返回的内容填充对应的单元格。 在这个示例中，我想让商品表中的每一行都显示商品的名称、说明和价格，并在最后一列显示商品的 Add to Cart 按钮。清单 4 显示了实现这一功能的单元格函数数组：<br />清单 4. 填充商品表的单元格函数数组 </p>
<p>/* * Array of functions to populate a row of the items table * using DWRUtil's addRows function */ var cellFunctions = [ function(item) { return item.name; }, function(item) { return item.description; }, function(item) { return item.formattedPrice; }, function(item) { var btn = document.createElement("button"); btn.innerHTML = "Add to cart"; btn.itemId = item.id; btn.onclick = addToCartButtonHandler; return btn; } ];</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;前三个函数只是返回 dwr.xml 中 Item 的 convertor 包含的字段内容。最后一个函数创建一个按钮，把 Item 的 ID 赋给它，并指定在点击按钮时应当调用名为 addToCartButtonHandler 的函数。这个函数是第二个用例的入口点：向购物车中添加 Item。<br />&nbsp;<br /><span style="text-decoration: underline;">9.1.5 实现购物车<br /></span>用户购物车的 Java 表示基于 Map。当 Item 添加到购物车中时，Item 本身作为键被插入 Map。 Map 中对应的值是一个 Integer，代表购物车中指定 Item 的数量。所以 Cart.java 有一个字段 contents，声明为 Map&lt;Item,Integer&gt;。 </p>
<p>使用复杂类型作为哈希键给 DWR 带来一个问题 &mdash;&mdash; 在 JavaScript 中，数组的键必须是标量的。所以，DWR 无法转换 contents Map。但是，对于购物车用户界面来说，用户需要查看的只是每个商品的名称和数量。所以我向 Cart 添加了一个名为 getSimpleContents() 的方法，它接受 contents Map 并根据它构建一个简化的 Map&lt;String,Integer&gt;，只代表每个 Item 的名称和数量。这个用字符串作为键的 map 表示可以由 DWR 的转换器转换成 JavaScript。</p>
<p>&nbsp;客户对 Cart 感兴趣的其他字段是 totalPrice，它代表购物车中所有商品的金额汇总。使用 Item，我还提供了一个合成的成员叫作 formattedTotalPrice，它是金额汇总的格式化好的 String 表示。</p>
<p><br /><strong>转换购物车 </strong></p>
<p>为了不让客户代码对 Cart 做两个调用（一个获得内容，一个获得总价），我想把这些数据一次全都发给客户。为了做到这一点，我添加了一个看起来有点儿怪的方法，如清单 5 所示：<br />清单 5. Cart.getCart() 方法 </p>
<p>/** * Returns the cart itself - for DWR * * @return the cart */ public Cart getCart() { return this; } </p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;虽然这个方法在普通的 Java 代码中可能完全是多余的（因为在调用这个方法时，已经有对 Cart 的引用），但它允许 DWR 客户让 Cart 把自己序列化成 JavaScript。 除了 getCart()，需要远程化的另一个方法是 addItemToCart()。这个方法接受目录 Item 的 ID 的 String 表示，把这个商品添加到 Cart 中并更新总价。方法还返回 Cart，这样客户代码在一个操作中就能更新 Cart 的内容并接收购物车的新状态。 清单 6 是扩展的 dwr.xml 配置文件，包含 Cart 类进行远程所需要的额外配置：<br />&nbsp;清单 6. dwr.xml 加入 Cart 类 </p>
<p>&lt;createcreator="new" scope="session" javascript="Cart"&gt; &lt;param name="class" value="developerworks.ajax.store.Cart"/&gt; &lt;include method="addItemToCart"/&gt; &lt;include method="getCart"/&gt; &lt;/create&gt; &lt;convertconverter="bean" match="developerworks.ajax.store.Cart"&gt; &lt;param name="include" value="simpleContents,formattedTotalPrice"/&gt; &lt;/convert&gt;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;<br />在这个版本的 dwr.xml 中，我添加了 Cart 的 creator 和 convertor。create 元素指定应当把 addItemToCart() 和 getCart() 方法远程化，而且重要的是，生成的 Cart 实例应当放在用户的会话中。所以，购物车的内容在用户的请求之间会保留。 Cart 的 convert 元素是必需的，因为远程的 Cart 方法返回的是 Cart 本身。在这里我指定在 Cart 的序列化 JavaScript 形式中应当存在的成员是 simpleContents 这个图和 formattedTotalPrice 这个字符串。 如果对这觉得有点儿不明白，那么只要记住 create 元素指定的是 DWR 客户可以调用的 Cart 服务器端方法，而 convert 元素指定在 Cart 的 JavaScript 序列化形式中包含的成员。 现在可以实现调用 Cart 的远程方法的客户端代码了。</p>
<p><br /><span style="text-decoration: underline;">&nbsp;9.1.6 调用远程的 Cart 方法</span><br />首先，当商店的 Web 页首次装入时，我想检查保存在会话中的 Cart 的状态，看是否已经有一个购物车了。这是必需的，因为用户可能已经向 Cart 中添加了商品，然后刷新了页面或者导航到其他地方之后又返回来。在这些情况下，重新载入的页面需要用会话中的 Cart 数据对自己进行同步。我可以在页面的 onload 函数中用一个调用做到这一点，就像这样：Cart.getCart(displayCart)。请注意 displayCart() 是一个回调函数，由服务器返回的 Cart 响应数据调用。 如果 Cart 已经在会话中，那么creator 会检索它并调用它的 getCart() 方法。如果会话中没有 Cart，那么 creator 会实例化一个新的，把它放在会话中，并调用 getCart() 方法。 清单 7 显示了 addToCartButtonHandler() 函数的实现，当点击商品的 Add to Cart 按钮时会调用这个函数：<br />清单 7. addToCartButtonHandler() 实现 </p>
<p>/* * Handles a click on an Item's "Add to Cart" button */ function addToCartButtonHandler() { // 'this' is the button that was clicked. // Obtain the item ID that was set on it, and // add to the cart. Cart.addItemToCart(this.itemId,displayCart); }</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;由 DWR 负责所有通信，所以客户上的添加到购物车行为就是一个函数。清单 8 显示了这个示例的最后一部分 &mdash;&mdash; displayCart() 回调的实现，它用 Cart 的状态更新用户界面：<br />&nbsp;<br />清单 8. displayCart() 实现 </p>
<p>/* * Displays the contents of the user's shopping cart */ function displayCart(cart) { // Clear existing content of cart UI var contentsUL = $("contents"); contentsUL.innerHTML=""; // Loop over cart items for (var item in cart.simpleContents) { // Add a list element with the name and quantity of item var li = document.createElement("li"); li.appendChild(document.createTextNode( cart.simpleContents[item] + " x " + item )); contentsUL.appendChild(li); } // Update cart total var totalSpan = $("totalprice"); totalSpan.innerHTML = cart.formattedTotalPrice; } </p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;在这里重要的是要记住，simpleContents 是一个把 String 映射到数字的 JavaScript 数组。每个字符串都是一个商品的名称，关联数组中的对应数字就是购物车中该商品的数量。所以表达式 cart.simpleContents[item] + " x " + item 可能就会计算出 &ldquo;2 x Oolong 128MB CF Card&rdquo; 这样的结果<br />&nbsp;</p>
<p><span style="text-decoration: underline;">9.1.7 演示结果<br /></span>图 3 显示了这个基于 DWR 的 Ajax 应用程序的使用情况：显示了通过搜索检索到的商品，并在右侧显示用户的购物车：<br />图 3. 基于 DWR 的 Ajax 商店应用程序的使用情况</p>
<p><img src="../../../topics/download/f2503f80-0648-39bd-bec3-fd85c3698cd2" height="241" alt="" style="vertical-align: middle;" width="572" /></p>
<p><br /><span style="text-decoration: underline;">9.1.8 总结<br /></span>DWR 的利弊 </p>
<p>调用批处理 </p>
<p>在 DWR 中，可以在一个 HTTP 请求中向服务器发送多个远程调用。调用 DWREngine.beginBatch() 告诉 DWR 不要直接分派后续的远程调用，而是把它们组合到一个批请求中。DWREngine.endBatch() 调用则把批请求发送到服务器。远程调用在服务器端顺序执行，然后调用每个 JavaScript 回调。 </p>
<p>批处理在两方面有助于降低延迟：第一，避免了为每个调用创建 XMLHttpRequest 对象并建立相关的 HTTP 连接的开销。第二，在生产环境中，Web 服务器不必处理过多的并发 HTTP 请求，改进了响应时间。</p>
<p>&nbsp;现在可以看出用 DWR 实现由 Java 支持的 Ajax 应用程序有多么容易了。虽然示例场景很简单，我实现用例的手段也尽可能少，但是不应因此而低估 DWR 引擎相对于自己设计 Ajax 应用程序可以节约的工作量。在前一篇文章中，我介绍了手工设计 Ajax 请求和响应、把 Java 对象图转化成 JSON 表示的全部步骤，在这篇文章中，DWR 替我做了所有这些工作。我只编写了不到 50 行 JavaScript 就实现了客户机，而在服务器端，我需要做的所有工作就是给常规的 JavaBean 加上一些额外方法。</p>
<p><br />当然，每种技术都有它的不足。同任何 RPC 机制一样，在 DWR 中，可能很容易忘记对于远程对象进行的每个调用都要比本地函数调用昂贵得多。DWR 在隐藏 Ajax 的机械性方面做得很好，但是重要的是要记住网络并不是透明的 &mdash;&mdash; 进行 DWR 调用会有延迟，所以应用程序的架构应当让远程方法的粒度比较粗。正是为了这个目的，addItemToCart() 才返回 Cart 本身。虽然让 addItemToCart() 作为一个 void 方<br />&nbsp;法可能更自然，但是这样的话对它的每个 DWR 调用后面都必须跟着一个 getCart() 调用以检索修改后的 Cart 状态。</p>
<p><br />对于延迟，DWR 在调用的批处理中有自己的解决方案。如果不能为应用程序提供适当粗粒度的 Ajax 接口，那么只要有可能把多个远程调用组合到一个 HTTP 请求中，就请使用调用批处理。</p>
<p>&nbsp;分离的问题 </p>
<p>从实质上看，DWR 在客户端和服务器端代码间形成了紧密的耦合，这有许多含义：首先，远程方法 API 的变化需要在 DWR 存根调用的 JavaScript 上反映出来。第二（也是最明显的），这种耦合会造成对客户端的考虑会渗入服务器端代码。例如，因为不是所有 Java 类型都能转化成 JavaScript，所以有时有必要给 Java 对象添加额外方法，好让它能够更容易地远程化。在示例场景中，我通过把 getSimpleContents() 方法添加到 Cart 来解决这个问题。我还添加了 getCart() 方法，它在 DWR 场景中是有用的，但在其他场景中则完全是多余的。由于远程对象粗粒度 API 的需要以及把某些 Java 类型转化成 JavaScript 的问题，所以可以看到远程 JavaBean 会被那些只对 Ajax 客户有用的方法&ldquo;污染&rdquo;。 </p>
<p>为了克服这个问题，可以使用包装器类把额外的特定于 DWR 的方法添加到普通 JavaBean。这意味着 JavaBean 类的 Java 客户可能看不到与远程相关联的额外的毛病，而且也允许给远程方法提供更友好的名称 &mdash;&mdash; 例如用 getPrice() 代替 getFormattedPrice()。图 4 显示的 RemoteCart 类对 Cart 进行了包装，添加了额外的 DWR 功能：<br />图 4. RemoteCart 为远程功能对 Cart 做了包装</p>
<p><img src="../../../topics/download/1f7b00e4-7d1a-3d00-98f3-3716a3507697" height="174" alt="" style="vertical-align: middle;" width="550" /></p>
<p>&nbsp;最后，需要记住：DWR Ajax 调用是异步的，所以不要期望它们会按照分派的顺序返回。在示例代码中我忽略了这个小问题，但是在这个系列的第一篇文章中，我演示了如何为响应加时间戳，以此作为保证数据到达顺序的一种简单手段。</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190184#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 13:59:41 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190184</link>
        <guid>http://lgf444.javaeye.com/blog/190184</guid>
      </item>
      <item>
        <title>DWR中文文档v0.9 09</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190182" style="color:red;">http://lgf444.javaeye.com/blog/190182</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>第8章. DWR进阶</strong><br /><span style="text-decoration: underline;">8.1 DWR Annotations<br /></span>DWR标注是用来代替dwr.xml或者与其一同工作的。<br /><span style="text-decoration: underline;">8.1.1 初始配置<br /></span>要使用DWR的标注，你需要在web.xml中配置不同的DWR控制器。 </p>
<pre name="code" class="java">&lt;servlet&gt; 
   &lt;description&gt;DWR controller servlet&lt;/description&gt; 
   &lt;servlet-name&gt;DWR controller servlet&lt;/servlet-name&gt; 
   &lt;servlet-class&gt; org.directwebremoting.servlet.DwrServlet          
   &lt;/servlet-class&gt; 
   &lt;init-param&gt; 
   &lt;param-name&gt;classes&lt;/param-name&gt; 
   &lt;param-value&gt; com.example.RemoteFunctions,    com.example.RemoteBean 
   &lt;/param-value&gt;
   &lt;/init-param&gt; 
&lt;/servlet&gt;</pre>
<p>&nbsp;servlet参数classes定义的时可以标注的类的全名，这些名字用逗号分割。<br /><span style="text-decoration: underline;">8.1.2 远程访问类<br /></span>要使一个简单的class可以成为远程访问类，你需要使用@Create和@RemoteMethod标注。</p>
<pre name="code" class="java">@Create
 public class RemoteFunctions {
    @RemoteMethod
     public int calculateFoo() { return 42; } 
}</pre>
<p>&nbsp;没有被@RemoteMethod标注的方法不能被远程访问。 要在Javascript使用不同于类型的名字，使用@Create标注的 </p>
<p>name 属性。</p>
<pre name="code" class="java">@Create(name = "Functions") 
public class RemoteFunctions {

}</pre>
<p>&nbsp;8.1.3 对象转换<br />要使一个简单的bean类可以被远程访问， 使用@Convert和@RemoteProperty标注:</p>
<pre name="code" class="java">@Convert 
public class Foo { 
     @RemoteProperty 
     private int foo; public int getFoo() { return foo; }
    @RemoteProperty 
    public int getBar() { return foo * 42; } 
}</pre>
<p>&nbsp;要使用复杂的转换器，使用@Convert标注的 converter 属性。</p>
<p><br /><span style="text-decoration: underline;">8.2 错误和异常处理</span></p>
<p><span style="text-decoration: underline;"><br />8.2.1 错误处理</span><br />在1.0版中错误处理规则有些bug，1.1修复了这些错误。 DWR中有一些全局的处理器(一个错误相关的, 叫做</p>
<p>errorHandler, 另一个警告相关的, 叫做warningHandler)。DWR会默认指定一些全局处理器。你可以这样的改变</p>
<p>全局级别的处理器： </p>
<pre name="code" class="java">DWREngine.setErrorHandler(handler);</pre>
<p>&nbsp;<br />你也可以指定单次调用和批量调用的错误和警告处理。例如，在调用元数据中: </p>
<pre name="code" class="java">Remote.method(params, { 
   callback:function(data) { ... }, 
   errorHandler:function(errorString, exception) { ... }
 });</pre>
<p>&nbsp;或者,在批量元数据中:</p>
<pre name="code" class="java">DWREngine.beginBatch();
 Remote.method(params, function(data) { ... });

// 其他的远程调用 
DWREngine.endBatch({ 
   errorHandler:function(errorString, exception) { ... } 
});</pre>
<p>&nbsp;<span style="text-decoration: underline;">8.2.2 异常<br /></span>DWR可以转换异常，这样他们会变成Javascript中的错误(他们可以被抛出，因为这可能在异步调用中发生)。 例</p>
<p>如，如果我们远程调用下面的Java类： </p>
<pre name="code" class="java">public class Remote { 
    public String getData() { throw new NullPointerException("message"); } 
}</pre>
<p>&nbsp;那么在Javascript中我们加入下面这些： </p>
<pre name="code" class="java">function eh(msg) { 
alert(msg); 
} 
{ 
DWREngine.setErrorHandler(eh);
 Remote.getData(function(data) { alert(data); });</pre>
<p>&nbsp;结果会通过eh()错误处理器调用alert窗口的，显示消息 &ndash; 例如调用异常的getMessage()得到的消息。</p>
<p><br /><span style="text-decoration: underline;">8.2.3 找出更多的信息</span><br />我们可以把整个异常传地到Javascript中。如果在dwr.xml中加入转换异常本身的能力： </p>
<pre name="code" class="java">&lt;convert converter="bean" match="my.special.FunkyException"/&gt;</pre>
<p>&nbsp;在这里例子中FunkyException被指定，因为它不仅仅包括一个消息，它还包括一些关于异常的额外数据。例如，</p>
<p>SQLException包含错误号，SAX异常包含错误的行和列等等。所以我们可以把上面的例如改为：</p>
<pre name="code" class="java">public class Remote { 
     public String getData() {
         Date when = new Date();
         throw new FunkyException("message", when); 
         // FunkyException有一个getWhen()方法 
    }
 }</pre>
<p>&nbsp;然后在Javascript中是这样的：</p>
<pre name="code" class="java">function eh(msg, ex) { 
  alert(msg + ", date=" + ex.when); 
} 
DWREngine.setErrorHandler(eh); 
Remote.getData(function(data) { alert(data); });</pre>
<p>&nbsp;结果会是一个eh()错误处理器调用的alert框，上面有这些信息："message, date=Mon Jan 01 2008 10:00:00 </p>
<p>GMT+0100" 被传递到错误处理器的ex对象会包含异常在服务端的所有属性，但是异常栈信息没有。</p>
<p><br /><span style="text-decoration: underline;">8.3 传递额外的数据到callback函数<br /></span>通常我们需要传递额外的数据到callback函数，但是因为所有的回调函数都只有一个参数(远程方法的返回结果)</p>
<p>，这就需要一些小技巧了。 解决方案就是使用Javascript的闭包特性。 例如，你的回调函数原本需要像这个样</p>
<p>子： </p>
<pre name="code" class="java">function callbackFunc(dataFromServer, dataFromBrowser) {
    // 用dataFromServer和dataFromBrowser做些事情...... 
}</pre>
<p>&nbsp;那么你可以像这个组织你的函数：</p>
<pre name="code" class="java">var dataFromBrowser = ...; 
// 定义一个闭包函数来存储dataFromBrowser的引用，并调用dataFromServer 
var callbackProxy = function(dataFromServer) { 
    callbackFunc(dataFromServer, dataFromBrowser);
 }; 
var callMetaData = { callback:callbackProxy }; 

Remote.method(params, callMetaData);</pre>
<p>&nbsp;换句话说，现在你作为callback函数传递过来的不是一个真正的callback，他只是一个做为代理的闭包，用来传</p>
<p>递客户端的数据。 你可以用更简介的形式：</p>
<pre name="code" class="java">var dataFromBrowser = ...; 
Remote.method(params, { 
   callback:function(dataFromServer) { 
     callbackFunc(dataFromServer, dataFromBrowser); 
  }
 });</pre>
<p><span style="text-decoration: underline;">&nbsp;8.4 从其他的URL读取数据<br /></span>如果你需要读取其他web应用程序生成的页面，并返回到Javascript中。非常简单。只要在你的Java类里面包括下</p>
<p>面这写代码：</p>
<pre name="code" class="java">public String getInclude() throws ServletException, IOException{
 return WebContextFactory.get().forwardToString("/forward.jsp"); 
}</pre>
<p>&nbsp;很明显你应该把"/forward.jsp"替换成你要forward到的页面的URL。这个URL必须以一个斜杠开始，因为它只是调</p>
<p>用 HttpRequest.forward() 。 你可以用这个方法在传递之前任何定制你的页面。<br />&nbsp;<br /><span style="text-decoration: underline;">8.5 安全</span><br />我们很谨慎的对待DWR的安全问题，并且认为有必要解释一下避免错误要做的事情。 首先DWR让你明确哪些是被远</p>
<p>程调用的，是如何被远程调用。原则就是DWR必须调用那些你明确允许的代码。 dwr.xml要求你为每一个远程类定</p>
<p>义一个'create'项。你还可以通过指定include和exclude元素来更精确的控制远程调用Bean中可以被调用的方法</p>
<p>。 除此之外如果你希望允许DWR在转换你的JavaBean到Javascript或者从Javascript转换到JavaBean时有一定的</p>
<p>许可限制，同样可以精确控制哪些Bean的属性可以被转换。 一个很明显但又必须指出的 &ndash; 不要在生产环境中打</p>
<p>开test/debug模式控制台。如何打开或关闭debug控制台在配置web.xml部分可以找到详细描述。<br /><strong> 审查 - DWR带来的最大好处<br /></strong>很值得对比一下DWR和Servlet、JSP或周围的其他web框架。 如果你要审查基于DWR的功能，那是非常简单的。看</p>
<p>看dwr.xml你就能得到一个哪些方法被暴露到外面的描述了。你也可以俯视全局用DWR可以访问哪些资源。 但是要</p>
<p>在其他系统里做这件事可不是这么容易。如果是Servlet你需要检查WEB-INF/web.xml文件，然后检查写在Servlet</p>
<p>中的request.getParameter(...)。如果是Struts和其他Framework你需要检查配置文件，然后顺着流程检查代码</p>
<p>，看请求信息出了什么问题。<br /><strong> 访问控制<br /></strong>DWR允许你通过两种基于J2EE的机制来进行访问控制。首先你可以基于J2EE角色定义DWR的访问。其次你可以在DWR</p>
<p>里面定义访问方法的角色。<br /><strong> 其他方面<br /></strong>DWR不允许你定义任何内部类的create和convert。这样设计是为了不出现意外的攻击来操作DWR的核心文件以提升</p>
<p>访问权限。<br /><strong> 风险<br /></strong>有什么机会可以让攻击者窥视你的系统呢？使用DWR你攻击者可以使服务器创建任何你在dwr.xml中指定的Java对</p>
<p>象的实例。并且(如果你用BeanConverter)Java类的任何方法、以及方法任何参数都是可见的。这些类的任何一个</p>
<p>属性都有可能是攻击者需要的。 如果你知道DWR是怎么工作的，这些都是很显而易见的结论，但是往往粗心会造</p>
<p>成问题。如果你创建了一个有appendStringToFile()方法的FileBean的类，而且用DWR把它暴露出去，那么你就给</p>
<p>了攻击者一个机会来填满你的文件系统。<br />&nbsp;<br />你必须时刻注意用了DWR以后，有没有给攻击者什么机会。 一般来说这样的情景让人感觉使用DWR是有风险的，但</p>
<p>是这样的问题在所有的传统web架构中都存在，只是在那些架构中这些不明显，所以就很难被修复。<br /> <strong>保证更加安全<br /></strong>这已经很安全了，那么你还能做什么来保证更加安全了？首先记住上面这些关于审查的内容，当web应用的其他地</p>
<p>方不安全时，即使它看上去很安全，过多的关注DWR是很愚蠢的。如果DWR让人感觉恐惧，那是因为它的问题都在</p>
<p>明处。所以第一步是多检查几遍传统架构的问题。 你可以通过把可远程访问的类放到不同的包里，并且使用代理</p>
<p>来防止DWR访问机制出问题。如果你愿意还可以再次检查基于角色的安全控制。这些内容只是在检查DWR已经为你</p>
<p>做的事情。 比多检查几次更好的方法是检查DWR的源码，保证它是在正确的工作。这些代码已经被很多人检查过</p>
<p>了，但多双眼睛总是有好处的。<br /><strong> 整合Acegi<br /></strong>DWR可以整合Acegi security framework。更多的信息见整合DWR和Acegi.<br />&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190182#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 13:57:24 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190182</link>
        <guid>http://lgf444.javaeye.com/blog/190182</guid>
      </item>
      <item>
        <title>DWR中文文档v0.9 08</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190180" style="color:red;">http://lgf444.javaeye.com/blog/190180</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>第7章. util.js 功能</strong><br />util.js包含了一些工具函数来帮助你用javascript数据(例如从服务器返回的数据)来更新你的web页面。</p>
<p>&nbsp;你可以在DWR以外使用它，因为它不依赖于DWR的其他部分。你可以下载整个DWR或者单独下载. </p>
<p>4个基本的操作页面的函数：getValue[s]()和setValue[s]()可以操作大部分HTML元素除了table，list和image。getText()可以操作select list。 </p>
<p>要修改table可以用addRows()和removeAllRows()。要修改列表(select列表和ul,ol列表)可以用addOptions()和removeAllOptions()。 </p>
<p>还有一些其他功能不是DWRUtil的一部分。但它们也很有用，它们可以用来解决一些小问题，但是它们不是对于所有任都通用的。<br /><span style="text-decoration: underline;">7.1 $()</span><br />$() 函数(它是合法的Javascript名字) 是从Protoype偷来的主意。 大略上的讲： $ = document.getElementById。 因为在Ajax程序中，你会需要写很多这样的语句，所以使用 $() 会更简洁。</p>
<p>&nbsp;通过指定的id来查找当前HTML文档中的元素，如果传递给它多个参数，它会返回找到的元素的数组。所有非String类型的参数会被原封不动的返回。这个函数的灵感来至于prototype库，但是它可以在更多的浏览器上运行。</p>
<p>&nbsp;可以看看DWRUtil.toDescriptiveString的演示。 从技术角度来讲他在IE5.0中是不能使用的，因为它使用了Array.push，尽管如此通常它只是用来同engine.js一起工作。</p>
<p>如果你不想要engine.js并且在IE5.0中使用，那么你最好为Array.push找个替代品。</p>
<p><br /><span style="text-decoration: underline;">7.2 addOptions and removeAllOptions</span></p>
<p><br />DWR的一个常遇到的任务就是根据选项填充选择列表。下面的例子就是根据输入填充列表。 下面将介绍 DWRUtil.addOptions() 的几种是用方法。 如果你希望在你更新了select以后，它仍然保持运来的选择，你要像下面这样做： </p>
<pre name="code" class="java">var sel = DWRUtil.getValue(id);
 DWRUtil.removeAllOptions(id); 
DWRUtil.addOptions(id, ...); 
DWRUtil.setValue(id, sel);</pre>
<p>&nbsp;如果你想加入一个初始的"Please select..." 选项那么你可以直接加入下面的语句：</p>
<pre name="code" class="java">DWRUtil.addOptions(id, \["Please select ..."]);</pre>
<p>&nbsp;DWRUtil.addOptions有5种模式<br />1. 数组: DWRUtil.addOptions(selectid, array) 会创建一堆option，每个option的文字和值都是数组元素中的值。</p>
<p><br />2. 对象数组 (指定text): DWRUtil.addOptions(selectid, data, prop) 用每个数组元素创造一个option，option的值和文字都是在prop中指定的对象的属性。</p>
<p><br />3. 对象数组 (指定text和value值): DWRUtil.addOptions(selectid, array, valueprop, textprop) 用每个数组元素创造一个option，option的值是对象的valueprop属性，option的文字是对象的textprop属性。</p>
<p><br />4. 对象: DWRUtil.addOptions(selectid, map, reverse)用每个属性创建一个option。对象属性名用来作为option的值，对象属性值用来作为属性的文字，这听上去有些不对。但是事实上却是正确的方式。如果reverse参数被设置为true，那么对象属性值用来作为选项的值。</p>
<p><br /> 5.对象的Map: DWRUtil.addOptions(selectid, map, valueprop, textprop) 用map中的每一个对象创建一个option。用对象的valueprop属性做为option的value，用对象的textprop属性做为option的文字。</p>
<p><br />6. ol 或 ul 列表: DWRUtil.addOptions(ulid, array) 用数组中的元素创建一堆li元素，他们的innerHTML是数组元素中的值。这种模式可以用来创建ul和ol列表。<br />这是网上的<a href="http://getahead.org/dwr/browser/lists" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.3 addRows and removeAllRows</span><br />DWR通过这两个函数来帮你操作table： DWRUtil.addRows() 和 DWRUtil.removeAllRows() 。这个函数的第一个参数都是table、tbody、thead、tfoot的id。一般来说最好使用tbody，因为这样可以保持你的header和footer行不变，并且可以防止Internet Explorer的bug。<br /> DWRUtil.removeAllRows()</p>
<pre name="code" class="java">DWRUtil.removeAllRows(id);</pre>
<p>&nbsp;<br />描述: 通过id删除table中所有行。 参数: id： table元素的id(最好是tbody元素的id)<br />&nbsp;<br /> DWRUtil.addRows()</p>
<pre name="code" class="java">DWRUtil.addRows(id, array, cellfuncs, [options]);</pre>
<p>&nbsp;<br />描述: 向指定id的table元素添加行。它使用数组中的每一个元素在table中创建一行。然后用cellfuncs数组中的没有函数创建一个列。单元格是依次用cellfunc根据没有数组中的元素创建出来的。 </p>
<p>DWR1.1开始，addRows()也可以用对象做为数据。如果你用一个对象代替一个数组来创建单元格，这个对象会被传递给cell函数。</p>
<p>&nbsp;参数: </p>
<p>id: table元素的id(最好是tbody元素的id) </p>
<p>array: 数组(DWR1.1以后可以是对象)，做为更新表格数据。 </p>
<p>cellfuncs: 函数数组，从传递过来的行数据中提取单元格数据。</p>
<p>&nbsp;options: 一个包含选项的对象(见下面) 选项包括:</p>
<p>&nbsp;rowCreator: 一个用来创建行的函数(例如，你希望个tr加个css). 默认是返回一个document.createElement("tr") cellCreator: 一个用来创建单元格的函数(例如，用th代替td). 默认返回一个document.createElement("td")<br />这是网上的<a href="http://getahead.org/dwr/browser/tables" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.4 getText</span><br />getText(id)和getValue(id)很相似。出了它是为select列表设计的。你可能需要取得显示的文字，而不是当前选项的值。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/gettext" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.5 getValue</span><br />DWRUtil.getValue(id)是 setValue()对应的"读版本"。它可以从HTML元素中取出其中的值，而你不用管这个元素是select列表还是一个div。</p>
<p>&nbsp;这个函数能操作大多数HTML元素包括select(去处当前选项的值而不是文字)、input元素(包括textarea)、div和span。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/getvalue" target="_blank">例子<br /></a>&nbsp;</p>
<p><span style="text-decoration: underline;">7.6 getValues</span><br />getValues()和getValue()非常相似，除了输入的是包含name/value对的javascript对象。name是HTML元素的ID，value会被更改为这些ID对象元素的内容。这个函数不会返回对象，它只更改传递给它的值。</p>
<p>&nbsp;从DWR1.1开始getValues()可以传入一个HTML元素(一个DOM对象或者id字符串)，然后从它生成一个reply对象。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/getvalues" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.7 onReturn</span><br />当按下return键时，得到通知。</p>
<p>&nbsp;当表单中有input元素，触发return键会导致表单被提交。当使用Ajax时，这往往不是你想要的。而通常你需要的触发一些Javscript。 </p>
<p>不幸的是不同的浏览器处理这个事件的方式不一样。所以DWRUtil.onReturn修复了这个差异。如果你需要一个同表单元素中按回车相同的特性，你可以用这样代码实现：</p>
<pre name="code" class="java">&lt;input type="text" onkeypress="DWRUtil.onReturn(event,submitFunction)"/&gt; 
&lt;input type="button" onclick="submitFunction()"/&gt;</pre>
<p>&nbsp;你也可以使用onkeypress事件或者onkeydown事件，他们做同样的事情。 </p>
<p>一般来说DWR不是一个Javascript类库，所以它应该试图满足这个需求。</p>
<p>不管怎样，这是在使用Ajax过程中一个很有用函数。 这个函数的工作原理是onSubmit()事件只存在于&lt;FORM ...&gt;元素上<br />这是网上的<a href="http://getahead.org/dwr/browser/util/onreturn" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.8 selectRange<br /></span>选择一个输入框中的一定范围的文字。 你可能为了实现类似"Google suggest"类型的功能而需要选择输入框中的一定范围的文字，但是不同浏览器间选择的模型不一样。这DWRUtil函数可以帮你实现。 DWRUtil.selectRange(ele, start, end)<br />这是网上的<a href="http://getahead.org/dwr/browser/util/selectrange" target="_blank">例子</a><br />&nbsp;<br /><span style="text-decoration: underline;">7.9 setValue<br /></span>DWRUtil.setValue(id, value)根据第一个参数中指定的id找到相应元素，并根据第二个参数改变其中的值。 这个函数能操作大多数HTML元素包括select(去处当前选项的值而不是文字)、input元素(包括textarea)、div和span。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/setvalue" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.10 setValues<br /></span>setValues()和setValue()非常相似，除了输入的是包含name/value对的javascript对象。name是HTML元素的ID，value是你想要设置给相应的元素的值。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/setvalues" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.11 toDescriptiveString</span><br />DWRUtil.toDescriptiveString()函数比默认的toString()更好。第一个参数是要调试的对象，第二个参数是可选的，用来指定内容深入的层次：</p>
<p>&nbsp;0: 单行调试 </p>
<p>1: 多行调试，但不深入到子对象。</p>
<p>&nbsp;2: 多行调试，深入到第二层子对象 </p>
<p>以此类推。一般调试到第二级是最佳的。 还有第三个参数，定义初始缩进。这个函数不应该被用于调式程序之外，因为以后可能会有变化。<br />这是网上的<a href="http://getahead.org/dwr/browser/util/todescriptivestring" target="_blank">例子</a></p>
<p><br /><span style="text-decoration: underline;">7.12 useLoadingMessage</span><br />这个方法将来可能被废弃，因为这个实现实在太专断了。为什么是红色，为什么在右上角，等等。唯一的真正答案就是：抄袭GMail。这里的建议是以本页面中的代码为模板，根据你的需求自定义。 你必须在页面加载以后调用这个方法(例如，不要在onload()事件触发之前调用)，因为它要创建一个隐藏的div来容纳消息。<br />&nbsp;<br />最简单的做法时在onload事件中调用DWRUtil.useLoadingMessage，像这样： </p>
<pre name="code" class="java">&lt;head&gt; 
&lt;script&gt;
 function init() { 
      DWRUtil.useLoadingMessage(); 
} 
&lt;/script&gt;
 ... 
&lt;/head&gt;
 &lt;body onload="init();"&gt; 
...</pre>
<p>&nbsp;可能有些情况下你是不能容易的编辑header和body标签(如果你在使用CMS，这很正常)，在这样的情况下你可以这样做： </p>
<pre name="code" class="java">&lt;script&gt;
 function init() { 
     DWRUtil.useLoadingMessage(); 
 } 
 if (window.addEventListener) { 
      window.addEventListener("load", init, false); 
 } else if (window.attachEvent) { 
        window.attachEvent("onload", init); 
 } else { window.onload = init; }
 &lt;/script&gt;</pre>
<p>&nbsp;下面这些是这个函数的代码，它对于你要实现自己的加载消息很有用。这个函数的主要内容是动态创建一个div(id是disabledZone)来容纳消息。重要的代码是当远程调用时使它显示和隐藏： </p>
<pre name="code" class="java">DWREngine.setPreHook(function() { 
     $('disabledZone').style.visibility = 'visible'; 
}); 
DWREngine.setPostHook(function() { 
     $('disabledZone').style.visibility = 'hidden'; 
}); 
This is fairly simple and makes it quite easy to implement your own "loading" message.

function useLoadingMessage(message) { 
     var loadingMessage; 
     if (message) loadingMessage = message; 
     else loadingMessage = "Loading";

 DWREngine.setPreHook(function() { 
     var disabledZone = $('disabledZone');
      if (!disabledZone) {
         disabledZone = document.createElement('div'); 
         disabledZone.setAttribute('id', 'disabledZone'); 
         disabledZone.style.position = "absolute"; 
         disabledZone.style.zIndex = "1000"; 
         disabledZone.style.left = "0px";
         disabledZone.style.top = "0px";
         disabledZone.style.width = "100%"; 
         disabledZone.style.height = "100%"; 
         document.body.appendChild(disabledZone);
         var messageZone = document.createElement('div'); 
         messageZone.setAttribute('id', 'messageZone'); 
         messageZone.style.position = "absolute"; 
         messageZone.style.top = "0px";
         messageZone.style.right = "0px"; 
         messageZone.style.background = "red"; 
         messageZone.style.color = "white"; 
         messageZone.style.fontFamily = "Arial,Helvetica,sans-serif"; 
         messageZone.style.padding = "4px"; 
         disabledZone.appendChild(messageZone); 
         var text = document.createTextNode(loadingMessage); 
         messageZone.appendChild(text); 
   } 
   else {
        $('messageZone').innerHTML = loadingMessage; 
           disabledZone.style.visibility = 'visible'; 
          } 
   });
   DWREngine.setPostHook(function() {
       $('disabledZone').style.visibility = 'hidden'; 
  }); 
}</pre>
<p>&nbsp;&nbsp;<br />下面的做法能简单的使用有加载消息图片：</p>
<pre name="code" class="java">function useLoadingImage(imageSrc) { 
   var loadingImage; 
   if (imageSrc) loadingImage = imageSrc; 
   else loadingImage = "ajax-loader.gif";
    DWREngine.setPreHook(function() {
       var disabledImageZone = $('disabledImageZone');
        if (!disabledImageZone) { 
          disabledImageZone = document.createElement('div');
          disabledImageZone.setAttribute('id', 'disabledImageZone');
          disabledImageZone.style.position = "absolute"; 
          disabledImageZone.style.zIndex = "1000"; 
          disabledImageZone.style.left = "0px"; 
          disabledImageZone.style.top = "0px"; 
          disabledImageZone.style.width = "100%"; 
          disabledImageZone.style.height = "100%";
          var imageZone = document.createElement('img'); 
          imageZone.setAttribute('id','imageZone');
          imageZone.setAttribute('src',imageSrc); 
          imageZone.style.position = "absolute";
          imageZone.style.top = "0px"; 
          imageZone.style.right = "0px"; 
          disabledImageZone.appendChild(imageZone);
          document.body.appendChild(disabledImageZone); 
     } 
     else {
        $('imageZone').src = imageSrc; 
        disabledImageZone.style.visibility = 'visible'; 
     } 
  });
   DWREngine.setPostHook(function() {
     $('disabledImageZone').style.visibility = 'hidden'; 
  }); 
}</pre>
<p>&nbsp;然后你就可以这样使用:useLoadingImage("images/loader.gif");</p>
<p><br /><span style="text-decoration: underline;">7.13 Submission box</span><br />h1 非util.js中的功能 这里有一些功能不适合加入到DWRUtil中。它们在解决一下特殊问题是很有用，但是他们还不够通用以适用任何场合。<br />修补浏览器事件 如果你创建了一个DOM元素，然后用addAttribute在这个元素上创建了一个事件，那么他们不能被正常的触发。你可以使用下面的脚本来遍历一个DOM树，并重新为他们绑定事件，这样他们就能正常的触发了。</p>
<p>&nbsp;把'click'改成你希望的事件。</p>
<pre name="code" class="java">DWREngine._fixExplorerEvents = function(obj) { 
   for (var i = 0; i &lt; obj.childNodes.length; i++) { 
      var childObj = obj.childNodes [i]; 
      if (childObj.nodeValue == null) {
          var onclickHandler = childObj.getAttribute('onclick'); 
          if (onclickHandler != null) { 
              childObj.removeAttribute('onclick'); 
              // If using prototype: 
              // Event.observe(childObj, 'click', new Function(onclickHandler)); 
              // Otherwise (but watch out for memory leaks): 
              if (element.attachEvent) { 
                 element.attachEvent("onclick", onclickHandler); 
              }
               else { 
                   element.addEventListener("click", onclickHandler, useCapture); 
                } 
            } 
             DWREngine._fixExplorerEvents(childObj); 
   } 
}</pre>
<p>&nbsp;&nbsp;</p>
          <br/>
          <span style="color:red;">
            <a href="http://lgf444.javaeye.com/blog/190180#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 06 May 2008 13:55:47 +0800</pubDate>
        <link>http://lgf444.javaeye.com/blog/190180</link>
        <guid>http://lgf444.javaeye.com/blog/190180</guid>
      </item>
      <item>
        <title>DWR中文文档v0.9 07</title>
        <author>lgf444</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://lgf444.javaeye.com">lgf444</a>&nbsp;
          链接：<a href="http://lgf444.javaeye.com/blog/190178" style="color:red;">http://lgf444.javaeye.com/blog/190178</a>&nbsp;
          发表时间: 2008年05月06日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><strong>第6章. engine.js 功能</strong><br />engine.js对DWR非常重要，因为它是用来转换来至动态生成的接口的javascript函数调用的，所以只要用到DWR的地方就需要它。 每一个页面都需要下面这些语句来引入主DWR引擎。 </p>
<pre name="code" class="java">&lt;script type="text/javascript" src="/[YOUR-WEB-APP]/dwr/engine.js"&gt;
 &lt;/script&gt;</pre>
<p>&nbsp;<span style="text-decoration: underline;">6.1 使用选项</span><br />下面这些选项可以通过 DWREngine.setX() 函数来设置全局属性。例如：</p>
<pre name="code" class="java">DWREngine.setTimeout(1000);</pre>
<p>&nbsp;或者在单次调用级别上(假设Remote被DWR暴露出来了)： </p>
<pre name="code" class="java">Remote.singleMethod(params, { 
   callback:function(data) { ... }, 
   timeout:2000 
});</pre>
<p>&nbsp;远程调用可以批量执行来减少反应时间。endBatch 函数中可以设置选项。</p>
<pre name="code" class="java">DWREngine.beginBatch();
 Remote.methodInBatch1(params, callback1); 
Remote.methodInBatch2(params, callback2); 
DWREngine.endBatch({
 timeout:3000 
});</pre>
<p>&nbsp;可以混合这几种方式，那样的话单次调用或者批量调用级别上的设置可以复写全局设置(就像你希望的那样)。当你在一个批量处理中多次设置了某个选项，DWR会保留最后一个。所以如果 Remote.singleMethod() 例子在batch里面，DWR会使用3000ms做为超时的时间。 callback和exceptionHandler两个选项只能在单次调用中使用，不能用于批量调用。 preHook和postHook选项两个选项是可添加的，就是说你可以为每一次调用添加多个hook。全局的preHook会在批量调用和单次调用之前被调用。同样全局的postHook会在单次调用和批量调用之后被调用。 如果以上叙述让你感到混乱，不用担心。DWR的的设计往往和你想象中的一样，所以其实这些并不复杂<br /><span style="text-decoration: underline;">&nbsp;6.2 选项索引<br /></span>下面是可用选项列表。 </p>
<p>Option&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Global&nbsp;&nbsp;&nbsp;&nbsp; Batch&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Summary<br />async&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.1&nbsp;&nbsp;&nbsp;&nbsp; 设置是否为异步调用，不推荐同步调用<br />headers&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.0&nbsp;&nbsp;&nbsp; &nbsp;在XHR调用中加入额外的头信息<br />parameters 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp; 可以通过Meta-datarequest.getParameter()取得的元数据<br />httpMethod&nbsp;2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp; 选择GET或者POST. 1.x中叫 &ldquo;verb&rdquo;<br />rpcType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp; 选择是使用xhr, iframe或者script-tag来实现远程调用. 1.x中叫&rdquo;method&rdquo;<br />skipBatch&nbsp;&nbsp;&nbsp; 1.0*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 某个调用是否应该设置为batch中的一部分或者直接的。这个选项和上面都有些</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 不同。 *没有setSkipBatch()方法，批量调用是通过beginBatch()</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 和&nbsp; endBatch()来控制的。</p>
<p><br />timeout&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设定超时时长，单位ms<br /><span style="text-decoration: underline;">6.2.1 处理器(Handler)</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp;&nbsp; Batch&nbsp;&nbsp; Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />errorHandler&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当出了什么问题时的动作。1.x中还包括服务端的异常。从2.0开始服务</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 端异常通过&rdquo;exceptionHandler&rdquo;处理<br />warningHandler&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当因为浏览器的bug引起问题时的动作，所以默认这个设置为null(关闭)<br />textHtmlHandler&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当得到不正常的text/html页面时的动作(通常表示超时)<br /><span style="text-decoration: underline;">6.2.2 调用处理器(Call Handler)</span></p>
<p>&nbsp;Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Batch&nbsp; &nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />callback&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用成功以后的要执行的回调函数，应该只有一个参数：远程调用得到的</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数据<br />exceptionHandler&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 远程调用失败的动作，一般是服务端异常或者数据转换问题。<br />&nbsp;<br /><span style="text-decoration: underline;">6.2.3 Hooks (一个batch中可以注册多个hook)</span> </p>
<p>Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp; &nbsp;Batch&nbsp;&nbsp;&nbsp; Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />preHook&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 远程调用前执行的函数<br />postHook&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 远程调用后执行的函数</p>
<p><br /><span style="text-decoration: underline;">6.2.4 全局选项(在单次调用或者批量调用中不可用)</span></p>
<p>&nbsp;Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Batch&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />ordered&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DWR是否支持顺序调用<br />pollType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 选择xhr或者iframe的反转Ajax<br />reverseAjax&nbsp;&nbsp; &nbsp;2.0&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是否查找inbound调用</p>
<p><br /><span style="text-decoration: underline;">6.2.5 废弃的选项</span> </p>
<p>Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Batch&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />verb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0废弃。使用 &ldquo;httpMethod&rdquo;代替<br />method&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 1.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.0废弃。使用 &ldquo;rpcType&rdquo;代替</p>
<p><br /><span style="text-decoration: underline;">6.2.6 未来版本的选项</span> </p>
<p>Option&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Global&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Batch&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;Call&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Summary<br />onBackButton&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;2.1?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户按了back按钮后的动作<br />onForwardButton&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.1?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.1?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用户按了forward按钮的动作</p>
<p><br /><span style="text-decoration: underline;">&nbsp;6.3 选项说明</span></p>
<p>&nbsp;</p>
<p><br /><span style="text-decoration: underline;">6.3.1 批量调用<br /></span>你可以使用batch来批量的执行远程调用。这样可以减少与服务器的交互次数，所以可以提交反应速度。</p>
<p>&nbsp;一个batch以 DWREngine.beginBatch() 开始 ，并以 DWREngine.endBatch() 结束。当 DWREngine.endBatch() 被调用，我们就结束了远程调用的分组，这样DWR就在一次与服务器的交互中执行它们。 </p>
<p>DWR会小心的处理保证所有的回调函数都会被调用，所以你可以明显的打开和关闭批处理。只要别忘了调用endBatch()，否则所有的远程调用永远的处于列队中。</p>
<p>&nbsp;警告：很明显，把一些远程调用放在一起执行也会产生一些影响。例如不能在batch里面执行同步调用。 所有的元数据选项，例如hooks, timeouts和errorHandlers都在batch级别的，而不是单次调用级别上的。所以如果一个batch中有两个调用设置了不同的超时，除了最后一个其他的都被忽略。</p>
<p><br /><span style="text-decoration: underline;">6.3.2 顺序调用</span></p>
<p>&nbsp;</p>
<p><br />因为Ajax一般是异步调用，所以远程调用不会按照发送的顺序返回。DWREngine.setOrdered(boolean) 允许结果严格按照发送的顺序返回。DWR在旧的请求安全返回以后才去发送新的请求。</p>
<p>&nbsp;我们一定需要保证请求按照发送的顺序返回吗？（默认为false）</p>
<p>&nbsp;警告 ： 把这个设置为true会减慢你的应用程序，如果一个消息丢失，浏览器就会没有响应。很多时候即使用异步调用也有更好的解决办法，所以在用这一功能之前先好好考虑一下。</p>
<p><br /><span style="text-decoration: underline;">6.3.3 错误警告和超时</span></p>
<p><br /> 处理错误和警告<br />当因为一些原因调用失败，DWR就会调用错误和警告handler(根据错误的激烈程度)，并传递错误消息。 你可以用这种方法来在alert窗口或状态来中显示错误信息。 你可以使用DWREngine.setErrorHandler(function)来改变错误处理方式，同样通过DWREngine.setWarningHandler(function)来改变警告处理方式。<br /> 设置超时<br />DWREngine.setTimeout()，单次调用和批量调用级别的元数据选项，允许你设置一个超时值。全局的DWREngine.setTimeout()函数设置全局超时。如果设置值为0(默认)可以将超时关掉。 setTimeout()的单位是毫秒。如果调用超时发生，错误处理器就会被调用。<br />51 / 92<br /> 一个例子:</p>
<pre name="code" class="java">Remote.method(params, { 
    callback:function(data) { alert("it worked"); },    
    errorHandler:function(message) { alert("it broke"); }, 
    timeout:1000 
});</pre>
<p>&nbsp;如果Remote.method()调用超过了1分钟还没有返回，"it broke"消息就会被显示。</p>
<p><br /><span style="text-decoration: underline;">6.3.4 远程调 Hooks</span></p>
<p>
<p><span style="text-decoration: underline;"><u>
<