<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>cleverpig</title>
    <description>思 想 的 自 由 才 是 真 正 的 自 由</description>
    <link>http://cleverpig.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>欢迎加入Matrix文档项目成为“福音”战士</title>
        <author>cleverpig</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cleverpig.javaeye.com">cleverpig</a>&nbsp;
          链接：<a href="http://cleverpig.javaeye.com/blog/138002" style="color:red;">http://cleverpig.javaeye.com/blog/138002</a>&nbsp;
          发表时间: 2007年11月05日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div align="center"><a href="http://www.matrix.org.cn/resource/article/2007-11-02/ae8c1199-890c-11dc-8166-7394e940be9c.html" target="_blank"><strong><span style="font-size: 14px;"><span style="color: red;">欢迎加入Matrix文档项目成为&ldquo;福音&rdquo;战士</span></span></strong></a><br />
</div>
<br />
<div align="center"><strong>发布者：matrix</strong><br />
</div>
<br />
<br />
目前Matrix正式开放五大开源文档项目，项目合作伙伴包括：<br />
<img src="http://static.zooomr.com/images/3647532_16381d843d_t.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>JavaWorld</strong><br />
<br />
<img src="http://static.zooomr.com/images/3647530_1b83623159_t.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>db4o</strong><br />
<br />
<img src="http://static.zooomr.com/images/3647531_fd13bc4aa2_o.png?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>JavaFX</strong><br />
<br />
<img src="http://static.zooomr.com/images/3648016_d8ec8b00fc_t.jpg?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>GlassFish</strong><br />
<br />
<img src="http://static.zooomr.com/images/3647541_cdfc1601c8_o.jpg?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>jMaki</strong><br />
<br />
欢迎大家加入并成为传播技术福音者！<br />
我们的目标：富有情感地进行翻译，更加广泛地撒播知识，让更多如我们曾经的初学者收益。<br />
我们的座右铭：我们不是机械的&ldquo;字幕&rdquo;组，而是富有激情的&ldquo;福音传播&rdquo;团队。<br />
<br />
加入方式详见下面项目列表：<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">JavaWorld中文同步项目： </span></span></strong><br />
<img src="http://static.zooomr.com/images/3647532_16381d843d_t.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">起始时间：</span></span></strong>2002年<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">项目简介：</span></span></strong>Matrix传统文档翻译项目，经过<a href="http://www.javaworld.com/" target="_new">javaWorld网站</a>官方正式授权。目前已经持续了近5年，翻译文档数量达2000余篇。<br />
组织模式：采用由Matrix管理员负责定期发布translate task list，翻译者自愿认领、并承诺完成期限的方式。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">获益模式：</span></span></strong>在翻译中享受学习知识的快乐、结识同行好友。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">适合人群：</span></span></strong>具有贡献精神的开发者、技术研究者、技术福音传播人士。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">db4o文档项目： </span></span></strong><br />
<img src="http://static.zooomr.com/images/3647530_1b83623159_t.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">起始时间：</span></span></strong>2007年10月<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">项目简介：</span></span></strong>Matrix作为<a href="http://www.db4o.com/" target="_new">db4o</a>在中国的伙伴，一直致力于db4o产品在国内的技术推广。本项目是通过db4o官方授权的中文化项目，致力于基于db4o 6.3版本的文档本地化。项目命名&mdash;chinesedb4o（<a href="http://code.google.com/p/chinesedb4o" target="_new">http://code.google.com/p/chinesedb4o</a>）；座右铭&mdash;我们不是机械的&ldquo;字幕&rdquo;组，而是富有激情的&ldquo;福音传播&rdquo;团队；工作范畴&mdash;db4o项目入门教学、最佳实践、原创技术文章等。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">授权方式：</span></span></strong><a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" target="_new">GNU General Public License v2</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">组织模式：</span></span></strong>参与者通过mail将加入请求提交给管理员cleverpig（<a href="mailto:greatcleverpig@gmail.com" target="_new">greatcleverpig@gmail.com</a>），由管理员负责任务安排、文章审核，并最终提交到db4o社区。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">获益模式：</span></span></strong>在翻译中享受学习知识的快乐、结识同行好友，而且贡献突出者每年都有机会免费参加db4o全球开发者大会。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">适合人群：</span></span></strong>db4o开发者、技术研究者、技术福音传播人士。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">JavaFX文档项目： </span></span></strong><br />
<img src="http://static.zooomr.com/images/3647531_fd13bc4aa2_o.png?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">起始时间：</span></span></strong>2007年6月<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">项目简介：</span></span></strong>Matrix作为Sun公司旗下<a href="https://openjfx.dev.java.net/" target="_new">JavaFX项目</a>的中文媒体合作伙伴，时刻关注着java脚本技术的动向。本项目是由cleverpig发起的JavaFX文档本地化项目，目前已经完成了大部分的翻译工作，目前正着手完成JavaFX中文网站的发布工作。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">组织模式：</span></span></strong>由cleverpig全权负责翻译工作，同时欢迎各位技术爱好者积极加入到JavaFX中文用户组（<a href="http://groups.google.com/group/CNJFXUG?hl=zh-CN" target="_new">http://groups.google.com/group/CNJFXUG?hl=zh-CN</a>）。cleverpig将定期发布新的翻译任务，大家可以通过发送邮件或者发帖的方式申请翻译任务。<br />
获益模式：在翻译中享受学习知识的快乐、结识同行好友，并能够参加有每年由Matrix和JavaFX联合组织的技术party。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">适合人群：</span></span></strong>JavaFX开发者、脚本技术研究者、技术福音传播人士。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">GlassFish-jMaki文档项目： </span></span></strong><br />
<img src="http://static.zooomr.com/images/3647541_cdfc1601c8_o.jpg?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">起始时间：</span></span></strong>2007年11月<br />
项目简介：<a href="https://ajax.dev.java.net/" target="_new">jMaki项目</a>是实现EJB3.1规范的<a href="http://glassfish.dev.java.net/" target="_new">GlassFish</a>的子项目之一，其目标是将Ajax和JSP tag技术完美的结合，以提升开发效率和用户体验。本文档项目由cleverpig发起，并经过GlassFish项目负责人Arun的正式授权。目前翻译工作正在着手进行。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">组织模式：</span></span></strong>由cleverpig负责翻译工作的分配，大家可以通过mail的方式加入和讨论。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">获益模式：</span></span></strong>在翻译中享受学习知识的快乐、结识同行好友，作为贡献者有机会参加GlassFish的相关技术活动。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">适合人群：</span></span></strong>Ajax&amp;Java Web开发者、技术研究者、技术福音传播人士。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">Matrix原创文档项目： </span></span></strong><br />
<img src="http://static.zooomr.com/images/3647836_46013895c5_t.jpg?r=360" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: blue;">起始时间：</span></span></strong>2002年<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">项目简介：</span></span></strong>Matrix一如既往支持的传统文档项目，目前已经持续了近5年，翻译文档数量达几百篇。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">组织模式：</span></span></strong>作者通过matrix网站页面自由提交，由Matrix管理员负责审核发布。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">获益模式：</span></span></strong>在翻译中享受学习知识的快乐、结识同行好友，成为网站&ldquo;名人堂&rdquo;成员。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><span style="font-size: 12px;"><span style="color: green;">适合人群：</span></span></strong>具有贡献精神的开发者、技术研究者、技术福音传播人士。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">加入特别说明（Matrix原创文档项目和JavaWorld中文同步项目除外）： </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于翻译工作，Matrix一直认为翻译文章的质量不能马虎的，尤其是文字表达上，因此cleverpig提供给各位三种选择，请注意Matrix原创文档项目和JavaWorld中文同步项目除外：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.你提供两个以上翻译作品或者链接给cleverpig，这样最好。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.如果手头没有的而有时间的话，烦请下载<a href="http://chinesedb4o.googlecode.com/files/db4o-6.3-tutorial-java.pdf" target="_blank">http://chinesedb4o.googlecode.com/files/db4o-6.3-tutorial-java.pdf</a>文档，并对其第一章进行翻译（仅三页，文字很少）并<a href="mailto:greatcleverpig@gmail.com" target="_new">mail给cleverpig</a>，主要考察一下文字描述上是否清晰达意。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.也许你并不喜欢上面的翻译小测试，你抽时间和cleverpig一起聊聊，当然你最好和他生活在同一个城市（北京）。:-)
          <br/>
          <span style="color:red;">
            <a href="http://cleverpig.javaeye.com/blog/138002#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>Mon, 05 Nov 2007 10:45:13 +0800</pubDate>
        <link>http://cleverpig.javaeye.com/blog/138002</link>
        <guid>http://cleverpig.javaeye.com/blog/138002</guid>
      </item>
      <item>
        <title>使用JXPath查询Java对象</title>
        <author>cleverpig</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cleverpig.javaeye.com">cleverpig</a>&nbsp;
          链接：<a href="http://cleverpig.javaeye.com/blog/79844" style="color:red;">http://cleverpig.javaeye.com/blog/79844</a>&nbsp;
          发表时间: 2007年05月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <a href="http://www.matrix.org.cn/resource/article/2007-05-14/a37d02e9-01f0-11dc-b893-bfacd340f814.html" target="_blank"><strong><span style="font-size: 14px;"><span style="color: red;"><center>使用JXPath查询Java对象<br />
&mdash;使用XPath表达式语言查询复杂的Java对象树</center></span></span></strong></a><br />
<br />
译者：<a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">cleverpig</a><br />
原文作者：Bart van Riel<br />
原文出处：<a href="http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html" target="_new">http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html</a><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在近期的一个项目中，我需要一种能够遍历Java对象树并从中提取对象属性值的简单方法。我希望找到一种提供 &ldquo;我所想要的id为X并且具有属性A的对象&rdquo;的简单工具，来顶替传统的不优雅方式&mdash;&mdash;通过巨大的if-else迭代器设置对对象树进行不断地遍历。 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;而<a href="http://jakarta.apache.org/commons/jxpath" target="_new">JXPath</a>正是我想找的那种对象查询工具。它是一个Apache公用组件：使用众所周知的<a href="http://www.w3schools.com/xpath" target="_new">XPath</a>表达式语言，能够对复杂的对象树进行查询。因此我将JXPath广泛地用在项目中，并且由于通过它的值提取算法（value-extraction algorithms）使应用获得了很大程度上的加速。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;但是，JXPath并没有被广泛地文档化。因为我正在深度探索此组件，所以我决定将我的发现写到一个内容详实的JXPath入门中，这个入门可以在<a href="http://www.tutorials.tfo-eservices.eu/" target="_new">我的站点</a>上找到。本文是这个入门的精简版本，它可以帮助你快速上手。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&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 />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注意：你可以从相关资源中下载本文的示例代码。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">示例模型</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了利用展示的目的，我们将使用一个简单的模型：一个具有多个部门（department）的公司（company），其中每个部门有多个雇员（employee）。下面是类模型：<br />
<center><img src="http://farm1.static.flickr.com/206/497483464_abcc9e19a2_o.gif" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="600" style="display: inline;" /><br />
<strong>Company类结构图</strong></center><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;很自然，我们需要一些用于该模型的样本数据：<center><img src="http://farm1.static.flickr.com/197/497485876_26cd7e4c1d.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /></center><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一切就绪了，现在就让我们开始使用JXPath吧！<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">执行简单的JXPath查询</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最简单的查询就是从对象树中提取单一对象。例如，为了取出Company对象，我们将使用到如下代码：<br />
<pre class="overflow">JXPathContext context = JXPathContext.newContext(company);<br />Company c = (Company)context.getValue(&quot;.&quot;);</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一行展示了如何建立一个上下文（context），它是对象树中所有JXPath的Xpath表达式的起点（与XML文档中的根节点类似）。第二行代码 执行了实际的查询。由于我们的上下文从company层开始，所以为了获取Company对象，我们简单地使用当前成员选择器&ldquo;.&rdquo;。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">使用判定（predicate）和变量</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Employee是Department的子对象。为了获取名为&ldquo;Johnny&rdquo;的Employee对象使用如下代码（注意此时Company仍然是上下文的起点）：<br />
<pre class="overflow">Employee emp = (Employee)context.getValue(&quot;/departmentList/employees[name='Johnny']&quot;);</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;代码大意为：&ldquo;从起点开始查询所有Department中name属性值为Johnny俄Employee对象&rdquo;。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面的代码说明了如何通过使用特定值来利用判定进行对象查询。判定的用法类似在SQL中使用WHERE子句。我们甚至能够将多个判定合并在一个查询中：<br />
<pre class="overflow">Employee emp = <br />&nbsp;&nbsp; (Employee)context.getValue(&quot;/departmentList/employees[name='Susan' and age=27]&quot;);</pre>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;除非使用特定的、一次性的查询，使用硬编码的查询通称是不合理的。最好定义一个能够使用不同参数执行的、可重用的查询。为了提供这种参数化的查询，JXPath支持在查询中使用变量。下面是使用变量的代码示例：<br />
<pre class="overflow">context.getVariables().declareVariable(&quot;name&quot;, &quot;Susan&quot;);<br />context.getVariables().declareVariable(&quot;age&quot;, new Integer(27));<br />Employee emp = <br />&nbsp;&nbsp; (Employee)context.getValue(&quot;/departmentList/employees[name=$name and age=$age]&quot;);</pre>
<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">在集合上进行迭代</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JXPath能够提供作用于查询获取的所有对象的迭代器，就像SQL中迭代结果集一样。下面的代码片段展示了如何对所有的Department进行迭代：<br />
<pre class="overflow">for(Iterator iter = context.iterate(&quot;/departmentList&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Department d = (Department)iter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;获取所有Department的所有Employee并进行迭代：<br />
<pre class="overflow">for(Iterator iter = context.iterate(&quot;/departmentList/employees&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Employee emp = (Employee)iter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了取得在销售部门的所有年龄大于30岁的Employee：<br />
<pre class="overflow"> for(Iterator iter = context.iterate<br />&nbsp;&nbsp;&nbsp;&nbsp; (&quot;/departmentList[name='Sales']/employees[age&gt;30]&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Employee emp = (Employee)iter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用变量的示例：<br />
<pre class="overflow">context.getVariables().declareVariable(&quot;deptName&quot;, &quot;Sales&quot;);<br />context.getVariables().declareVariable(&quot;minAge&quot;, new Integer(30));<br />for(Iterator iter = context.iterate(&quot;/departmentList<br />&nbsp;&nbsp;&nbsp;&nbsp; [name=$deptName]/employees[age&gt;$minAge]&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Employee emp = (Employee)iter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上的两个代码片段展示了多种在XPath查询中的使用判定的方式。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">指针</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指针是一个JXPath工具对象，它代表了在对象树中对对象位置的引用。例如，指针可以指向&ldquo;第二个department中的第一个employee&rdquo;。与直接从对象树中获取对象相比，指针提供了通过相关上下文执行相关查询的功能。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">使用指针</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;使用指向对象树中某个对象的指针几乎和直接获取对象的编码都很简单：<br />
<pre class="overflow">JXPathContext context = JXPathContext.newContext(company);<br />Pointer empPtr = context.getPointer(&quot;/departmentList[name='Sales']/employees[age&gt;40]&quot;);<br /><br />System.out.println(empPtr);<br />//output: /departmentList[1]/employees[1]<br /><br />System.out.println(((Employee)empPtr.getValue()).getName());<br />//output: Johnny</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请注意这里指针的输出展示了指针表示了对象的位置，而不是对象本身。也要注意指针指向的实际对象可以通过指针的getValue()方法获得。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;指针也具有迭代器：<br />
<pre class="overflow">for(Iterator iter = context.iteratePointers(&quot;/departmentList[name='Sales']<br />&nbsp;&nbsp;&nbsp;&nbsp; /employees[age&gt;30]&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Pointer empPtr = (Pointer)iter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">相对上下文和相对查询</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 由于指针表示了对象的位置，所以它能够被用作在整个对象树中进行&ldquo;航行&rdquo;的参考点。为了实现这一点，将指针作为被称为&ldquo;相对上下文&rdquo;的根对象（还记得起在 前面示例中使用Company作为根节点吗？）。从这个相对上下文出发，你可以通过通过执行相对查询来对整个对象树进行查询。指针提供的这一优势为查询提 供了很大灵活性，下面将举例说明。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先，这是建立相对上下文的方式：<br />
<pre class="overflow">for(Iterator iter = context.iteratePointers(&quot;/departmentList[name='Sales']<br />&nbsp;&nbsp;&nbsp;&nbsp; /employees[age&gt;30]&quot;); iter.hasNext();){<br />&nbsp;&nbsp; Pointer empPtr = (Pointer)iter.next();<br />&nbsp;&nbsp; JXPathContext relativeContext = context.getRelativeContext(empPtr);<br />}</pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在这段代码中，为连续的employee指针建立了一个新的相对上下文。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通过使用相对上下文，XPath能够在整个对象树上兄弟节点、子节点、父节点、祖父节点对象上执行查询：<br />
<pre class="overflow">//Current employee<br />Employee emp = (Employee)relativeContext.getValue(&quot;.&quot;);<br /><br />//Employee name<br />String name = (String)relativeContext.getValue(&quot;./name&quot;);<br /><br />//Name of the Department this Employee belongs to (a parent object)<br />String deptName = (String)relativeContext.getValue(&quot;../name&quot;);<br /><br />//Name of the Company this Employee belongs to (a 'grandparent' object)<br />String compName = (String)relativeContext.getValue(&quot;../../name&quot;);<br /><br />//All coworkers of this Employee (sibling objects)<br />for(Iterator empIter = relativeContext.iterate(&quot;../employees&quot;); empIter.hasNext();){<br />&nbsp;&nbsp; Employee colleague = (Employee)empIter.next();<br />&nbsp;&nbsp; //...<br />}</pre>
<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">总结</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JXPath是一种用于遍历、查询复杂对象树，并在其中进行&ldquo;航行&rdquo;的极其有用的工具。因为它将XPath表达式语言用于查询，因此大量关于XPath的参考资料有助于你建立高效、复杂的对象查询。甚至可以通过使用指针和相对上下文来增加更多的灵活性。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本文仅仅蜻蜓点水式地涉及到了JXPath的几个可能的方面，如果要获得更多的使用示例和深度的讨论，请阅读<a href="http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html#resources" target="_new">我写的完整的入门</a>。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">作者经历</span></span></strong><br />
<center><img src="http://farm1.static.flickr.com/204/497442889_6b576ba3f7.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /></center><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Bart van Riel已经涉足Java和面向对象时间达七年多了。他即是一位开发者又是一位面向对象和Java领域的培训师。目前他作为软件架构师和开源倡导者任职于全球IT咨询公司<a href="http://www.capgemini.com/" target="_new">Capgemini</a>。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">相关资源</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.javaworld.com/javaworld/jw-03-2007/jxpath/jw-03-jxpath.zip" target="_new">下载本文源代码</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.tutorials.tfo-eservices.eu/" target="_new">Bart van Riel编写的完整的JXPath入门</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://jakarta.apache.org/commons/jxpath" target="_new">Apache Commons JXPath</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.w3schools.com/xpath" target="_new">W3C提供的XPath入门</a>
          <br/>
          <span style="color:red;">
            <a href="http://cleverpig.javaeye.com/blog/79844#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>Mon, 14 May 2007 16:09:05 +0800</pubDate>
        <link>http://cleverpig.javaeye.com/blog/79844</link>
        <guid>http://cleverpig.javaeye.com/blog/79844</guid>
      </item>
      <item>
        <title>二十分钟Ruby入门</title>
        <author>cleverpig</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cleverpig.javaeye.com">cleverpig</a>&nbsp;
          链接：<a href="http://cleverpig.javaeye.com/blog/55826" style="color:red;">http://cleverpig.javaeye.com/blog/55826</a>&nbsp;
          发表时间: 2007年02月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <center><a href="http://www.matrix.org.cn/resource/article/2007-02-26/ff82b100-c542-11db-9ca0-c55b502ecb5b.html" target="_blank"><strong><span style="font-size: 14px;"><span style="color: red;">二十分钟Ruby入门</span></span></strong></a><br />
<br />
<strong>作者：<a href="http://blog.matrix.org.cn/page/cleverpig/" target="_new">cleverpig</a></strong><br />
<img src="http://farm1.static.flickr.com/156/402783523_6b4b7fafc4.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /></center><br />
<font size="2" face="Courier New">原文永久链接地址：</font><a href="http://www.matrix.org.cn/resource/article/2007-02-26/ff82b100-c542-11db-9ca0-c55b502ecb5b.html" target="_blank">http://www.matrix.org.cn/resource/article/2007-02-26/ff82b100-c542-11db-9ca0-c55b502ecb5b.html</a><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">介绍</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是一个短小的Ruby入门，完全读完只需20分钟。这里假设读者已经安装了Ruby，如果你没有安装的话，请在阅读文前访问<a href="http://www.ruby-lang.org/" target="_new">Ruby官方网站</a>进行<a href="http://www.ruby-lang.org/en/downloads/" target="_new">下载</a>并安装。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">交互式的Ruby</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;打开IRB（交互式Ruby外壳）：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你使用Mac OS X，那么请打开终端窗口输入irb；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你使用Linux，那么请打开shell输入irb；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你使用windows，那么请在开始菜单中找到Ruby-&gt;fxri，并执行它。<br />
<img src="http://farm1.static.flickr.com/127/402783526_0265941fc7.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" />&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok，在打开IRB之后，在其中输入&quot;Hello World&quot;。<br />
<img src="http://farm1.static.flickr.com/156/402783530_616782f058.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">Ruby听从你的安排!</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;发生了什么？我们刚才编写了世界上最短小的&ldquo;Hello World&rdquo;程序吗？这么说不太确切。第二行输出是IRB告诉我们：上一个表达式的评估结果。如果我们希望打印出&ldquo;Hello World&rdquo;，那么就还需要一点努力：<br />
<img src="http://farm1.static.flickr.com/161/402783535_3d586b8c65.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts 在Ruby中是一个简单的打印输出命令。后面的&ldquo;=&gt; nil&rdquo;表示什么？&mdash;&mdash;那是表达式的结果。Puts总是返回nil，这是Ruby中表示&ldquo;绝对无值&rdquo;（absolutely-positively- nothing value）的方式，看上去有些类似Java中的null。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">你的免费计算器在这里！</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;无需做什么，我们就能把IRB作为一个简单的计算器使用：<img src="http://farm1.static.flickr.com/146/402783539_bbdb9cd7f0.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这样就能计算3+2。够简单的！那么3乘以2如何？你可以在下面继续输入3*2，也可以回到上面（3+2处）重新修改你刚刚输入的计算公式。使用键盘上的向上键，使光标到达3+2那一行，再用左键移动光标到加号上，然后使用空格键进行修改。<img src="http://farm1.static.flickr.com/150/402783542_410f913368.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面，让我们尝试计算3的平方：<br />
<img src="http://farm1.static.flickr.com/151/402784608_a4e2227405.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" />&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Ruby语言中，**表示幂运算。那么如何计算平方根呢？<br />
<img src="http://farm1.static.flickr.com/152/402784611_db0e91d519.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ok，等一下，表达式中的sqrt(9)表示什么？你一定能猜到这是计算9的平方根。而Math表示什么？不要着急，下面就让我们进一步了解像Math这样的模块。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">模块&mdash;&mdash;按照主题分组的代码</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Math 是Ruby内建的数学模块。在Ruby中，模块提供了两种角色：一种角色是将类似的方法聚集在同一个&ldquo;家族&rdquo;名下。因此，Math也包括sin、tan这 样的方法。第二种角色是一个圆点（dot），它标记了消息的接收者。什么是消息？在上面的例子中，sqrt(9)便是消息，它意味着调用sqrt方法取出 9的平方根。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sqrt方法调用的结果是3.0。你可能注意到它并不是3。这是因为多数情况下，数字的平方根并不是整数，所以这里返回了一个浮点数。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么我们如何记住这些计算结果呢？&mdash;&mdash;将结果赋值给变量。<br />
<img src="http://farm1.static.flickr.com/155/402784614_0308c666bc.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">如何定义方法？</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何才能方便省事地随意输出字符串，而无需过多地劳烦我们的手指呢？&mdash;&mdash;我们需要定义一个方法！<br />
<img src="http://farm1.static.flickr.com/187/402784615_78757f66ab.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的代码中第一行&ldquo;def h&rdquo;标志着方法定义的开始。它告诉Ruby我们正在定义一个名为h的方法。下面一行是方法体：puts &quot;Hello World&quot;。最后，也就是第三行&ldquo;end&rdquo;通知Ruby我们完成了方法定义。Ruby的回应&ldquo;=&gt; nil&rdquo;告诉我们它已经知道我们定义了此方法。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">简短、重复地调用方法</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现在，让我们尝试多次执行这个方法：<br />
<img src="http://farm1.static.flickr.com/130/402784619_25ae90c97e.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" />&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;哈，这太容易了。在Ruby中调用某个方法只需将方法名提交给Ruby。当然，这是在方法没有参数的情况下。如果你愿意也可以添加一个空白的括号，但是这没有必要。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果我们想对某个人说hello而不是整个&ldquo;世界&rdquo;（world），那该怎么做？&mdash;&mdash;重定义h方法使它接收name参数。<br />
<img src="http://farm1.static.flickr.com/181/402784624_8c071b7a1f.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;嗯，现在看来工作正常。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">字符串中的奥秘</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&ldquo;#{name}&rdquo;是什么意思？这是Ruby在某个字符串中插入其它字符的方式。在大括号之间放入的字符串（这里是指name）将被外部的字符串代替。你也可以使用字符串类内建的capitalize方法来确保某人名字的首字母大写：<br />
<img src="http://farm1.static.flickr.com/164/402785322_4811643464.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面的代码有两个地方需要说明：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一，我们通过无括号的方式调用方法，因为括号是可选的；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第二，这里的默认参数值为&ldquo;World&rdquo;。也就是说在调用方法时如果没有提供name参数，则使用默认值&ldquo;World&rdquo;。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">进化为Greeter！</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们是否需要一个真正的问候者（greeter），他能记住你的名字、问候你、总是尊重地向你示好？那么这就最好建立一个&ldquo;Greeter&rdquo;类：<br />
<img src="http://farm1.static.flickr.com/136/402785324_624e380cef.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在上面的类代码中定义了一个称为Greeter的类和一些类方法，其中出现了一些新的&ldquo;关键词&rdquo;:请注意&ldquo;@name&rdquo;，它是类的实例变量，并对类中的所有方法（say_hi和say_bye方法）都有效。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何让Greeter类发挥作用？现在让我们来建立一个Greeter对象并使用它！<img src="http://farm1.static.flickr.com/155/402785326_b4b6758669.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Greeter类的实例对象g被建立后，它便接受了name参数（值为Pat）。那么我们能直接访问name吗？<br />
<img src="http://farm1.static.flickr.com/167/402785327_1cb9162321.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;看看上面的编译错误来看，这样直接访问name是行不通的。&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">窥视对象的内部</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对象中的实例变量总是隐藏于其中，但也并非毫无踪迹可寻，通过审查（inspect）对象便会见到它们。当然还有其它的访问方法，但是Ruby采用了良好的面向对象的方式来保持数据的隐藏性。<img src="http://farm1.static.flickr.com/175/402785331_3aca789d08.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 喔！这么多方法，可是我们只定义了两个方法呀？其它的方法又出自何处？不要担心，instance_methods方法列出了Greeter对象的所有方 法，其中包括父类中定义的方法。如果我们只想对Greeter类的方法进行列表的话，那么把false作为参数调用instance_methods方法 即可。false意味着我们不需要父类定义的方法。<br />
<img src="http://farm1.static.flickr.com/147/402785332_88d7a163fc.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;哈哈，这才是我们想要的。下面让我们看看Greeter对象能回应哪些方法：<img src="http://farm1.static.flickr.com/136/402786237_577ae319c7.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它知道say_hi、to_s（此方法将对象转换为字符串，是任何对象都必备的默认方法，很想Java中的toString方法），但它不知道name。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">随时修改类定义</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何才能查看或者修改name呢？Ruby提供了访问对象变量的简单方法：<img src="http://farm1.static.flickr.com/135/402786239_f2c178bdaa.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Ruby语言中，你能够多次打开某个类并修改它。而修改所带来的变化将应用在此后建立的任何新对象中、甚至现存的此类对象中。下面让我们建立一个新对象并访问它的@name属性。<img src="http://farm1.static.flickr.com/124/402786240_4a7bebd561.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们通过使用attr_accessor定义了两个方法：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&ldquo;.name&rdquo;用来获取name属性值；<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&ldquo;.name=&rdquo;用来设置namee属性值。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这很类似在Java类中访问被Public修饰的成员变量。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">向每个人问候，MegaGreeter不会漏掉一个人</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Greeter并不完美，因为它只能一次服务一个人。所以我们在这里设计一个能够一次向全世界、世界上每个人或者在名单中的人发送问候的MegaGreeter类。在这里，我们将放弃从前的IRB交互模式，转而改为编写Ruby程序文件。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;退出IRB的方法：输入&ldquo;quit&rdquo;、&ldquo;exit&rdquo;或者按下Control+D的组合键。<br />
<br />
<img src="http://farm1.static.flickr.com/130/402786242_3be5f25196_o.jpg" border="0" height="450" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="178" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;保存上面的代码到名为&ldquo;ri20min.rb&rdquo;的文件中，并使用&ldquo;ruby ri20min.rb&rdquo;的命令执行它。程序输出如下：<br />
<img src="http://farm1.static.flickr.com/153/402786243_cfc859343c.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面我们将深入了解一下上面的代码。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请注意上面代码中的起始行，它以#开头。在Ruby语言中，任何以#开头的行都被视为注释，并被解释程序忽略。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们的say_hi方法已经发生了变化：<br />
<img src="http://farm1.static.flickr.com/151/402786244_0d0384f569.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;它查找@names参数并按照其参数值作出决定：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果参数值为nil，它将打印三个圆点。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么@names.respond_to?(&quot;each&quot;)表示什么？<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">循环&mdash;&mdash;也叫迭代</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果@names对象具有each方法，那么它是可以被迭代的，进而可以对其进行迭代，从而问候列表中每个人。如果@names不具备each方法，则将它自动转换为字符串，并执行默认的问候。<img src="http://farm1.static.flickr.com/185/402786871_754495cbe7.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;each 是一种方法，它接受一个代码块（block of code），然后针对列表中的每个成员执行这个代码块，而在do和end之间的部分便是这个非常类似匿名函数的代码块。在管道符之间的变量是代码块的参数 name，它作为代码块参数被绑定为列表成员，而代码块puts &quot;Hello #{name}!&quot;将使用这个参数进行输出。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大多数其它的编程语言使用循环遍历列表，下面是C语言的循环示例：<img src="http://farm1.static.flickr.com/187/402786872_6372269031.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面的代码显然可以工作，但它不够&ldquo;优雅&rdquo;！你不得不用i这个多余的循环变量，还需要指出列表的长度，然后再解释如何遍历列表。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Ruby的迭代方式则更加优雅，所有的内部管理细节都隐藏在each方法中，你所需做的就是告诉它如何处理其中的每个成员。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">块，Ruby边缘的高亮点！</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;块(block)的真正优势在于：能够处理比列表更加复杂的对象。除了在方法中可以处理简单的内部管理细节外，你还能处理setup、teardown和所有错误，而不让用户有所察觉。<br />
<img src="http://farm1.static.flickr.com/166/402786875_cfb3557eb2.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;say_bye方法没有使用each，而是检查@names是否具有join方法，如果具有join方法，则调用join方法。否则它将直接打印@names变量。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此方法并不关心变量的实际类型，这依赖于它所支持的那些被称为&ldquo;<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=DuckTyping" target="_new">Duck Typing</a>&rdquo; 的方法：duck typing是动态类型的一种形式：变量的值自身隐含地决定了了变量的行为。这暗示了某个对象与其它实现了相同接口的对象之间是可交换的，不管对象之间是 否具有继承关系。鸭子测试（duck test）是对duck typing的一种形象比喻&mdash;&mdash;&ldquo;如果它走路像鸭子，那么也一定像鸭子一样呷呷地叫，那么它必定是一只鸭子&rdquo;。duck typing是某些编程语言的特性：如Smalltalk, Python, Ruby, ColdFusion。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Duck Typing的益处是无需对变量的类型进行严格地限制，如果某人使用一种新类型的列表类，只要它实现了与其它列表相同语义的join方法，便可以拿来使用。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">启动脚本</span></span></strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;文件上半部分是MegaGreeter类的代码，而后面剩下的部分则是对这些类方法的调用。而这是我们最后值得注意的一点：<br />
<img src="http://farm1.static.flickr.com/164/402786880_1747f86a44.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__FILE__ 是一个&ldquo;具有魔力&rdquo;的变量，它代表了当前文件名。$0是用于启动程序的文件名。那么代码&ldquo;if __FILE__ == $0&rdquo;便意味着检查此文件是否为将被使用的主程序文件。这样做可以使程序文件作为代码库使用，而不是可执行代码；但当此文件被用作执行文件时，也可被执 行。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">如何进一步学习Ruby</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;到此便是本入门的尾声了。当然还有许多值得浏览的：Ruby提供的各种不同的控制结构；块和yield的使用；模块作为<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=Mixin" target="_new">mixins</a>使用等。希望这次Ruby初体验能使你对Ruby更感兴趣。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em><span style="color: green;">注： mixin在面向对象编程语言中是一种提供某些功能给子类继承的类，但mixin并不能实例化。从某个mixin继承并不是什么特殊的形式，而它更适于收 集功能。某个子类甚至可以通过继承一个或者多个mixin选择继承它的全部或者多数功能。一个mixin能延期定义和绑定方法直到运行时，而属性和实例参 数也将在编译时才被定义。这不同于多数常见的方式：定义所有的属性、方法，并在编译时进行初始化。</span></em><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果这样的话，请埋头翻阅<a href="http://www.ruby-lang.org/en/documentation/" target="_new">我们的文档</a>，那里有免费、丰富的在线手册和入门资源。或者如果你喜欢在啃书本的话，可以到<a href="http://ruby-doc.org/bookstore" target="_new">图书列表</a>中选择一些你所需要的。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">相关资源</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.ruby-lang.org/en/downloads/" target="_new">下载Ruby</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.ruby-lang.org/en/documentation/" target="_new">Ruby官方文档</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://ruby-doc.org/bookstore" target="_new">Ruby出版图书列表</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://rubyeclipse.sourceforge.net/" target="_new">用于Eclipse的Ruby开发插件</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.ruby-lang.org/en/documentation/quickstart/" target="_new">Ruby in Twenty Minutes</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.javaeye.com/topic/52358" target="_new"> Ruby函数式风格编程</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.javaeye.com/topic/54600" target="_new">用block简化编程一例</a><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.javaeye.com/topic/54745" target="_new">迭代器+代码块，让代码更简短</a><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">感谢阅读此文</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请支持<u><a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">cleverpig</a></u>发起的<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=MatrixIAC" target="_new"><img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_08_110742_whRQwxOqao.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /></a>
          <br/>
          <span style="color:red;">
            <a href="http://cleverpig.javaeye.com/blog/55826#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>Mon, 26 Feb 2007 10:49:39 +0800</pubDate>
        <link>http://cleverpig.javaeye.com/blog/55826</link>
        <guid>http://cleverpig.javaeye.com/blog/55826</guid>
      </item>
      <item>
        <title>AJAX真的不安全？！</title>
        <author>cleverpig</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cleverpig.javaeye.com">cleverpig</a>&nbsp;
          链接：<a href="http://cleverpig.javaeye.com/blog/52950" style="color:red;">http://cleverpig.javaeye.com/blog/52950</a>&nbsp;
          发表时间: 2007年02月07日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <center><a href="http://www.matrix.org.cn/resource/article/2007-02-07/a5f2d5c6-b677-11db-82df-078095a5dcde.html" target="_blank"><strong><span style="font-size: 14px;"><span style="color: red;">AJAX真的不安全？！</span></span></strong></a><br />
<br />
作者：<a href="http://blog.matrix.org.cn/page/cleverpig/" target="_new">cleverpig</a><br />
<br />
<img src="http://farm1.static.flickr.com/159/382432449_dc2c13d0a5.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
</center><br />
<br />
原文永久链接：<a href="http://www.matrix.org.cn/resource/article/2007-02-07/a5f2d5c6-b677-11db-82df-078095a5dcde.html">http://www.matrix.org.cn/resource/article/2007-02-07/a5f2d5c6-b677-11db-82df-078095a5dcde.html</a><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">前言</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;日前网络中流行围绕AJAX和安全风险的讨伐声浪让人不绝于耳。这种火热的新技术已经被铺天盖地地应&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用在各种web应用（构建如<a href="http://www.gmail.com/" target="_new">Gmail</a>、<a href="http://maps.google.com/" target="_new">Google Maps</a>这些基于web的应用），但在其炙手可热的光环背后隐藏着一个黑暗的鬼怪&mdash;&mdash;AJAX正在为心怀恶意的hacker打开着后门。但这并不完全正确。恰好，目前几乎所有的web应用开发老手和安全专家都正在力图冲过冷嘲热讽式的取笑，触及到事情的真相：<strong><span style="color: rgb(255, 0, 0);">多数web站点都是不安全，但AJAX并不是罪魁祸首。</span></strong>尽管AJAX不能使web站点变得丝毫安全，但理解它能做些什么是非常重要的。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AJAX(Asynchronous JavaScript + XML)是web浏览器技术的集合体，它允许web页面内容飞速地更新而无需刷新页面。在使用AJAX的web页面背后，数据（通常格式化为XML，但也 可以是HTML、JavaScript等格式）在web服务器与客户端浏览器之间来回传输。比如在Gmail应用场景中，新的邮件信息被自动接收和显示。 在Google Maps应用场景中，用户可以通过鼠标拖拽的方式在地图中的街区之间穿梭漫游。这种执行异步数据传输的机制是一个嵌入在所有现代web浏览器内部的、被称 为XMLHTTPRequest(XHR)的软件库。XHR是web站点获得&ldquo;AJAX&rdquo;商标的关键。另一方面，它也是一些实现了&ldquo;奇思妙想&rdquo;的 JavaScript。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果你正在思考这究竟和安全有什么关系，那么你是正确的。AJAX技术使站点平滑地与用户交互， 并给用户带来更多的回应。而在web服务器上并没有任何改变，而安全焦点却应该着重在web服务器端。如果这是事实的话，那么我们每个人还考虑什么？在计 算机安全社区中，AJAX意味着大量攻击平面（attack surface）、骤增的复杂性、伪造请求、拒绝服务、跨站脚本（XSS）、依赖于客户端安全等等。而事实上，这些问题在AJAX出现之前就已经存在。并 且推荐给开发者的安全最佳实践也从没有因为AJAX的出现而改变过。如果你像我一样想知道到底哪些才是重要的，那么请让我们进行一次深入的讨论。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">名词解释</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong> Cross-site scripting (XSS):</strong>跨站脚本是一种经常出现在web应用中的计算机安全漏洞，它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞越过访问控制&mdash;&mdash;例如同源策略（<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=SameOriginPolicy" target="_new">same origin policy</a>）。近来，这种类型的漏洞被用来编写危害性更大的<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=Phishing" target="_new">phishing</a>攻击和利用浏览器漏洞。详细解释请看<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=XSS" target="_new">这里</a>。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong> Same Origin Policy:</strong>计 算机术语。这里译为&ldquo;同源策略&rdquo;。它是对于客户端脚本（尤其是JavaScript）的重要安全 度量标准。它首先出自Netscape Navigator2.0。之后历经Navigator2.01和Navigator2.02的修正完善。其目的在于防止某个文档或者脚本从多个不同 &ldquo;origin&rdquo;（源）装载。 这里的单词&ldquo;origin&rdquo;指使用域名、协议、端口。详细解释请看<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=Sameoriginpolicy" target="_new">这里</a>。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong> Cross-site request forgery（CSRF）:</strong>跨 站请求伪造，也被称成为&ldquo;one click attack&rdquo;或者session riding，通常缩写为CSRF或者XSRF，是一种对网站的恶意利用。尽管听起来像跨站脚本（XSS），但它与XSS非常不同，并且攻击方式几乎相 左。XSS利用站点内的信任用户，而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比，CSRF攻击往往不大流行（因此对其 进行防范的资源也相当稀少）和难以防范，所以被认为比XSS更具危险性。详细解释请看<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=CSRF" target="_new">这里</a>。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX导致大量的&ldquo;攻击平面&rdquo;?&mdash;&mdash;不！</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &ldquo;攻击平面&rdquo;一词被应用到通过对系统中开放攻击点的分析来度量安全的概念中。对于软件，这些点便是被第三方（用户）操作数据输入、输出的区域。显而易见， 具有相对越少的安全平面使应用越安全。同样明显的是，对于web应用或者任何应用，编写的功能点与攻击平面同样多。这并不和用户接口是否采用AJAX、 Flash、ASCII艺术字或者其它任何方式有关。AJAX是一种浏览器技术，且不在服务端执行。<strong>当AJAX驱使开发者公开地暴露更多的功能时，便可能引入新的&ldquo;服务器端&rdquo;漏洞&mdash;&mdash;你并不能责备AJAX。新的代码总意味着增加漏洞的风险。</strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;更进一步讲，从本人的经验看，使用AJAX技术的web应用在功能上并不具有比传统的标准web应用更多的复杂性。Google Maps就是一个比看似简单的<a href="http://sfbay.craigslist.org/" target="_new">craigslist</a>的 更简练的应用。Gmail也比Outlook Web Access更加轻巧。而且，使用AJAX进行Web应用设计（或者重新设计）将给在使用新式平台上（.NET，J2EE等）进行开发带来更多的机会。这 些平台与生俱来就更加安全、不会出现例如SQL注入、证书会话推算（Credential Session Prediction）、目录遍历等在上一代平台中常见的漏洞。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX使&ldquo;攻击平面&rdquo;更加难以发现？&mdash;&mdash;是，但又不是</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 没有测试结果的安全程序是不完整的。度量web站点安全的最常见方式便是通过模拟攻击&mdash;&mdash;成千上万的攻击（也就是漏洞评估）。漏洞评估能被手工执行，也可 以使用自动化扫描工具，或者两者兼而有之。在漏洞评估过程的第一步就是定位web应用的输入点或者&ldquo;攻击平面&rdquo;。因此，一个完整的漏洞评估需要发现所有可 能的漏洞。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自动化抓取整个web站点、映射链接是漏洞评估的标准行为。此方法对于某些站点工作很好，对另一些站点则无能 为力，而对其余站点的效果在前两者之间。对使用大量JavaScript、Flash、ActiveX、Applet和AJAX的新式站点来讲，进行漏洞 评估的挑战是网站中的链接是即时生成或者在复杂的客户端代码中动态生成的。分析出这些链接非常困难，有时几乎不可能。因此自动化扫描成为了检验AJAX站 点安全性的一种不大可靠的方法。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另一方面依靠人工可以相对轻松地详细审视代码并推断代码之间的关系。<strong>有时，JavaScript源代码中记录了web站点所有的输出区域，甚至XML web服务的细节，当然这不但对心怀善意者有用，而且对心存恶意者也同样有用处。</strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在一个平常的web站点中，没有这样的资源，而漏洞评估程序必须依赖于链接抓取的方式。<strong>因此这里做出的结论便是：AJAX并没有削弱web站点的安全性，但它使评估安全工作面临更多的挑战。</strong><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX导致&ldquo;拒绝服务&rdquo;？&mdash;&mdash;这并非事实</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于AJAX的web站点被要求设计成为使用大量零碎的HTTP请求，而不是少量的、大规模HTTP请求的应用。例如，Google Suggest在每个用户敲击键盘时，可以发出微小的HTTP请求来执行自动单词完成工作。这里假定1000用户同时使用此系统，采用这种AJAX快速触 发HTTP请求的模式将会明显地提高系统处理请求的压力。这便是潜在的拒绝服务场景。假定这是可能的，但这是谁的过错呢？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>以本人的观点，这个问题不是因AJAX、甚至不良的软件设计策略而引起的、而是缺乏恰当的实现和质量测试而造成的。</strong>针对此问题的解决方案便是优化配置或者增加更多的web服务。现实中，如果某人想发动Dos攻击，他将使用巨大的HTTP流量作为洪流冲击网络，而不管web站点是否采用AJAX。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX依赖客户端安全？&mdash;&mdash;不！</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们回到web应用安全上来。Web应用必须从不信任客户端（web浏览器）。这是无论web页面接口使用JavaScript、Flash、 ActiveX、Applet、AJAX或者其它协议、语言都适用的&ldquo;福音&rdquo;。每个开发者应该谨慎对待HTTP代理，因为它能改变HTTP请求中的任何东 西、甚至是那些被XHR生成的数据。<strong>最谨慎的做法是确保所有安全检查都在server上进行，无一例外。</strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>这意味着我们不应该使用客户端安全检查吗？不，正相反。</strong>我推荐在form中和其它业务处理流中使用客户端安全检查，因为它通过更多的反馈完善了用户体验。把用户在电话号码field中输入的字符传送到服务器进行检查的做法是没有必要的。而且通过将部分处理时间推给客户端可以减轻服务器的负载。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX导致糟糕的安全决策？&mdash;&mdash;有几分可能。</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Web2.0 站点经常囊括了来自一个或者多个第三方站点的数据，这称为&ldquo;mash-up&rdquo;。AJAX开发者首选的做法是使用直接从第三方站点&ldquo;拉&rdquo;数据给用户，这样可 以减少没必要的带宽浪费。但是这对XHR技术来讲是不可能的。XHR具有内建在浏览器中的安全保护机制，它防止位于A站点的用户浏览器向B站点发起连接。 这有助于防止用户受到那些在页面中使用JavaScript代码强迫用户下载银行账户信息的恶意站点的威胁。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;而Web开 发者并不愿抑制革新，他们完成了一套能够使用XHR访问第三方站点的应用：Web开发者在web服务器上建立一个本地HTTP代理。为了使客户端能够从第 三方站点&ldquo;拉&rdquo;数据，他们通过本地代理将XHR直接传送给目的服务器。下面便是web浏览器生成的请求示例：<br />
<br />
<pre class="overflow">http://websiteA/proxy?url=http://websitesB/ </pre>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;A站点接收进入的请求，而后&ldquo;proxy&rdquo;web应用通过&ldquo;URL&rdquo;参数发送请求给B站点。通过使用代理，开发者可以使用XHR作跨域请求。因为A站点不能直接连接到B站点，所以XHR不能发送用户授权cookie到B站点， <strong>因此这里并不存在跨域请求伪造（CSRF）的威胁。</strong>这里安全问题时A站点上存在一个没有进行限制的HTTP代理。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;攻击者喜欢寻找开放的代理，因为他们能够从那里发起攻击，而不必暴露自己的行踪。代理的使用应被仔细地控制，对连接代理的站点和此站点的行为进行限制。<strong>我认为问题出在开发者忽视了安全控制，而不是AJAX。</strong><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX使跨站脚本攻击（XSS）更甚？&mdash;&mdash;我希望不是。</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AJAX使得XSS攻击更甚？记得在2006年<a href="http://www.blackhat.com/" target="_new">BlackHat</a>发表的一篇<a href="http://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Grossman.pdf" target="_new">《Hacking Intranet Websites from the Outside》</a>中演示了JavaScript恶意代码如何获取内网NAT后的IP地址、扫描端口、使web服务器记录系统失明、盗取浏览器历史记录、利用处于内网的web接口。华盛顿邮报称此&ldquo;使人不安&rdquo;。所有的演示代码没有使用AJAX编写，都是古老的JavaScript。<br />
<br />
XHR能够发起在同一域下的任何HTTP请求，并浏览回应数据。简单的JavaScript能够完成同样的请求，而无需&ldquo;域&rdquo;的限制，但它不能浏览回应数据。<strong>这意味着如果某个用户位于A网站，XHR不能强迫用户连接到B网站、并读取B网站的数据。但是简单的JavaScript代码能够做到。从这个角度来看，XHR是如等的安全！</strong><br />
<br />
对于JavaScript的深入研究已经导致了新生的恶意代码能够发现哪些服务器具有潜在的XSS漏洞安全问题。更为直接的例子就是，<a href="http://www.ccw.com.cn/news2/secure/htm2005/20051018_15P0X.htm" target="_new">Samy蠕虫曾经击倒了MySpace</a>，<a href="http://digi.it.sohu.com/20060613/n243713229.shtml" target="_new">利用XHR的JS-Yamaner也在Yahoo上肆虐繁殖过</a>。但是这些攻击都采用简单的JavaScript。AJAX与这种场景毫无干系。我们所能做的是寻找和修复在web应用中的XSS漏洞。<a href="http://www.whitehatsec.com/" target="_new">WhiteHat</a>的安全白皮书<a href="http://www.microsoft.com/technet/security/tools/mbsa2/default.mspx#EEAA" target="_new">《Cross-Site Scripting Worms and Viruses》</a>中提供了更丰富的资源。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">AJAX改变了安全最佳实践？&mdash;&mdash;不。</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>如果某个web应用存在漏洞，那么无论采用何种技术进行开发，它都是不安全的。如果某个web应用具备良好的设计，&ldquo;不安全的AJAX&rdquo;怎么也削弱不了它的安全性。<br />
</strong><br />
下面是使web应用安全的5点提示：<br />
<br />
1）设计安全。进行从安全出发、时刻关注安全的设计：在软件开发生命周期中每个阶段中将安全性作为一个组件对待。<br />
<br />
2）可靠的输入验证。从不信任客户端。<br />
<br />
3）使用可靠的软件库。从加密到会话管理，最好尽量使用经过全面的测试的组件。不要重新发明轮子和重复别人的错误。<br />
<br />
4）安全配置。web站点的每个组件都应该使用职责相互分离的配置，最小化权限，屏蔽掉不使用的特性，禁用错误信息。<br />
<br />
5）寻找和修复漏洞。持续化的漏洞评估是预防攻击者访问公司和客户数据的最佳方式。因为你不能控制那些无法测试到的。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;遵守上面的5点提示是使Web应用走向安全的第一步。第二步则是数据验证。没有哪家公司指望能编写没有任何缺陷的代码，或者具有连续不断定位web应用中所有安全漏洞能力的有效工具。这就是<a href="http://www.whitehatsec.com/" target="_new">WhiteHat</a>建立<a href="http://www.whitehatsec.com/services.shtml" target="_new">WhiteHat Sentinel</a>这个提供持续的漏洞评估和web应用管理服务的原因。<br />
<br />
记住基本原则，使用深层防御，你的在线业务将更安全。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">针对XSS蠕虫和病毒的最佳防范方法</span></span></strong><br />
<br />
<center> <img src="http://farm1.static.flickr.com/188/382432451_67230c1455.jpg?v=0" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>我们如何吃下这袋中甜点？</strong><br />
</center><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 近十年来，反病毒社区已经建立了依靠快速反应时间来限制蠕虫和病毒所造成的危害的机制。随着新一代恶意软件滋生速度的提高，几百万、甚至上亿美元在病毒突 发事态趋于稳定之前白白损失掉了。这种情况要求我们采取措施在病毒刚发作时对病毒的爆发进行辨别，防止病毒在第一发生地点扩大化。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了缩小新种类病毒和蠕虫的危害，下面列举出了一些防范步骤供web用户、web开发者参考：<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">web用户</span></span></strong><br />
<br />
1.在电子邮件或者即时通讯软件中点击链接时需要格外小心：留心可疑的过长链接，尤其是它们看上去包含了HTML代码。如果对其产生怀疑，可以在浏览器地址栏中手工输入域名，而后通过该页面中的链接浏览你所要的信息。<br />
<br />
2.对于XSS漏洞，没有哪种web浏览器具有明显的安全优势。也就是Firefox也同样不安全。为了获得更多的安全性，可以安装一些浏览器插件：比如Firefox的<a href="https://addons.mozilla.org/firefox/722/" target="_new">NoScript</a>或者<a href="http://toolbar.netcraft.com/" target="_new">Netcraft工具条</a>。<br />
<br />
3.然而，世界上没有&ldquo;100%的有效&rdquo;。尽量避免访问有问题的站点：比如提供hack信息和工具、破解软件、成人照片的网站。这些类型的网站会利用浏览器漏洞并危害操作系统。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">web应用开发者</span></span></strong><br />
<br />
1.对于开发者，首先应该把精力放到对所有用户提交内容进行可靠的输入验证上。这些提交内容包括URL、查询关键字、http头、post数据等。只接受在你所规定长度范围内、采用适当格式、你所希望的字符。阻塞、过滤或者忽略其它的任何东西。<br />
<br />
2.保护所有敏感的功能，以防被<a href="http://en.wikipedia.org/wiki/Wikipedia:Bots" target="_new">bots</a>自动化或者被第三方网站所执行。实现<a href="http://shiflett.org/articles/security-corner-dec2004" target="_new">session标记（session tokens）</a>、<a href="http://www.captcha.net/" target="_new">CAPTCHA系统</a>或者HTTP引用头检查。<br />
<br />
3. 如果你的web应用必须支持用户提供的HTML，那么应用的安全性将受到灾难性的下滑。但是你还是可以做一些事来保护web站点：确认你接收的HTML内 容被妥善地格式化，仅包含最小化的、安全的tag（绝对没有JavaScript），去掉任何对远程内容的引用（尤其是样式表和JavaScript）。 为了更多的安全，请使用<a href="http://msdn.microsoft.com/workshop/author/dhtml/httponly_cookies.asp" target="_new">httpOnly的cookie</a>。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">参考资源</span></span></strong><br />
<br />
<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=XSS" target="_new">什么是跨站脚本（XSS）？</a><br />
<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=CSRF" target="_new">什么是跨站请求伪造（CSRF）？</a><br />
<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=Sameoriginpolicy" target="_new">同源策略的定义</a><br />
<a href="http://www.whitehatsec.com/home/resources/articles/files/myth_busting_ajax_insecurity.html" target="_new">Myth-Busting AJAX (In)security</a><br />
<a href="http://www.blackhat.com/presentations/bh-usa-06/BH-US-06-Grossman.pdf" target="_new">BlackHat于2006年发表的《Hacking Intranet Websites from the Outside》</a><br />
<a href="http://www.microsoft.com/technet/security/tools/mbsa2/default.mspx#EEAA" target="_new">WhiteHat的安全白皮书《Cross-Site Scripting Worms and Viruses》</a><br />
<a href="http://shiflett.org/articles/cross-site-request-forgeries" target="_new">Security Corner: Cross-Site Request Forgeries</a><br />
<a href="http://www.captcha.net/" target="_new">CAPTCHA项目官网</a><br />
<a href="http://msdn.microsoft.com/workshop/author/dhtml/httponly_cookies.asp" target="_new">httpOnly的cookie<br />
</a><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">感谢阅读此文</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;请支持<u><a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">cleverpig</a></u>发起的<a href="http://wiki.matrix.org.cn/Wiki.jsp?page=MatrixIAC" target="_new"><img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_08_110742_whRQwxOqao.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /></a>
          <br/>
          <span style="color:red;">
            <a href="http://cleverpig.javaeye.com/blog/52950#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, 07 Feb 2007 15:01:23 +0800</pubDate>
        <link>http://cleverpig.javaeye.com/blog/52950</link>
        <guid>http://cleverpig.javaeye.com/blog/52950</guid>
      </item>
      <item>
        <title>Think in Pushlet </title>
        <author>cleverpig</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://cleverpig.javaeye.com">cleverpig</a>&nbsp;
          链接：<a href="http://cleverpig.javaeye.com/blog/47661" style="color:red;">http://cleverpig.javaeye.com/blog/47661</a>&nbsp;
          发表时间: 2007年01月16日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <center><font size="3"><a href="http://www.matrix.org.cn/resource/article/2007-01-16/bcc2c490-a502-11db-8440-755941c7293d.html" target="_blank"><strong><span style="font-size: 14px;"><span style="color: red;">Think in Pushlet </span></span></strong></a></font><br />
<br />
作者：<u><a href="http://blog.matrix.org.cn/page/cleverpig" target="_new">cleverpig</a></u><br />
<br />
<img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_16_092132_nWJDcylMZM.jpg" border="0" height="450" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="301" style="display: inline;" /><br />
</center><br />
<font size="2" face="Courier New"><strong><font color="#0000ff">原文地址：</font></strong></font><a href="http://www.matrix.org.cn/resource/article/2007-01-16/bcc2c490-a502-11db-8440-755941c7293d.html" target="_blank">http://www.matrix.org.cn/resource/article/2007-01-16/bcc2c490-a502-11db-8440-755941c7293d.html</a><br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">介绍 </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server端向浏览器client发送通知这种通讯模式在J2EE应用中很常见，通常使用采用<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=RMI" target="_new">RMI</a></u>、<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=CORBA" target="_new">CORBA</a></u>或 者自定义TCP/IP信息的applet来实现。这些技术往往由于复杂而产生诸多不利之处：技术难以实现、存在防火墙限制（因为需要打开非HTTP的通讯 端口）、需要额外的server开发和维护。并且除了刷新整个页面或者完全采用applet展示内容之外，很难找到别的方法将client端applet 的状态和浏览器的页面内容集成在一起。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<u><a href="http://www.pushlets.com/" target="_new">Pushlet</a></u>是一种<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=Comet" target="_new">comet</a></u>实 现：在Servlet机制下，数据从server端的Java对象直接推送（push）到（动态）HTML页面，而无需任何Java applet或者插件的帮助。它使server端可以周期性地更新client的web页面，这与传统的request/response方式相悖。浏览 器client为兼容JavaScript1.4版本以上的浏览器（如Internet Explorer、FireFox），并使用JavaScript/Dynamic HTML特性。而低层实现使用一个servlet通过Http连接到JavaScript所在的浏览器，并将数据推送到后者。有关JavaScript版 本的知识请参看Mozilla开发中心提供的<u><a href="http://developer.mozilla.org/cn/docs/Core_JavaScript_1.5_Reference:About#JavaScript_Versions" target="_new">《JavaScript核心参考》</a></u>和<u><a href="http://javascript.about.com/mbiopage.htm" target="_new">Stephen Chapman</a></u>编写的<u><a href="http://javascript.about.com/library/bljver.htm" target="_new">《What Version of Javascript》</a></u>。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这种机制是轻量级的，它使用server端的servlet连接管理、线程工具、javax.servlet API，并通过标准Java特性中Object的wait()和notify()实现的生产者/消费者机制。原则上，Pushlet框架能够运行在任何支 持servlet的server上、防火墙的后面。当在client中使用JavaScript/DHTML时，Pushlet提供了通过脚本快速建立应 用、使用HTML/CSS特性集成和布局新内容的便利方法。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">动机 </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;目前越来越多的servlet和JSP用来部署web，于是便出现了在页面已经装载完毕后由于server端某些对象的状态变化而产生对client浏览器进行通知和同步的需要。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这些状态变化的原因很复杂：可能由于用户通过访问servlet或者修改数据库记录、更新EJB造成，或是在多用户应用（比如聊天室和共享白板）中的事件导致数据状态变化。这些类型的应用常常使用一种分布式的<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=%E6%A8%A1%E5%9E%8B%E8%A7%86%E5%9B%BE%E6%8E%A7%E5%88%B6%E5%99%A8%E6%A8%A1%E5%BC%8F" target="_new">MVC模板</a></u>：模式层位于server上（可能缓存在client中），控制层和视图层位于client中（这两个层可能合为一体）。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，这里也存在需要订阅server端动态内容的应用：那些动态内容不停地从server端推送过来。例如股票实时情报、系统状态报告、天气情况或者其 它的监测应用。它遵循观察者（Observer）模板（也称为发布/订阅模板），这种模板中的远程client注册成为关注于server端对象变化的观 察者。关于设计模板的知识请看<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F" target="_new">Matrix Wiki上的介绍</a></u>。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;那么在HTML页面已经被装载后如何通知浏览器客户端？或者如果有选择地更新页面中一些部分的话，那该怎么做？比如只更新在HTML Table中的那些价格发生变化的股票列？<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">多种通知解决方案 </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 让我们对应用进行这样的假设：拥有一个Java web server或者Java应用server，我们试图从server发送通知给client端浏览器。这里的解决方案可以分为：&ldquo;轮询 （polling）&rdquo;、&ldquo;服务端回调（server-side callbacks）&rdquo;和&ldquo;消息（messaging）&rdquo;三类。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">轮询</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最简单的解决方案便是&ldquo;定时刷新页面&rdquo;。在HTML文档的头部使用HTML META标签，页面便可以每隔N秒自动reload一次。如果在此期间server端数据发生变化，那么我们可以获得新的内容，否则将得到相同的页面。虽 然方法很简单，但是如何设置刷新间隔是让人头疼的大问题。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">服务端回调</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因为我们是&ldquo;身经百战&rdquo;的Java开发老手，所以经常会用到&ldquo;服务端回调&rdquo;。这种方式通过RMI或者CORBA将Server端的对象传输到Java applet客户端。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">消息（MOM）</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这种解决方案采用一个作为client的applet，它使用TCP/IP或者无连接的UDP、甚至多播协议来建立与消息中间键server的通讯，然后由server推送消息给client。你可以从例如<u><a href="http://www.softwired-inc.com/" target="_new">SoftWired的iBus</a></u>、<u><a href="http://www.ibm.com/software/mqseries/" target="_new">IBM的MQSeries</a></u>、<u><a href="http://e-docs.bea.com/wls/docs61/event/index.html" target="_new">BEA的WebLogic Event</a></u>这些消息产品中直接挑选，或者自己使用基于socket的java.io.ObjectStream定制开发消息软件。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">讨论（MOM）</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面三种解决方案在复杂性、安全性、性能、可测量性、浏览器兼容性、防火墙限制上各有优势、劣势。最佳解决方案依赖于你的应用需求。例如，在共享白板应用中，用户需要直接与&ldquo;状态&rdquo;交互，那么server端回调或者消息很可能会大显身手。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但在浏览器环境下，除非完全使用applet作为整个client应用，否则把来自于server的更新信息集成到页面中并非易事。如何在applet收 到回调或者消息时变更页面相关内容？一个很&ldquo;痛快&rdquo;而又&ldquo;痛苦&rdquo;的解决方案就是在回调方法中使用AppletContext.showDocument (URL)方法来刷新整个页面。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于HTML代码可以直接影响页面布局，直接使用来自server的数据更改HTML部 分内容不是更好吗？这是web应用的理想方案，在server上内容动态改变时，从用户到server所需的交互是最小化的。作为对上面的解决方案的补 充，我开发了Pushlet这种轻量级、瘦客户端的技术，它无需applet或者插件而直接与脚本/HTML集成在一起、使用标准HTTP连接、理论上可 以部署到任何支持Java servlet的server上。但这并不意味着它将替换对前面解决方案，而是在你的开发&ldquo;工具箱&rdquo;中添加另一种选择。作为Java构架者/开发者，你可 以自行权衡、选择、决定哪种适合应用的解决方案。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">Pushlet原理</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet的基本使用形式是极为简单的。后面的一些示例会说明这一点。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">HTTP流</span></span></strong><br />
<center> <br />
<img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_16_092206_YuMERGJbQN.jpg" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" style="display: inline;" /><br />
<strong>极富生活韵味的&ldquo;Urban Stream&rdquo;把我们Connecting Together</strong><br />
</center><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet 基于HTTP流，这种技术常常用在多媒体视频、通讯应用中，比如QuickTime。与装载HTTP页面之后马上关闭HTTP连接的做法相反， Pushlet采用HTTP流方式将新数据源源不断地推送到client，再此期间HTTP连接一直保持打开。有关如何在Java中实现这种Keep- alive的长连接请参看Sun提供的<u><a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/http-keepalive.html" target="_new">《HTTP Persistent Connection》</a></u>和<u><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" target="_new">W3C的《HTTP1.1规范</a></u>》。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">示例1</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们利用HTTP流开发一个JSP页面（因为它易于部署，而且它在web server中也是作为servlet对待的），此页面在一个定时器循环中不断地发送新的HTML内容给client：<br />
<pre class="overflow"><div class="code_title">java 代码</div><div class="dp-highlighter"><div class="bar">&nbsp;</div><ol class="dp-j" start="1"><li class="alt"><span><span>&lt;%&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;<span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">1</span><span>;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">while</span><span>&nbsp;(</span><span class="keyword">true</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(<span class="string">&quot;<h1>&quot;<span>+(i++)+</span><span class="string">&quot;</span></h1>&quot;</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.flush();&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(<span class="number">3000</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(<span class="string">&quot;<h1>&quot;<span>+e+</span><span class="string">&quot;</span></h1>&quot;</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;}&nbsp;<span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(<span class="string">&quot;<h1>&quot;<span>+e+</span><span class="string">&quot;</span></h1>&quot;</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class=""><span>%&gt;&nbsp;&nbsp;</span></li></ol></div><br /></pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在Pushlet源代码中提供了此页面（examples/basics/push-html-stream.jsp）。上面的页面并不是十分有用，因为在我们刷新页面时，新内容机械地、持续不断地被添加到页面中，而不是server端更新的内容。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">示例2</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现在让我们步入Pushlet工作机理中一探究竟。通过运行Pushlet的示例源代码（examples/basics/ push-js-stream.html），我们会看到这个每3秒刷新一次的页面。那么它是如何实现的呢？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此示例中包含了三个文件：push-js-stream.html、push-js-stream-pusher.jsp、push-js-stream-display.html。 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中push-js-stream.html是主框架文件，它以HTML Frame的形式包含其它两个页面。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;push-js-stream-pusher.jsp是一个JSP，它执行在server端，此文件内容如下：&nbsp;
<pre class="overflow"><div class="code_title">java 代码</div><div class="dp-highlighter"><div class="bar">&nbsp;</div><ol class="dp-j" start="1"><li class="alt"><span><span>&nbsp;</span><span class="number">7</span><span>:&nbsp;&lt;%&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;<span class="number">8</span><span>:&nbsp;&nbsp;&nbsp;</span><span class="comment">/**&nbsp;Start&nbsp;a&nbsp;line&nbsp;of&nbsp;JavaScript&nbsp;with&nbsp;a&nbsp;function&nbsp;call&nbsp;to&nbsp;parent&nbsp;frame.&nbsp;*/</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;<span class="number">9</span><span>:&nbsp;&nbsp;&nbsp;String&nbsp;jsFunPre&nbsp;=&nbsp;</span><span class="string">&quot;<script language=JavaScript >parent.push('"</span><span>;  </span></span></li><li class=""><span><span class="number">10</span><span>:     </span></span></li><li class="alt"><span><span class="number">11</span><span>:   </span><span class="comment">/** End the line of JavaScript */</span><span>  </span></span></li><li class=""><span><span class="number">12</span><span>:   String jsFunPost = </span><span class="string">"')&nbsp;&quot;</span><span>;&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">13</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">14</span><span>:&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;i&nbsp;=&nbsp;</span><span class="number">1</span><span>;&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">15</span><span>:&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">16</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">17</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Every&nbsp;three&nbsp;seconds&nbsp;a&nbsp;line&nbsp;of&nbsp;JavaScript&nbsp;is&nbsp;pushed&nbsp;to&nbsp;the&nbsp;client</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">18</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>&nbsp;(</span><span class="keyword">true</span><span>)&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">19</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">20</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Push&nbsp;a&nbsp;line&nbsp;of&nbsp;JavaScript&nbsp;to&nbsp;the&nbsp;client&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">21</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(jsFunPre+</span><span class="string">&quot;Page&nbsp;&quot;</span><span>+(i++)+jsFunPost);&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">22</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.flush();&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">23</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">24</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Sleep&nbsp;three&nbsp;secs</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">25</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">26</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(</span><span class="number">3000</span><span>);&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">27</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">28</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Let&nbsp;client&nbsp;display&nbsp;exception&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">29</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(jsFunPre+</span><span class="string">&quot;InterruptedException:&nbsp;&quot;</span><span>+e+jsFunPost);&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">30</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">31</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">32</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">33</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Let&nbsp;client&nbsp;display&nbsp;exception&nbsp;</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">34</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.print(jsFunPre+</span><span class="string">&quot;Exception:&nbsp;&quot;</span><span>+e+jsFunPost);&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="number">35</span><span>:&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></span></li><li class=""><span><span class="number">36</span><span>:&nbsp;%&gt;&nbsp;&nbsp;&nbsp;</span></span></li></ol></div><br /></pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong><em><span style="color: green;">注 意在示例1和示例2中使用JSP时都存在一个问题：一些servlet引擎在某个client离开时会&ldquo;吃掉&rdquo;IOException，以至于JSP页面 将永不抛出此异常。所以在这种情况下，页面循环将会永远执行下去。而这正是Pushlet实现采用servlet的原因之一：可以捕获到 IOException。 </span></em></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在上面代码的第21行中可以看到在一个定时器循环（3秒/周期）中打印了一些HTML并将它们输出到client浏览器。请注意，这里推送的并非HTML而是Javascript！这样做的意义何在？<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它把类似&ldquo;<script language="JavaScript">parent.push('Page 4')</script>&rdquo;的一行代码推送到浏览器；而具有JavaScript引擎的浏览器可以直接执行收到的每一行代码，并调用 parent.push()函数。而代码中的Parent便是浏览器页面中所在Frame的Parent，也就是push-js- stream.html。让我们看看都发生了什么？<br />
<pre class="overflow"><div class="code_title">js 代码</div><div class="dp-highlighter"><div class="bar">&nbsp;</div><ol class="dp-c" start="1"><li class="alt"><span><span><script LANGUAGE=</span><span class="string">"JavaScript"</span><span>>  </span></span></li><li class=""><span><span class="keyword">var</span><span> pageStart=</span><span class="string">"<html><head></head><BODY BGCOLOR=blue TEXT=white></html><h2>Server pushes: </h2><para>"</para></span><span>;  </span></span></li><li class="alt"><span><span class="keyword">var</span><span> pageEnd=</span><span class="string">""</span><span>;  </span></span></li><li class=""><span>  <span class="comment">// Callback function with message from server.</span><span>  </span></span></li><li class="alt"><span>  <span class="comment">// This function is called from within the hidden JSP pushlet frame</span><span>  </span></span></li><li class=""><span>  <span class="keyword">function</span><span> push(content) {  </span></span></li><li class="alt"><span>   </span></li><li class=""><span>    <span class="comment">// Refresh the display frame with the content received</span><span>  </span></span></li><li class="alt"><span>    window.frames['displayFrame'].document.writeln(pageStart+content+pageEnd);  </span></li><li class=""><span>    window.frames['displayFrame'].document.close();  </span></li><li class="alt"><span>  }  </span></li><li class=""><span>  </span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<!-- frame to display the content pushed by the pushlet -->&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<!-- Hidden frame <span class="keyword">with</span><span> the pushlet that pushes lines of JavaScript-->&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;</span></li></ol></div><br /></pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以看到push-js-stream.html中的push()函数被名为pushletFrame的JSP Frame调用：把传入的参数值写入到displayFrame（此Frame为push-js-stream-display.html）。这是动态 HTML的一个小技巧：使用document对象的writeln方法刷新某个Frame或者Window的内容。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;于是displayFrame成为了用于显示内容的、真正的视图。displayFrame初始化为黑色背景并显示&ldquo;wait&hellip;&rdquo;直到来自server的内容被推送过来：<br />
<pre class="overflow"><h1>WAIT...</h1><br /></pre>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这便是Pushlet的基本做法：我们从servlet（或者从示例中的JSP）把JavaScript代码作为HTTP流推送到浏览器。这些代码被浏览 器的JavaScript引擎解释并完成一些有趣的工作。于是便轻松地完成了从server端的Java到浏览器中的JavaScript的回调。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上面的示例展示了Pushlet原理，但这里存在一些等待解决的问题和需要增添的特性。于是我建立了一个小型的server端Pushlet框架（其类结 构图表将会展示在下面），添加了一些用在client中的JavaScript库。由于client需要依赖更多的DHTML特性（比如Layers）， 我们将首先粗略地温习一些<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=DHTML" target="_new">DHTML知识</a></u>。示例代码见examples/dhtml。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">框架的设计 </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注意：本章节仅反映了Pushlet server端框架的1.0版本（随着版本升级可能还会重新构造）。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet 框架允许client订阅在server端的主题（subject），而server则接收订阅，然后在server端的订阅主题所对应的数据变化时推送 数据到client。此框架的基本设计模板是发布/订阅（Publish/Subscrib），也被称为观察者（Observer）。它具有server 和client两部分组建而成：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>Server端：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由围绕着Pushlet类的Java类集合构成（见下面的UML类设计图表）。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>Client端：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;脚本与页面：可重用的JavaScript库（pushlet.js）和用来在DHTML client（这里指浏览器）中接收事件的HTML（pushlet.html）组成。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>Client端Java类：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JavaPushletClient.java和JavaPushletClientListener.java，负责在Java client中接收事件。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>跨越浏览器的DHTML工具库：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;layer.js, layer-grid.js, layer-region.js，用来在DHTML层中显示数据内容。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后，还有用于测试事件的生成工具类EventGenerators.java以及一些示例应用。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">server端类设计 </span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面是server端Java类的UML图表：<br />
<center><br />
<img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_16_092143_CsqEypyPee.gif" border="0" height="450" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="531" style="display: inline;" /><br />
<strong>Pushlet框架Java类UML图</strong><br />
</center><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;关键的类：Pushlet、Publisher类、Subscriber接口和Event类。通过HTTP请求调用Pushlet这个servlet，client订阅事件并接收事件。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>Client发送订阅请求时需要表明的内容如下：</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.订阅事件的主题<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.接收事件所采用的格式：默认为JavaScript调用，还有XML或者Java序列化对象者三种。目前Pushlet 2.0.2版已经支持AJAX。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.使用哪种接收协议（将来实现）：TCP/IP、UDP、Multicast。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;示例：用于接收AEX股票价格的请求，默认使用JavaScript调用作为格式。 <br />
<pre class="overflow"><div class="code_title">js 代码</div><div class="dp-highlighter"><div class="bar">&nbsp;</div><ol class="dp-c" start="1"><li class="alt"><span><span>http:</span><span class="comment">//www.fluidiom.com:8080/servlet/pushlet?subject=&quot;/stocks/aex&quot;</span><span>&nbsp;&nbsp;</span></span></li></ol></div><br /></pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 主题（subject）表示为具有层次的&ldquo;主题树&rdquo;（topic-tree）形式。例如：&ldquo;/stocks&rdquo;表示与股票价格相关的所有事件，而 &ldquo;/stocks/aex&rdquo;表示Amsterdam Exchange公司的股票价格。&ldquo;/&rdquo;表示所有事件。这并不时硬性规定，而是由开发者根据应用自行定义。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当前只有接收方协议是发送到client的HTTP回应流（response stream）。在将来的扩展版本中，接收方协议能够提供多种选择，比如TCP、UDP、RMI、HTTP POST甚至只SMTP。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>Event（事件）类：</strong>仅仅是name/value的字符串对（使用java.util.Properties实现）的集合。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>产生Event的方式：</strong>Publisher 类为生成的Event提供了发布接口，它内部保存了订阅者（那些实现Subscriber接口的类）列表，并把每个Event发送给那些主题与Event 匹配的订阅者。Event在server端也可以通过能够侦听外部Event的EventGenerators类来生成。另外client可以通过基于 HTTP通讯的Postlet类来发布Event。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在上面的图表中，为了适配不同请求源（浏览器、Java client程序），PushletSubscriber以及它所包含的那些类提供了多种订阅者的实现。<br />
<br />
<strong><span style="font-size: 11px;"><span style="color: purple;">场景1: 事件订阅 </span></span></strong><br />
<center> <br />
<img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_16_092151_rQeypNpXkq.gif" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="600" style="display: inline;" /><br />
<strong>浏览器client订阅程序图</strong><br />
</center><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;上面的UML程序图中，浏览器client通过Publisher订阅Event。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet 作为servlet，通过doGet/doPost方法被调用。由于多个client可以同时调用同一个Pushlet，所以Pushlet本身不能作为 订阅者。取而代之的是，它派发所有的订阅：在每一次调用doGet()/doPost()时，新建PushletSubscriber对象、并使之运行直 至事件循环（eventLoop)结束。PushletSubscriber作为一个实现Subscriber接口的对象，通过join()方法向 Publisher类进行注册的方式将自身添加到Publisher的内部列表。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;面对不同的client类型和协议， PushletSubscriber建立一个相对的ClientAdapter对象，在这个场景中是BrowserPushletAdapter对象。而 对于支持Multipart MIME的浏览器，将建立MultipartBrowserClientAdapter对象。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后的deQueue()调用是一个&ldquo;等待Event的循环&rdquo;，deQueue的意思为入队。注意此方法将挂起当前线程直到PushletSubscriber的GuardedQueue队列中存入有效的Event。<br />
<br />
<strong><span style="font-size: 11px;"><span style="color: purple;">场景2: 发送和派发事件</span></span></strong><br />
<center> <br />
<img src="http://www.matrix.org.cn/resource/upload/forum/2007_01_16_092202_AxYbIhVBOW.gif" border="0" onclick="javascript:imgClick(this);" onload="javascript:imgLoad(this);" alt="image" width="600" style="display: inline;" /><br />
<strong>事件发布程序图</strong><br />
</center><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上图显示了发送一个事件所要经历的程序。它展现了Event如何被生成、被派发给浏览器client。在这个场景中，EventGenerator建立了 一个Event对象，并调用Publisher.publish()将其派发到client。Publisher遍历它内部的订阅者列表，询问这个 Event是否匹配订阅标准（目前只是主题匹配）。如果发现与之匹配的订阅者，则调用该订阅者的send()方法。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个 PushletSubscriber对象都有一个GuardedQueue对象，在其中以队列的形式保存着调用send()方法时传入的Event。那么 它为什么不直接将Event推送给BrowserPushletAdapter呢？最重要的原因是我们期望挂起 BrowserPushletAdapter线程，直到GuardedQueue中存在有效的Event，这样就避免了&ldquo;忙于等待&rdquo;或者&ldquo;轮询&rdquo;方式所带 来的负面影响。第二原因是Publisher可以通知多个client，如果在执行同步的send()调用时，某个慢速的client可能会堵塞所有其它 正在等待通知的client。这正是我在RMI或者CORBA提供的一组client进行同步回调的示例中所看到的设计缺陷。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GuardedQueue 是个工具类，它使用了读/写模板（readers-writers pattern），此模板采取java.lang.Object.wait()/notifyAll()方法实现可被监控的挂起。通过使用读/写模板，使 GuardedQueue类具有进行对象入队/出队（enqueue/dequeue）操作的能力。当队列为空时，GuardedQueue调用 deQueue()方法时，此时调用线程将被挂起，直到有对象入队为止。相反，当队列已满时调用enQueue（），线程也将挂起。在 BrowserPushletSubscriber获得出队的Event对象后，它将调用BrowserPushletAdapter的push()方 法，后者将格式化Event为JavaScript代码或者XML以及其它格式），并将它发送到浏览器。比如Philips股票价格为123.45的 JavaScript代码格式如下：<br />
<pre class="overflow"><div class="code_title">js 代码</div><div class="dp-highlighter"><ol class="dp-c" start="1"><li class="alt"><span><span><SCRIPT language=JavaScript >parent.push('subject', '/stocks/aex', 'philips', '123.45') &nbsp;&nbsp;</span></span></li></ol></div><br /></pre>
<strong><span style="font-size: 12px;"><span style="color: green;">Client端框架</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于这是对于所有浏览器client的通用任务，所以Pushlet Client端框架提供了两个可重用的文件：<br />
pushlet.html和pushlet.js。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet.html本身是被附着在一个隐藏的HTML Frame中。这个Frame的parent调用并实现push()方法。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pushlet.html ：被包含在client端的HTML文档中的Frame中。它可以传入主题标识和背景颜色两个参数。而它所做的最重要的工作是下面的push方法：<br />
<div class="code_title">js 代码</div>
<div class="dp-highlighter">
<div class="bar">&nbsp;</div>
<ol class="dp-c" start="1">
    <li class="alt"><span><span class="keyword">function</span><span>&nbsp;push()&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;根据传入的参数建立PushletEvent&nbsp;object</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;push.arguments是来自server的Event数据</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pushletEvent&nbsp;=&nbsp;<span class="keyword">new</span><span>&nbsp;PushletEvent(push.arguments)&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;更新状态Frame：显示闪光表示接收数据</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;updateStatusFrame();&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;parent&nbsp;frame是否准备好接收Event?</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>&nbsp;(!parent.onPush)&nbsp;{&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>;&nbsp;&nbsp;</span></span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;把Event转发给parent&nbsp;frame指定的处理方法</span><span>&nbsp;&nbsp;</span></span></li>
    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parent.onPush(pushletEvent);&nbsp;&nbsp;</span></li>
    <li class=""><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Push ()函数首先根据传入的参数建立了一个JavaScript对象&mdash;&mdash;pushletEvent。接着使用updateStatusFrame()显示闪 光，表示我们正在接收Event数据，如果parent frame存在onPush()函数，则将前面建立的PushletEvent对象作为参数调用parent frame指定的处理方法。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在pushlet.js 中的PushletEvent类代码如下：<br />
<pre class="overflow"><div class="code_title">js 代码</div><div class="dp-highlighter"><div class="bar">&nbsp;</div><ol class="dp-c" start="1"><li class="alt"><span><span class="comment">/*&nbsp;Object&nbsp;to&nbsp;represent&nbsp;nl.justobjects.pushlet.Event&nbsp;in&nbsp;JavaScript.&nbsp;</span>&nbsp;</span></li><li class=""><span><span class="comment">&nbsp;&nbsp;&nbsp;Arguments&nbsp;are&nbsp;an&nbsp;array&nbsp;where&nbsp;args[i]&nbsp;is&nbsp;name&nbsp;and&nbsp;args[i+1]&nbsp;is&nbsp;value&nbsp;</span>&nbsp;</span></li><li class="alt"><span><span class="comment">*/</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="keyword">function</span><span>&nbsp;PushletEvent(args)&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;Map存放Name/Value&nbsp;pairs</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.map&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Map();&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;设置成员方法</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.getSubject&nbsp;=&nbsp;PushletEventGetSubject&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.put&nbsp;=&nbsp;PushletEventPut&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.get&nbsp;=&nbsp;PushletEventGet&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.toString&nbsp;=&nbsp;PushletEventToString&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.toTable&nbsp;=&nbsp;PushletEventToTable&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;<span class="comment">//&nbsp;将传入的参数值放入到map中</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;<span class="keyword">for</span><span>&nbsp;(</span><span class="keyword">var</span><span>&nbsp;i=0;&nbsp;i&nbsp;&lt;&nbsp;args.length;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">this</span><span>.put(args[i],&nbsp;args[++i]&nbsp;);&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;</span></li><li class="alt"><span><span class="comment">//&nbsp;获取事件主题</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="keyword">function</span><span>&nbsp;PushletEventGetSubject()&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.map.get('subject')&nbsp;&nbsp;</span></span></li><li class=""><span>}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li class=""><span><span class="comment">//&nbsp;获取事件属性</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="keyword">function</span><span>&nbsp;PushletEventGet(name)&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.map.get(name)&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li><li class=""><span>&nbsp;&nbsp;</span></li><li class="alt"><span><span class="comment">//&nbsp;存放事件属性</span><span>&nbsp;&nbsp;</span></span></li><li class=""><span><span class="keyword">function</span><span>&nbsp;PushletEventPut(name,&nbsp;value)&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.map.put(name,&nbsp;value)&nbsp;&nbsp;</span></span></li><li class=""><span>}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li class=""><span><span class="keyword">function</span><span>&nbsp;PushletEventToString()&nbsp;{&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.map.toString();&nbsp;&nbsp;</span></span></li><li class=""><span>}&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;</span></li><li class=""><span><span class="comment">//&nbsp;将map内容转化为HTML&nbsp;Table</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span><span class="keyword">function</span><span>&nbsp;PushletEventToTable()&nbsp;{&nbsp;&nbsp;</span></span></li><li class=""><span>&nbsp;&nbsp;<span class="keyword">return</span><span>&nbsp;</span><span class="keyword">this</span><span>.map.toTable();&nbsp;&nbsp;</span></span></li><li class="alt"><span>}&nbsp;&nbsp;</span></li></ol></div><br /></pre>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PushletEvent使用了一个我增加的Map JavaScript对象，它类似于java.util.Hashtable。<br />
<br />
<strong><span style="font-size: 14px;"><span style="color: blue;">Pushlet协议</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;详见<u><a href="http://www.pushlets.com/doc/protocol.html" target="_new">http://www.pushlets.com/doc/protocol.html</a><br />
<br />
</u><strong><span style="font-size: 14px;"><span style="color: blue;">应用</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pushlet可以开发多种类型的web应用。由于此框架允许client主动更新事件（通过Postlet），所以应用就并不只是被动地推送数据了。每个Pushlet应用都可以根据下面进行分类：<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;事件由server发起、还是client发起或者两者都有可能；状态是否保持在server、还是在client或者两者都有可能。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于事件不但被做成了对JavaScript有效，而且也是其它脚本化的插件能够接收实时的事件更新。例如你可以脚本化Macromedia Flash或者<u><a href="http://wiki.matrix.org.cn/Wiki.jsp?page=VRML" target="_new">VRML</a></u>应用。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了说明Pushlet应用的范围，下面提供了一些简单的demo。<br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">监控</span></span></strong><br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;例如股票、天气、投票、机场到达系统，这些应用都可以采用Pushlet对实时数据进行监控。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这是一个实时FX股票/新闻应用：<u><a href="http://www.rabotreasuryweb.com/" target="_new">www.rabotreasuryweb.com</a></u> (IE only). 另一个部署Pushlet的实时股票/新闻应用：<u>www.marketnews.com. </u><br />
<br />
<strong><span style="font-size: 12px;"><span style="color: green;">游戏</span></span></strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从象棋到