<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>gwbasic</title>
    <description></description>
    <link>http://gwbasic.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>GB12904-2003商品条码检码计算方法</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/175005" style="color:red;">http://gwbasic.javaeye.com/blog/175005</a>&nbsp;
          发表时间: 2008年03月23日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
	/**
	 * 返回带正确检验码的商品条码.
	 * 
	 * @param value
	 *            商品条码前12位
	 * @return
	 */
	public String checkEAN(String value) {
		if (value.length() &lt; 12)
			return value;

		int v = 0;
		for (int i = 1; i &lt; 12; i = i + 2) {
			v += Character.digit(value.charAt(i), 10);
		}
		v *= 3;
		for (int i = 0; i &lt; 12; i = i + 2) {
			v += Character.digit(value.charAt(i), 10);
		}
		v %= 10;
		if (v > 0) {
			v = 10 - v;
		}

		return value.substring(0, 12) + Integer.toString(v);
	}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/175005#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>Sun, 23 Mar 2008 09:46:17 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/175005</link>
        <guid>http://gwbasic.javaeye.com/blog/175005</guid>
      </item>
      <item>
        <title>杞人忧天</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/165257" style="color:red;">http://gwbasic.javaeye.com/blog/165257</a>&nbsp;
          发表时间: 2008年02月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天坐出租车，出租车师傅问了一个问题,"怎么知道天气还会不会转冷？"，我说：“不知道”。心里却在想，GOOGLE一下，看一下专家的评论就知道了。现在，对于网络，我有了严重的依赖，一天上不网，总觉的缺了些什么？<br />    出租车师傅说：“还会转冷，因为苍蝇，蜜蜂还没有出来。它们还有一种人类已经退化了的”功能“，能够预知未来天气的变化。如果他们没有这个功能，现在出来，天气一旦转冷，还不都冻死？正是这个”功能“，使的这个物种能够长期生存下来。而人类，很多功能都在退化，比如双腿，现在出门，都要靠车,以前，走几十里路是很平常的一件事，现在谁还愿意走这么长的路呀。“<br />    人类，太依赖高科技了!!
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/165257#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Feb 2008 20:32:59 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/165257</link>
        <guid>http://gwbasic.javaeye.com/blog/165257</guid>
      </item>
      <item>
        <title>而立之年</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/162121" style="color:red;">http://gwbasic.javaeye.com/blog/162121</a>&nbsp;
          发表时间: 2008年02月13日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          昨天度过了30岁的生日.<br />很惊讶的发现,自己脸上已经有了岁月的痕迹.<br />更惊讶的发现,自己越来越不了解这个世界.<br />人的这一生,价值究竟何在?究竟为何而存在?<br />还记得政治课上"树立正确人生观,价值观"的论述.那时很不解,以为慢慢会懂得.<br />十几年过去了,我还是没有找到.<br />30岁,也许是理解社会的起点,因为我还是到处充满疑惑,<br />30岁,也许是走向成熟的起点,因为自己已不年经.<br />30岁,也许是挑起重担,大步向前的时候,因为时不待我.<br />30岁,再过十年,能否解答我心中的种种疑问,因为那是不惑之年.<br />如果不能,我也知天命了.
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/162121#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 13 Feb 2008 21:15:00 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/162121</link>
        <guid>http://gwbasic.javaeye.com/blog/162121</guid>
      </item>
      <item>
        <title>金融炼金术之书签</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/161882" style="color:red;">http://gwbasic.javaeye.com/blog/161882</a>&nbsp;
          发表时间: 2008年02月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          没有网络的春节,在乔治.索罗斯的大作&lt;&lt;金融炼金术>>之下渡过了,本人墨水不多,所以给我的第一印象就是深涩难懂,看了半天,不知所云,所以也成了我枕边催眠的法宝.<br />现对这几日领悟到的几个知识点(希望能以百分之几来计算)作一下整理,但愿这本被我尘封了一年的好书能再次被我打开.<br />1.反均衡<br />    经济学的所谓均衡只不过是天方夜谭.<br />    看看股市,不是涨是太高,便是跌的太深.这一点还是很好理解的.<br />2.不完备的理解<br />    完备的知识是不可企及的.我们只不过是井底之蛙,有时候我总是在想,诺大的宇宙,会不会就是更大宇宙里的一粒尘埃,而我们生活中的一粒尘埃,会不会存在着一个宇宙<br />3.自然科学和社会科学<br />    不能用分析自然科学的方法来分析社会科学,因为社会科学是研究人的学科,而人是有思维的,所以以后就不要用马克思主义的辩证唯物主义来理解这个社会(当然要先学一下马克思的辩证唯物主义,我不懂政治,因为我的邓小平理论没有及格),毛主席的"实事求是",可能也不适合来分析股市,因为毛主席会说,卖三元的东西,你就应该实事求是,卖三元.<br />    唯心主义.唯物主义可能都太极端了一点.<br />    "如果说黑格尔是正题，马克思主义是反题，那么反身性就是合题"<br />4.参与者的偏向<br />    因为"不完备的知识",作出的判断也是不准确的,所以偏向是很自然的.所以经济学的"均衡"也就成了天方夜谭,人们总是从一个极端,到另一个极端.<br />5.反身性(也有翻译成反射性)<br />    将参与者理解情境的努力称为认识(或被动)函数,把他们的思维对现实的影响称为参与(或主动)函数.在认识函数中,参与者的认识依赖于情境,在参与函数中,情境受参与者认知的影响.<br />    参与者影响了情境,情境又影响了参与者,这是一个永无止步的变化过程.<br /><br />看了这些理论,能再应运到生活中,那就有些妙不可言了,所以我把这本书理解为大作.这是一本教人生活,教人道理的书,能发人深思.<br /><br />也许你听说过"市场永远是对的",但索老师却说"不",一.市场总是表现出某种偏向;二.市场能影响它预期的事件.依照我理解,"市场永远是对的",是因为经济学上的得失,最终的裁判是市场,所以在这一点上,市场永远是对的.所以希望球场上的球员也别和裁判较劲了,虽然"裁判"总是表现出某种偏向,这是"裁判"固有的现象.<br /><br />再根据这两点来理解股市,就有点知其然了,因为市场是不讲道理的,他总是表现出某种偏向,即使这支股票价值真的就只值1百元,当他疯起来的时候,也可能涨到1千元,跌的时候,也可能跌到10元.市场没有均衡点,要么沽值太高,要么沽值太低.为什么呢?因为"反身性".股市涨,人们的预期高,买的人多,买的人多,股市涨,人们的预期更高,这种趋势不断加强,而越是加强,这种状态越是依赖于人们的预期,最终滑入极其脆弱的状态,最后,进入了矫正的过程.失望的预期对股票的价格产生了一种消极的影响,如果基本趋势过度依赖股票价格的变化,则基本趋势可能发生逆转,而这种逆转,最终在跌到极限后,才能再次重新反转过来.<br /><br />再来看"爱之深,恨之切",也就可以理解了,人们总是从这个极端,到那个极端,很少停留在"均衡"的位置,为什么呢?因为"反身性",当人们对某人产生好感时,人们的这种认知,影响了评价此人的立场;这种立场,又反过来影响了以后对此人的评价,这个递归永无止步的进行下去,不断的加强,最后,给他打了个100分.在这个"完美"的人,犯下了人们认为不应出现的错误后,对此人产生的一点点厌恶,开始一点点改变人们的立场,这种立场,又在影响对此人的看法,又是一个永无止步的死循环.最后,把此人打下了地狱.<br /><br />罗老师在书中还谈到这样一句话,"追求完美,就是拥抱死亡",太有意思了.<br />我们总是在追求完美,不能容忍瑕疵,无论做事,还是对人.程序员往往认为自己能做出完美无缺的程序,过度的设计,只能以失败收场.对朋友,对家人,又往往把他们看成一个个完人,当他们表现出这个那个缺点的时候,却很难理解和接受.<br />微软设计出来满是漏洞的windows,他成功了,赚得盆满钵满<br />上帝造出了满是缺点的人类,他成功了,人类开始走上了发展的道路<br />当你下次再评价一个人的时候,请不要再打满分了,如果你还没有看到此人的缺点,说明你还没了解他.和完美的人在一起,是十分危险的<br />在教育下一代方面,请不要再把你的小宝贝照顾的无微不至,让他接爱大自然,接爱社会的洗礼,你不可能培养出一个完美无缺的宝贝,因为连上帝都不行,所以请再多点容忍,让他顺其自然,让他自己选择自己的道路.<br /><br />未完...<br /><br />乔治.索罗斯,具有传奇色彩的金融大师,1993年发动抛售英镑的投机风潮,迫使英格兰银行(英国中央银行)认亏出场,1997年2月,抛售泰铢,引出了东南亚金融危机.<br />(有点象金庸笔下的东邪)
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/161882#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, 11 Feb 2008 17:52:37 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/161882</link>
        <guid>http://gwbasic.javaeye.com/blog/161882</guid>
      </item>
      <item>
        <title>JavaScript格式化数字显示格式</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/161249" style="color:red;">http://gwbasic.javaeye.com/blog/161249</a>&nbsp;
          发表时间: 2008年02月02日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          代码如有BUG,请通知一下,谢谢<br />sales#soulan.com<br /><br /><pre name="code" class="js">

/**
 * 格式化数字显示方式 
 * 用法
 * formatNumber(12345.999,'#,##0.00');
 * formatNumber(12345.999,'#,##0.##');
 * formatNumber(123,'000000');
 * @param num
 * @param pattern
 */
function formatNumber(num,pattern){
  var strarr = num?num.toString().split('.'):['0'];
  var fmtarr = pattern?pattern.split('.'):[''];
  var retstr='';

  // 整数部分
  var str = strarr[0];
  var fmt = fmtarr[0];
  var i = str.length-1;  
  var comma = false;
  for(var f=fmt.length-1;f>=0;f--){
    switch(fmt.substr(f,1)){
      case '#':
        if(i>=0 ) retstr = str.substr(i--,1) + retstr;
        break;
      case '0':
        if(i>=0) retstr = str.substr(i--,1) + retstr;
        else retstr = '0' + retstr;
        break;
      case ',':
        comma = true;
        retstr=','+retstr;
        break;
    }
  }
  if(i>=0){
    if(comma){
      var l = str.length;
      for(;i>=0;i--){
        retstr = str.substr(i,1) + retstr;
        if(i>0 && ((l-i)%3)==0) retstr = ',' + retstr; 
      }
    }
    else retstr = str.substr(0,i+1) + retstr;
  }

  retstr = retstr+'.';
  // 处理小数部分
  str=strarr.length>1?strarr[1]:'';
  fmt=fmtarr.length>1?fmtarr[1]:'';
  i=0;
  for(var f=0;f&lt;fmt.length;f++){
    switch(fmt.substr(f,1)){
      case '#':
        if(i&lt;str.length) retstr+=str.substr(i++,1);
        break;
      case '0':
        if(i&lt;str.length) retstr+= str.substr(i++,1);
        else retstr+='0';
        break;
    }
  }
  return retstr.replace(/^,+/,'').replace(/\.$/,'');
}

document.write("formatNumber('','')=" + formatNumber('',''));
document.write("&lt;br/>");
document.write("formatNumber(123456789012.129,null)=" + formatNumber(123456789012.129,null));
document.write("&lt;br/>");
document.write("formatNumber(null,null)=" + formatNumber(null,null));
document.write("&lt;br/>");
document.write("formatNumber(123456789012.129,'#,##0.00')=" + formatNumber(123456789012.129,'#,##0.00'));
document.write("&lt;br/>");
document.write("formatNumber(123456789012.129,'#,##0.##')=" + formatNumber(123456789012.129,'#,##0.##'));
document.write("&lt;br/>");
document.write("formatNumber(123456789012.129,'#0.00')=" + formatNumber(123456789012.129,'#,##0.00'));
document.write("&lt;br/>");
document.write("formatNumber(123456789012.129,'#0.##')=" + formatNumber(123456789012.129,'#,##0.##'));
document.write("&lt;br/>");
document.write("formatNumber(12.129,'0.00')=" + formatNumber(12.129,'0.00'));
document.write("&lt;br/>");
document.write("formatNumber(12.129,'0.##')=" + formatNumber(12.129,'0.##'));
document.write("&lt;br/>");
document.write("formatNumber(12,'00000')=" + formatNumber(12,'00000'));
document.write("&lt;br/>");
document.write("formatNumber(12,'#.##')=" + formatNumber(12,'#.##'));
document.write("&lt;br/>");
document.write("formatNumber(12,'#.00')=" + formatNumber(12,'#.00'));
document.write("&lt;br/>");
document.write("formatNumber(0,'#.##')=" + formatNumber(0,'#.##'));
document.write("&lt;br/>");
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/161249#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>Sat, 02 Feb 2008 23:43:56 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/161249</link>
        <guid>http://gwbasic.javaeye.com/blog/161249</guid>
      </item>
      <item>
        <title>Always歌曲下载</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/159434" style="color:red;">http://gwbasic.javaeye.com/blog/159434</a>&nbsp;
          发表时间: 2008年01月25日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          英文歌曲:always<br />歌手:atlantic starr<br />格式:MP3
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/159434#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 25 Jan 2008 20:47:27 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/159434</link>
        <guid>http://gwbasic.javaeye.com/blog/159434</guid>
      </item>
      <item>
        <title>Hessian2序列化</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/129854" style="color:red;">http://gwbasic.javaeye.com/blog/129854</a>&nbsp;
          发表时间: 2007年10月08日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
unit Hessian2Output;

{
  title: hessian 2.0 序列化
  author: Xiao Chun 
  email: cnxiaochun#gmail.com
  version: draft
  reference: http://hessian.caucho.com/
}

interface
uses Classes;
const
  BUFFER_SIZE = 4096;

  INT_DIRECT_MIN = -$10;
  INT_DIRECT_MAX = $2F;
  INT_ZERO = $90;

  INT_BYTE_MIN = -$800;
  INT_BYTE_MAX = $7FF;
  INT_BYTE_ZERO = $C8;

  INT_SHORT_MIN = -$40000;
  INT_SHORT_MAX = $3FFFF;
  INT_SHORT_ZERO = $D4;

  LONG_DIRECT_MIN = -$08;
  LONG_DIRECT_MAX = $0F;
  LONG_ZERO = $E0;

  LONG_BYTE_MIN = -$800;
  LONG_BYTE_MAX = $7FF;
  LONG_BYTE_ZERO = $F8;

  LONG_SHORT_MIN = -$40000;
  LONG_SHORT_MAX = $3FFFF;
  LONG_SHORT_ZERO = $3C;

  LONG_INT_MIN = -$7FFFFFFF - 1;
  LONG_INT_MAX = $7FFFFFFF;
  LONG_INT_ZERO = $77;

  STRING_DIRECT_MAX = $1F;
  STRING_DIRECT = $00;

  BYTES_DIRECT_MAX = $0F;
  BYTES_DIRECT = $20;

  DOUBLE_ZERO = $67;
  DOUBLE_ONE = $68;
  DOUBLE_BYTE = $69;
  DOUBLE_SHORT = $6A;
  DOUBLE_FLOAT = $6B;

  LENGTH_BYTE = $6E;
  LIST_FIXED = $76; // 'v'

  REF_BYTE = $4A;
  REF_SHORT = $4B;

  TYPE_REF = $75;
type
  THessian2Output = class(TObject)
  private
    FBuffer: array[0..BUFFER_SIZE - 1] of Byte;
    FOffset: integer;
    FStream: TStream;
    FFreeStreamOnDestroy: boolean;
    _typeRefs: TStringList;
    procedure PrintString(const AValue: WideString; AOffset, ACount: integer);
    procedure WriteType(const AType: WideString);
    procedure _WriteString(const AValue: WideString; AOffset, ACount: integer);
  public
    constructor Create(AStream: TStream);
    destructor Destroy; override;
  public
    procedure StartCall(const AMethodName: WideString);
    procedure CompleteCall;
    procedure Flush;
    procedure WriteInt(AValue: integer);
    procedure WriteLong(AValue: Int64);
    procedure WriteDouble(AValue: Double);
    procedure WriteBoolean(AValue: boolean);
    procedure WriteNull;
    procedure WriteString(const AValue: WideString);
    procedure WriteUTCDate(AValue: TDateTime);
    procedure WriteBytes(ASourceStream: TStream); overload;
    procedure WriteBytes(ASourceStream: TStream; AOffset, ACount: integer); overload;
    procedure WriteMapBegin; overload;
    procedure WriteMapBegin(const AType: WideString); overload;
    procedure WriteMapEnd;
    function WriteListBegin(ALength: integer; const AType: WideString): boolean; overload;
    function WriteListBegin(ALength: integer): boolean; overload;
    procedure WriteListEnd;
  end;

implementation
uses JavaDate;

constructor THessian2Output.Create(AStream: TStream);
begin
  inherited Create;
  FOffset := 0;
  if Assigned(AStream) then
  begin
    FFreeStreamOnDestroy := false;
    FStream := AStream;
  end
  else begin
    FFreeStreamOnDestroy := true;
    FStream := TMemoryStream.Create;
  end;
end;

destructor THessian2Output.Destroy;
begin
  if FFreeStreamOnDestroy then FStream.Free;
  if Assigned(_typeRefs) then _typeRefs.Free;
  inherited;
end;

procedure THessian2Output.StartCall(const AMethodName: WideString);
var
  Len: Integer;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('c'); Inc(FOffset);
  FBuffer[FOffset] := Byte(2); Inc(FOffset);
  FBuffer[FOffset] := Byte(0); Inc(FOffset);
  FBuffer[FOffset] := Byte('m'); Inc(FOffset);

  Len := Length(AMethodName);
  FBuffer[FOffset] := Byte(len shr 8 ); Inc(FOffset);
  FBuffer[FOffset] := Byte(len); Inc(FOffset);
  PrintString(AMethodName, 0, Len);
end;

procedure THessian2Output.CompleteCall;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('z'); Inc(FOffset);
end;

procedure THessian2Output.WriteInt(AValue: integer);
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if (INT_DIRECT_MIN &lt;= AValue) and (AValue &lt;= INT_DIRECT_MAX) then
  begin
    FBuffer[FOffset] := Byte(AValue + INT_ZERO); Inc(FOffset);
  end
  else if (INT_BYTE_MIN &lt;= AValue) and (AValue &lt;= INT_BYTE_MAX) then
  begin
    FBuffer[FOffset] := Byte(INT_BYTE_ZERO + (AValue shr 8 )); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
  else if (INT_SHORT_MIN &lt;= AValue) and (AValue &lt;= INT_SHORT_MAX) then
  begin
    FBuffer[FOffset] := Byte(INT_SHORT_ZERO + (AValue shr 16 )); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
  else begin
    FBuffer[FOffset] := Byte('I'); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 24); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 16); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
end;

procedure THessian2Output.WriteLong(AValue: int64);
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if (LONG_DIRECT_MIN &lt;= AValue) and (AValue &lt;= LONG_DIRECT_MAX) then
  begin
    FBuffer[FOffset] := Byte(AValue + LONG_ZERO); Inc(FOffset);
  end
  else if (LONG_BYTE_MIN &lt;= AValue) and (AValue &lt;= LONG_BYTE_MAX) then
  begin
    FBuffer[FOffset] := Byte(LONG_BYTE_ZERO + (AValue shr 8 )); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
  else if (LONG_SHORT_MIN &lt;= AValue) and (AValue &lt;= LONG_SHORT_MAX) then
  begin
    FBuffer[FOffset] := Byte(LONG_SHORT_ZERO + (AValue shr 16)); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
  else if (LONG_INT_MIN &lt;= AValue) and (AValue &lt;= LONG_INT_MAX) then
  begin
    FBuffer[FOffset] := Byte(LONG_INT_ZERO); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 24); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 16); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
  else begin
    FBuffer[FOffset] := Byte('L'); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 56); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 48); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 40); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 32); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 24); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 16); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(AValue); Inc(FOffset);
  end
end;

procedure THessian2Output.WriteDouble(AValue: Double);
var
  intValue: integer;
  longValue: int64;
  floatValue: single;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if Int(AValue) = AValue then
  begin // 只有整数部分
    intValue := Round(AValue);
    if intValue = 0 then
    begin
      FBuffer[FOffset] := Byte(DOUBLE_ZERO); Inc(FOffset);
      exit;
    end
    else if intValue = 1 then
    begin
      FBuffer[FOffset] := Byte(DOUBLE_ONE); Inc(FOffset);
      exit;
    end
    else if (-$80 &lt;= intValue) and (intValue &lt; $80) then
    begin
      FBuffer[FOffset] := Byte(DOUBLE_BYTE); Inc(FOffset);
      FBuffer[FOffset] := Byte(intValue); Inc(FOffset);
      exit;
    end
    else if ($8000 &lt;= intValue) and (intValue &lt; $8000) then
    begin
      FBuffer[FOffset] := Byte(DOUBLE_SHORT); Inc(FOffset);
      FBuffer[FOffset] := Byte(intValue shr 8 ); Inc(FOffset);
      FBuffer[FOffset] := Byte(intValue); Inc(FOffset);
      exit;
    end;
  end;

  floatValue := AValue;
  if floatValue = AValue then
  begin
    FBuffer[FOffset] := Byte(DOUBLE_FLOAT); Inc(FOffset);
    intValue := PInteger(@floatValue)^;
    FBuffer[FOffset] := Byte(intValue shr 24); Inc(FOffset);
    FBuffer[FOffset] := Byte(intValue shr 16); Inc(FOffset);
    FBuffer[FOffset] := Byte(intValue shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(intValue); Inc(FOffset);
    exit;
  end;

  FBuffer[FOffset] := Byte('D'); Inc(FOffset);
  longValue := PInt64(@AValue)^;
  FBuffer[FOffset] := Byte(longValue shr 56); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 48); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 40); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 32); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 24); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 16); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue shr 8 ); Inc(FOffset);
  FBuffer[FOffset] := Byte(longValue); Inc(FOffset);
end;

procedure THessian2Output.WriteBoolean(AValue: boolean);
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if AValue then
  begin
    FBuffer[FOffset] := Byte('T'); Inc(FOffset);
  end
  else begin
    FBuffer[FOffset] := Byte('F'); Inc(FOffset);
  end
end;

procedure THessian2Output.WriteString(const AValue: WideString);
begin
  _WriteString(AValue, 0, Length(AValue));
end;

procedure THessian2Output.WriteUTCDate(AValue: TDateTime);
var
  UTCValue: int64;
begin
  UTCValue := DateTimeToJavaDate(AValue);

  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('d'); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 56); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 48); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 40); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 32); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 24); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 16); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue shr 8 ); Inc(FOffset);
  FBuffer[FOffset] := Byte(UTCValue); Inc(FOffset);
end;

procedure THessian2Output.WriteNull;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('N'); Inc(FOffset);
end;

procedure THessian2Output.WriteBytes(ASourceStream: TStream);
begin
  if ASourceStream = nil then
  begin
    WriteNull;
  end
  else begin
    WriteBytes(ASourceStream, 0, ASourceStream.Size);
  end;
end;

procedure THessian2Output.WriteBytes(ASourceStream: TStream; AOffset, ACount: integer);
var
  sublen: integer;
  N: integer;
begin
  if ASourceStream = nil then
  begin
    WriteNull;
  end
  else begin
    if AOffset > 0 then
    begin
      ASourceStream.Position := AOffset;
    end
    else begin
      ASourceStream.Position := 0;
    end;

    if BUFFER_SIZE &lt; FOffset + 16 then Flush;

    while ACount > $8000 do
    begin
      FBuffer[FOffset] := Byte('b'); Inc(FOffset);
      FBuffer[FOffset] := Byte($8000 shr 8 ); Inc(FOffset);
      FBuffer[FOffset] := Byte($8000); Inc(FOffset);

      sublen := $8000;
      while sublen > 0 do
      begin
        if sublen > (BUFFER_SIZE - FOffset) then N := BUFFER_SIZE - FOffset else N := sublen;
        ASourceStream.ReadBuffer(FBuffer, N); Inc(FOffset, N);

        // Flush
        FStream.WriteBuffer(FBuffer, FOffset);
        FOffset := 0;

        Dec(sublen, N);
      end;
      ACount := ACount - $8000;
      //AOffset := AOffset + $80000;
    end;

    if ACount &lt; $10 then
    begin
      FBuffer[FOffset] := Byte(BYTES_DIRECT + ACount); Inc(FOffset);
    end
    else begin
      FBuffer[FOffset] := Byte('B'); Inc(FOffset);
      FBuffer[FOffset] := Byte(ACount shr 8 ); Inc(FOffset);
      FBuffer[FOffset] := Byte(ACount); Inc(FOffset);
    end;

    while ACount > 0 do
    begin
      if ACount > (BUFFER_SIZE - FOffset) then N := BUFFER_SIZE - FOffset else N := ACount;
      ASourceStream.ReadBuffer(FBuffer, N); Inc(FOffset, N);

      // Flush
      FStream.WriteBuffer(FBuffer, FOffset);
      FOffset := 0;

      Dec(ACount, N);
    end;
  end
end;

procedure THessian2Output.WriteMapBegin;
begin
  WriteMapBegin('');
end;

procedure THessian2Output.WriteMapBegin(const AType: WideString);
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('M'); Inc(FOffset);
  WriteType(AType);
end;

procedure THessian2Output.WriteMapEnd;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('z'); Inc(FOffset);
end;

function THessian2Output.WriteListBegin(ALength: integer): boolean;
begin
  result := WriteListBegin(ALength, '');
end;

function THessian2Output.WriteListBegin(ALength: integer; const AType: WideString): boolean;
var
  refV: integer;
begin
  if _typeRefs &lt;> nil then
  begin
    refV := _typeRefs.IndexOf(AType);
    if refV >= 0 then
    begin
      refV := Integer(_typeRefs.Objects[refV]);

      if BUFFER_SIZE &lt; FOffset + 16 then Flush;

      FBuffer[FOffset] := Byte(LIST_FIXED); Inc(FOffset);

      WriteInt(refV);
      WriteInt(ALength);

      result := false;
      exit;
    end
  end;

  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('V'); Inc(FOffset);
  WriteType(AType);

  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if ALength &lt; 0 then
  begin
  end
  else if ALength &lt; $100 then
  begin
    FBuffer[FOffset] := Byte(LENGTH_BYTE); Inc(FOffset);
    FBuffer[FOffset] := Byte(ALength); Inc(FOffset);
  end
  else begin
    FBuffer[FOffset] := Byte('l'); Inc(FOffset);
    FBuffer[FOffset] := Byte(ALength shr 24); Inc(FOffset);
    FBuffer[FOffset] := Byte(ALength shr 16); Inc(FOffset);
    FBuffer[FOffset] := Byte(ALength shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(ALength); Inc(FOffset);
  end;
  result := True;
end;

procedure THessian2Output.WriteListEnd;
begin
  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  FBuffer[FOffset] := Byte('z'); Inc(FOffset);
end;

procedure THessian2Output._WriteString(const AValue: WideString; AOffset, ACount: integer);
var
  sublen: integer;
  tail: integer;
begin
  while ACount > $8000 do
  begin
    if BUFFER_SIZE &lt; FOffset + 16 then Flush;

    sublen := $8000;
    // chunk can't end in high surrogate
    tail := Integer(AValue[AOffset + sublen - 1]);
    if ($D800 &lt;= tail) and (tail &lt;= $DBFF) then dec(sublen);

    FBuffer[FOffset] := Byte('s'); Inc(FOffset);
    FBuffer[FOffset] := Byte(sublen shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(sublen); Inc(FOffset);

    PrintString(AValue, AOffset, sublen);

    ACount := ACount - sublen;
    AOffset := AOffset + sublen;
  end;

  if BUFFER_SIZE &lt; FOffset + 16 then Flush;

  if ACount &lt;= STRING_DIRECT_MAX then
  begin
    FBuffer[FOffset] := Byte(STRING_DIRECT + ACount); Inc(FOffset);
  end
  else begin
    FBuffer[FOffset] := Byte('S'); Inc(FOffset);
    FBuffer[FOffset] := Byte(ACount shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(ACount); Inc(FOffset);
  end;
  PrintString(AValue, AOffset, ACount);
end;

procedure THessian2Output.WriteType(const AType: WideString);
var
  Len: integer;
  typeRefV: integer;
begin
  Len := Length(AType);
  if Len = 0 then exit;

  if _typeRefs = nil then
  begin
    _typeRefs := TStringList.Create;
  end;

  typeRefV := _typeRefs.IndexOf(AType);
  if typeRefV >= 0 then
  begin
    typeRefV := Integer(_typeRefs.Objects[typeRefV]);

    if BUFFER_SIZE &lt; FOffset + 16 then Flush;

    FBuffer[FOffset] := Byte(TYPE_REF); Inc(FOffset);

    writeInt(typeRefV);
  end
  else begin
    _typeRefs.AddObject(AType, TObject(_typeRefs.Count));

    if BUFFER_SIZE &lt; FOffset + 16 then Flush;

    FBuffer[FOffset] := Byte('t'); Inc(FOffset);
    FBuffer[FOffset] := Byte(Len shr 8 ); Inc(FOffset);
    FBuffer[FOffset] := Byte(Len); Inc(FOffset);
    PrintString(AType, 0, Len);
  end
end;

procedure THessian2Output.PrintString(const AValue: WideString; AOffset, ACount: integer);
var
  I: integer;
  ch: integer;
begin
  for i := 1 to ACount do
  begin
    if BUFFER_SIZE &lt; FOffset + 16 then Flush;

    // encoded as UTF-8
    ch := Integer(AValue[i + AOffset]);
    if ch &lt; $80 then
    begin
      FBuffer[FOffset] := Byte(ch); Inc(FOffset);
    end
    else if ch &lt; $800 then
    begin
      FBuffer[FOffset] := Byte($C0 + ((ch shr 6) and $1F)); Inc(FOffset);
      FBuffer[FOffset] := Byte($80 + (ch and $3F)); Inc(FOffset);
    end
    else begin
      FBuffer[FOffset] := Byte($E0 + ((ch shr 12) and $F)); Inc(FOffset);
      FBuffer[FOffset] := Byte($80 + ((ch shr 6) and $3F)); Inc(FOffset);
      FBuffer[FOffset] := Byte($80 + (ch and $3F)); Inc(FOffset);
    end
  end
end;

procedure THessian2Output.Flush;
var
  offset: integer;
begin
  offset := FOffset;
  if offset > 0 then
  begin
    FOffset := 0;
    FStream.WriteBuffer(FBuffer, offset);
  end
end;
end.
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/129854#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 08 Oct 2007 17:51:40 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/129854</link>
        <guid>http://gwbasic.javaeye.com/blog/129854</guid>
      </item>
      <item>
        <title>GWT和AOP</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/40194" style="color:red;">http://gwbasic.javaeye.com/blog/40194</a>&nbsp;
          发表时间: 2006年12月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          上文<a href="http://gwbasic.javaeye.com/admin/show/39079" target="_blank">http://gwbasic.javaeye.com/admin/show/39079</a>提到的GWTSpringController.java,继承的是GWT中的RemoteServiceServlet类,在使用过程中发现这个类不支持AOP,原因<br /><pre name="code" class="java">
public String processCall(String payload) throws SerializationException {
  // .............
  // ............
      // Actually get the service interface, so that we can query its methods.
    //
    Class serviceIntf; 
    try {
      // 此处的serviceIntf,是用getClassForName获取的,没有经过proxy代理
      serviceIntf = getClassFromName(serviceIntfName);
    } catch (ClassNotFoundException e) {
      throw new SerializationException("Unknown service interface class '"
          + serviceIntfName + "'", e);
    }

    // Read the method name.
    //
    String methodName = streamReader.readString();

    // Read the number and names of the parameter classes from the stream.
    // We have to do this so that we can find the correct overload of the
    // method.
    //
    int paramCount = streamReader.readInt();
    Class[] paramTypes = new Class[paramCount];
    for (int i = 0; i &lt; paramTypes.length; i++) {
      String paramClassName = streamReader.readString();
      try {
        paramTypes[i] = getClassOrPrimitiveFromName(paramClassName);
      } catch (ClassNotFoundException e) {
        throw new SerializationException("Unknown parameter " + i + " type '"
            + paramClassName + "'", e);
      }
    }

    // For security, make sure the method is found in the service interface
    // and not just one that happens to be defined on this class.
    //
    Method serviceIntfMethod = findInterfaceMethod(serviceIntf, methodName,
        paramTypes, true);
}
</pre><br /><br />于是参照RemoteServiceServlet重新写了一个在Spring中使用的Controller<br />GWTServiceController<br /><pre name="code" class="java">

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracle;
import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracleImpl;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;

public class GWTServiceController implements ServletContextAware, Controller {
	private ServletContext servletContext;

	/** Object we'll invoke methods on. Defaults to this. */
	private Object delegate;

	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	public ServletContext getServletContext() {
		return servletContext;
	}

	public Object getDelegate() {
		return delegate;
	}

	public void setDelegate(Object delegate) {
		this.delegate = delegate;
		registerImplementedRemoteServiceInterface(this.delegate);
	}

	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		doPost(request, response);
		return null;
	}

	/*
	 * These members are used to get and set the different HttpServletResponse and
	 * HttpServletRequest headers.
	 */
	private static final String ACCEPT_ENCODING = "Accept-Encoding";

	private static final String CHARSET_UTF8 = "UTF-8";

	private static final String CONTENT_ENCODING = "Content-Encoding";

	private static final String CONTENT_ENCODING_GZIP = "gzip";

	private static final String CONTENT_TYPE_TEXT_PLAIN_UTF8 = "text/plain; charset=utf-8";

	private static final String GENERIC_FAILURE_MSG = "The call failed on the server; see server log for details";

	private static final HashMap TYPE_NAMES;

	/**
	 * Controls the compression threshold at and below which no compression will
	 * take place.
	 */
	private static final int UNCOMPRESSED_BYTE_SIZE_LIMIT = 256;

	static {
		TYPE_NAMES = new HashMap();
		TYPE_NAMES.put("Z", boolean.class);
		TYPE_NAMES.put("B", byte.class);
		TYPE_NAMES.put("C", char.class);
		TYPE_NAMES.put("D", double.class);
		TYPE_NAMES.put("F", float.class);
		TYPE_NAMES.put("I", int.class);
		TYPE_NAMES.put("J", long.class);
		TYPE_NAMES.put("S", short.class);
	}

	/**
	 * Return true if the response object accepts Gzip encoding. This is done by
	 * checking that the accept-encoding header specifies gzip as a supported
	 * encoding.
	 */
	private static boolean acceptsGzipEncoding(HttpServletRequest request) {
		assert (request != null);

		String acceptEncoding = request.getHeader(ACCEPT_ENCODING);
		if (null == acceptEncoding) {
			return false;
		}

		return (acceptEncoding.indexOf(CONTENT_ENCODING_GZIP) != -1);
	}

	/**
	 * This method attempts to estimate the number of bytes that a string will
	 * consume when it is sent out as part of an HttpServletResponse. This really
	 * a hack since we are assuming that every character will consume two bytes
	 * upon transmission. This is definitely not true since some characters
	 * actually consume more than two bytes and some consume less. This is even
	 * less accurate if the string is converted to UTF8. However, it does save us
	 * from converting every string that we plan on sending back to UTF8 just to
	 * determine that we should not compress it.
	 */
	private static int estimateByteSize(final String buffer) {
		return (buffer.length() * 2);
	}

	/**
	 * Find the invoked method on either the specified interface or any super.
	 */
	private static Method findInterfaceMethod(Class intf, String methodName, Class[] paramTypes,
			boolean includeInherited) {
		try {
			return intf.getDeclaredMethod(methodName, paramTypes);
		} catch (NoSuchMethodException e) {
			if (includeInherited) {
				Class[] superintfs = intf.getInterfaces();
				for (int i = 0; i &lt; superintfs.length; i++) {
					Method method = findInterfaceMethod(superintfs[i], methodName, paramTypes, true);
					if (method != null) {
						return method;
					}
				}
			}

			return null;
		}
	}

	private final ServerSerializableTypeOracle serializableTypeOracle;

	/**
	 * The default constructor.
	 */
	public GWTServiceController() {
		serializableTypeOracle = new ServerSerializableTypeOracleImpl(getPackagePaths());
		this.delegate = this;
		registerImplementedRemoteServiceInterface(this.delegate);
	}

	/**
	 * This is called internally.
	 */
	public final void doPost(HttpServletRequest request, HttpServletResponse response) {
		Throwable caught;
		try {

			// Read the request fully.
			//
			String requestPayload = readPayloadAsUtf8(request);

			// Invoke the core dispatching logic, which returns the serialized
			// result.
			//
			String responsePayload = processCall(requestPayload);

			// Write the response.
			//
			writeResponse(request, response, responsePayload);
			return;
		} catch (IOException e) {
			caught = e;
		} catch (ServletException e) {
			caught = e;
		} catch (SerializationException e) {
			caught = e;
		} catch (Throwable e) {
			caught = e;
		}

		respondWithFailure(response, caught);
	}

	/**
	 * This is public so that it can be unit tested easily without HTTP.
	 */
	public String processCall(String payload) throws SerializationException {

		// Let subclasses see the serialized request.
		//
		onBeforeRequestDeserialized(payload);

		// Create a stream to deserialize the request.
		//
		ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(serializableTypeOracle);
		streamReader.prepareToRead(payload);

		// Read the service interface
		//
		String serviceIntfName = streamReader.readString();

		// TODO(mmendez): need a way to check the type signature of the service intf
		// Verify that this very servlet implements the specified interface name.
		// 从delegate中获取serviceIntf
		Class serviceIntf = getImplementedRemoteServiceInterface(serviceIntfName);
		if (serviceIntf == null) {
			// Bad payload, possible hack attempt.
			//
			throw new SecurityException(
					"Blocked attempt to access interface '"
							+ serviceIntfName
							+ "', which is either not implemented by this servlet or which doesn't extend RemoteService; this is either misconfiguration or a hack attempt");
		}

		// Read the method name.
		//
		String methodName = streamReader.readString();

		// Read the number and names of the parameter classes from the stream.
		// We have to do this so that we can find the correct overload of the
		// method.
		//
		int paramCount = streamReader.readInt();
		Class[] paramTypes = new Class[paramCount];
		for (int i = 0; i &lt; paramTypes.length; i++) {
			String paramClassName = streamReader.readString();
			try {
				paramTypes[i] = getClassOrPrimitiveFromName(paramClassName);
			} catch (ClassNotFoundException e) {
				throw new SerializationException("Unknown parameter " + i + " type '" + paramClassName + "'", e);
			}
		}

		// For security, make sure the method is found in the service interface
		// and not just one that happens to be defined on this class.
		//
		Method serviceIntfMethod = findInterfaceMethod(serviceIntf, methodName, paramTypes, true);

		// If it wasn't found, don't continue.
		//
		if (serviceIntfMethod == null) {
			// Bad payload, possible hack attempt.
			//
			throw new SecurityException("Method '" + methodName + "' (or a particular overload) on interface '"
					+ serviceIntfName + "' was not found, this is either misconfiguration or a hack attempt");
		}

		// Deserialize the parameters.
		//
		Object[] args = new Object[paramCount];
		for (int i = 0; i &lt; args.length; i++) {
			args[i] = streamReader.deserializeValue(paramTypes[i]);
		}

		// Make the call via reflection.
		//
		String responsePayload = GENERIC_FAILURE_MSG;
		ServerSerializationStreamWriter streamWriter = new ServerSerializationStreamWriter(serializableTypeOracle);
		Throwable caught = null;
		try {
			Class returnType = serviceIntfMethod.getReturnType();
			Object returnVal = serviceIntfMethod.invoke(this.delegate, args);
			responsePayload = createResponse(streamWriter, returnType, returnVal, false);
		} catch (IllegalArgumentException e) {
			caught = e;
		} catch (IllegalAccessException e) {
			caught = e;
		} catch (InvocationTargetException e) {
			// Try to serialize the caught exception if the client is expecting it,
			// otherwise log the exception server-side.
			caught = e;
			Throwable cause = e.getCause();
			if (cause != null) {
				// Update the caught exception to the underlying cause
				caught = cause;
				// Serialize the exception back to the client if it's a declared
				// exception
				if (isExpectedException(serviceIntfMethod, cause)) {
					Class thrownClass = cause.getClass();
					responsePayload = createResponse(streamWriter, thrownClass, cause, true);
					// Don't log the exception on the server
					caught = null;
				}
			}
		}

		if (caught != null) {
			responsePayload = GENERIC_FAILURE_MSG;
			ServletContext servletContext = getServletContext();
			// servletContext may be null (for example, when unit testing)
			if (servletContext != null) {
				// Log the exception server side
				servletContext.log("Exception while dispatching incoming RPC call", caught);
			}
		}

		// Let subclasses see the serialized response.
		//
		onAfterResponseSerialized(responsePayload);

		return responsePayload;
	}

	/**
	 * Override this method to examine the serialized response that will be
	 * returned to the client. The default implementation does nothing and need
	 * not be called by subclasses.
	 */
	protected void onAfterResponseSerialized(String serializedResponse) {
	}

	/**
	 * Override this method to examine the serialized version of the request
	 * payload before it is deserialized into objects. The default implementation
	 * does nothing and need not be called by subclasses.
	 */
	protected void onBeforeRequestDeserialized(String serializedRequest) {
	}

	/**
	 * Determines whether the response to a given servlet request should or should
	 * not be GZIP compressed. This method is only called in cases where the
	 * requestor accepts GZIP encoding.
	 * &lt;p>
	 * This implementation currently returns &lt;code>true&lt;/code> if the response
	 * string's estimated byte length is longer than 256 bytes. Subclasses can
	 * override this logic.
	 * &lt;/p>
	 * 
	 * @param request the request being served
	 * @param response the response that will be written into
	 * @param responsePayload the payload that is about to be sent to the client
	 * @return &lt;code>true&lt;/code> if responsePayload should be GZIP compressed,
	 *         otherwise &lt;code>false&lt;/code>.
	 */
	protected boolean shouldCompressResponse(HttpServletRequest request, HttpServletResponse response,
			String responsePayload) {
		return estimateByteSize(responsePayload) > UNCOMPRESSED_BYTE_SIZE_LIMIT;
	}

	/**
	 * @param stream
	 * @param responseType
	 * @param responseObj
	 * @param isException
	 * @return response
	 */
	private String createResponse(ServerSerializationStreamWriter stream, Class responseType,
			Object responseObj, boolean isException) {
		stream.prepareToWrite();
		if (responseType != void.class) {
			try {
				stream.serializeValue(responseObj, responseType);
			} catch (SerializationException e) {
				responseObj = e;
				isException = true;
			}
		}

		String bufferStr = (isException ? "{EX}" : "{OK}") + stream.toString();
		return bufferStr;
	}

	/**
	 * Returns the {@link Class} instance for the named class.
	 * 
	 * @param name the name of a class or primitive type
	 * @return Class instance for the given type name
	 * @throws ClassNotFoundException if the named type was not found
	 */
	private Class getClassFromName(String name) throws ClassNotFoundException {
		return Class.forName(name, false, this.getClass().getClassLoader());
	}

	/**
	 * Returns the {@link Class} instance for the named class or primitive type.
	 * 
	 * @param name the name of a class or primitive type
	 * @return Class instance for the given type name
	 * @throws ClassNotFoundException if the named type was not found
	 */
	private Class getClassOrPrimitiveFromName(String name) throws ClassNotFoundException {
		Object value = TYPE_NAMES.get(name);
		if (value != null) {
			return (Class) value;
		}

		return getClassFromName(name);
	}

	/**
	 * Obtain the special package-prefixes we use to check for custom serializers
	 * that would like to live in a package that they cannot. For example,
	 * "java.util.ArrayList" is in a sealed package, so instead we use this prefix
	 * to check for a custom serializer in
	 * "com.google.gwt.user.client.rpc.core.java.util.ArrayList". Right now, it's
	 * hard-coded because we don't have a pressing need for this mechanism to be
	 * extensible, but it is imaginable, which is why it's implemented this way.
	 */
	private String[] getPackagePaths() {
		return new String[] { "com.google.gwt.user.client.rpc.core" };
	}

	/**
	 * Returns true if the {@link java.lang.reflect.Method Method} definition on
	 * the service is specified to throw the exception contained in the
	 * InvocationTargetException or false otherwise. NOTE we do not check that the
	 * type is serializable here. We assume that it must be otherwise the
	 * application would never have been allowed to run.
	 * 
	 * @param serviceIntfMethod
	 * @param e
	 * @return is expected exception
	 */
	private boolean isExpectedException(Method serviceIntfMethod, Throwable cause) {
		assert (serviceIntfMethod != null);
		assert (cause != null);

		Class[] exceptionsThrown = serviceIntfMethod.getExceptionTypes();
		if (exceptionsThrown.length &lt;= 0) {
			// The method is not specified to throw any exceptions
			//
			return false;
		}

		Class causeType = cause.getClass();

		for (int index = 0; index &lt; exceptionsThrown.length; ++index) {
			Class exceptionThrown = exceptionsThrown[index];
			assert (exceptionThrown != null);

			if (exceptionThrown.isAssignableFrom(causeType)) {
				return true;
			}
		}

		return false;
	}

	private final Map&lt;String, Class> knownImplementedInterfacesMap = new HashMap&lt;String, Class>();

	private void registerImplementedRemoteServiceInterface(Object delegate) {
		this.knownImplementedInterfacesMap.clear();
		if (delegate != null) {
			Class cls = delegate.getClass();
			if (cls.isInterface()) {
				addImplementedRemoteServiceInterfaceRecursive(cls);
			} else {
				while (cls != null) {
					Class[] intfs = cls.getInterfaces();
					for (int i = 0; i &lt; intfs.length; i++) {
						addImplementedRemoteServiceInterfaceRecursive(intfs[i]);
					}

					// we look in the superclass
					cls = cls.getSuperclass();
				}
			}
		}
	}

	private void addImplementedRemoteServiceInterfaceRecursive(Class intfToCheck) {
		assert (intfToCheck.isInterface());

		if (RemoteService.class.equals(intfToCheck))
			return;

		if (RemoteService.class.isAssignableFrom(intfToCheck)) {
			this.knownImplementedInterfacesMap.put(intfToCheck.getName(), intfToCheck);
		}

		Class[] intfs = intfToCheck.getInterfaces();
		for (int i = 0; i &lt; intfs.length; i++) {
			addImplementedRemoteServiceInterfaceRecursive(intfs[i]);
		}
	}

	private Class getImplementedRemoteServiceInterface(String intfName) {
		return this.knownImplementedInterfacesMap.get(intfName);
	}

	private String readPayloadAsUtf8(HttpServletRequest request) throws IOException, ServletException {
		int contentLength = request.getContentLength();
		if (contentLength == -1) {
			// Content length must be known.
			throw new ServletException("Content-Length must be specified");
		}

		String contentType = request.getContentType();
		boolean contentTypeIsOkay = false;
		// Content-Type must be specified.
		if (contentType != null) {
			// The type must be plain text.
			if (contentType.startsWith("text/plain")) {
				// And it must be UTF-8 encoded (or unspecified, in which case we assume
				// that it's either UTF-8 or ASCII).
				if (contentType.indexOf("charset=") == -1) {
					contentTypeIsOkay = true;
				} else if (contentType.indexOf("charset=utf-8") != -1) {
					contentTypeIsOkay = true;
				}
			}
		}
		if (!contentTypeIsOkay) {
			throw new ServletException(
					"Content-Type must be 'text/plain' with 'charset=utf-8' (or unspecified charset)");
		}
		InputStream in = request.getInputStream();
		try {
			byte[] payload = new byte[contentLength];
			int offset = 0;
			int len = contentLength;
			int byteCount;
			while (offset &lt; contentLength) {
				byteCount = in.read(payload, offset, len);
				if (byteCount == -1) {
					throw new ServletException("Client did not send " + contentLength + " bytes as expected");
				}
				offset += byteCount;
				len -= byteCount;
			}
			return new String(payload, "UTF-8");
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	/**
	 * Called when the machinery of this class itself has a problem, rather than
	 * the invoked third-party method. It writes a simple 500 message back to the
	 * client.
	 */
	private void respondWithFailure(HttpServletResponse response, Throwable caught) {
		ServletContext servletContext = getServletContext();
		servletContext.log("Exception while dispatching incoming RPC call", caught);
		try {
			response.setContentType("text/plain");
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			response.getWriter().write(GENERIC_FAILURE_MSG);
		} catch (IOException e) {
			servletContext.log("sendError() failed while sending the previous failure to the client", caught);
		}
	}

	private void writeResponse(HttpServletRequest request, HttpServletResponse response, String responsePayload)
			throws IOException {

		byte[] reply = responsePayload.getBytes(CHARSET_UTF8);
		String contentType = CONTENT_TYPE_TEXT_PLAIN_UTF8;

		if (acceptsGzipEncoding(request) && shouldCompressResponse(request, response, responsePayload)) {
			// Compress the reply and adjust headers.
			//
			ByteArrayOutputStream output = null;
			GZIPOutputStream gzipOutputStream = null;
			Throwable caught = null;
			try {
				output = new ByteArrayOutputStream(reply.length);
				gzipOutputStream = new GZIPOutputStream(output);
				gzipOutputStream.write(reply);
				gzipOutputStream.finish();
				gzipOutputStream.flush();
				response.setHeader(CONTENT_ENCODING, CONTENT_ENCODING_GZIP);
				reply = output.toByteArray();
			} catch (UnsupportedEncodingException e) {
				caught = e;
			} catch (IOException e) {
				caught = e;
			} finally {
				if (null != gzipOutputStream) {
					gzipOutputStream.close();
				}
				if (null != output) {
					output.close();
				}
			}

			if (caught != null) {
				getServletContext().log("Unable to compress response", caught);
				response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
				return;
			}
		}

		// Send the reply.
		//
		response.setContentLength(reply.length);
		response.setContentType(contentType);
		response.setStatus(HttpServletResponse.SC_OK);
		response.getOutputStream().write(reply);
	}

}
</pre><br /><br />// delegate 用法参照 org.springframework.web.servlet.mvc.multiaction.MultiActionController<br /><br /><br /><br /><br /><br /><pre name="code" class="java">
/*
  For GWT 1.4.60
*/
public class GwtRemoteServiceController extends RemoteServiceServlet implements
		Controller, ServletContextAware {
	private static final long serialVersionUID = 8175888785480720736L;

	private Object delegate;

	private ServletContext servletContext;

	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	@Override
	public ServletContext getServletContext() {
		return servletContext;
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		super.doPost(request, response);
		return null;
	}

	@Override
	public String processCall(String payload) throws SerializationException {
		Object delegateToUse = this.delegate;
		if (delegateToUse == null) {
			return super.processCall(payload);
		} else {
			try {
				RPCRequest rpcRequest = RPC.decodeRequest(payload,
						delegateToUse.getClass(), this);
				return RPC.invokeAndEncodeResponse(delegateToUse, rpcRequest
						.getMethod(), rpcRequest.getParameters(), rpcRequest
						.getSerializationPolicy());
			} catch (IncompatibleRemoteServiceException ex) {
				getServletContext()
						.log(
								"An IncompatibleRemoteServiceException was thrown while processing this call.",
								ex);
				return RPC.encodeResponseForFailure(null, ex);
			}
		}
	}

	public Object getDelegate() {
		return delegate;
	}

	public void setDelegate(Object delegate) {
		this.delegate = delegate;
	}
}
</pre><br />开源真好:D
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/40194#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 22 Dec 2006 12:11:22 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/40194</link>
        <guid>http://gwbasic.javaeye.com/blog/40194</guid>
      </item>
      <item>
        <title>文件编码格式转换</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/40192" style="color:red;">http://gwbasic.javaeye.com/blog/40192</a>&nbsp;
          发表时间: 2006年12月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          由于GWT(Google Web Toolkit)需要utf-8编码的源代码(采用gbk会乱码),因此决定将所有的java文件encoding改为utf-8.<br /><br />转换方法:ant<br /><br />build.xml<br /><pre name="code" class="java">
&lt;project name="encoding" default="build">
    &lt;target name="build">    
      &lt;copy todir="e:/output" outputencoding="utf-8">
        &lt;fileset dir=".">
          &lt;include name="**/*.java"/>
        &lt;/fileset>
      &lt;/copy>
    &lt;/target>
&lt;/project>
</pre><br /><br /><br />先把源代码全部用utf-8格式拷贝到e:/output,然后再把output中的所有文件拷贝到原先的地方就可以.<br /><br />Eclipse的菜单 Windows\Preferences\Workspace\Text file encoding 改成 utf-8
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/40192#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 22 Dec 2006 11:58:25 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/40192</link>
        <guid>http://gwbasic.javaeye.com/blog/40192</guid>
      </item>
      <item>
        <title>试用GWT-1</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/39079" style="color:red;">http://gwbasic.javaeye.com/blog/39079</a>&nbsp;
          发表时间: 2006年12月14日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Google Web Toolkit终于完全开源了,开心!<br />写Javascript太烦了,早就想换了,这次gwt开源,正是一个好机会.<br />第一天试用,便测试了与Spring的整合,参考了http://gwt-widget.sourceforge.net/中的GWT Server Library (GWT-SL) 0.1.2 Released 中的 GWTSpringController.java<br /><pre name="code" class="java">
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class GWTSpringController extends RemoteServiceServlet implements ServletContextAware, Controller {

	private ServletContext servletContext;

	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}

	@Override
	public ServletContext getServletContext() {
		return servletContext;
	}

	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		doPost(request, response);
		return null;
	}
}</pre><br /><br />客户端代码:<br /><pre name="code" class="java">
// File LoginForm.java
import com.google.gwt.user.client.rpc.IsSerializable;

public class LoginForm implements IsSerializable {
	private String usercode;
	private String pwd;
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	public String getUsercode() {
		return usercode;
	}
	public void setUsercode(String usercode) {
		this.usercode = usercode;
	}
}

// File LoginSvr.java
import com.google.gwt.user.client.rpc.RemoteService;
import com.connstar.client.form.LoginForm;

public interface LoginSvr extends RemoteService {
	Integer queryUserPwd(LoginForm command) throws Exception;
}

// File LoginSvrAsync.java
import com.connstar.client.form.LoginForm;
import com.google.gwt.user.client.rpc.AsyncCallback;

public interface LoginSvrAsync {
	void queryUserPwd(LoginForm form, AsyncCallback callback);
}

// 远程调用代码
  Button rpcButton = new Button("RPC");
  rpcButton.addClickListener(new ClickListener() {
		public void onClick(Widget sender) {
			LoginSvrAsync loginService = (LoginSvrAsync) GWT.create(LoginSvr.class);
			ServiceDefTarget endpoint = (ServiceDefTarget) loginService;
			endpoint.setServiceEntryPoint("http://127.0.0.1:8080/test/gwt/login");
			AsyncCallback callback = new AsyncCallback() {
				public void onSuccess(Object result) {
					Window.alert("success:" + result.toString());
				}

				public void onFailure(Throwable caught) {
					Window.alert("failure:" + caught.toString());
				}
			};

			LoginForm form = new LoginForm();
			form.setUsercode("用户名");
			form.setPwd("密码");
			loginService.queryUserPwd(form, callback);
		}
	});            
</pre><br /><br />试用成功.<br /><br />其中注意的是在服务器端也要包含 com.google.gwt.user.client.rpc.core这个包<br />,是实例化Character, Byte, Short, Integer, Long, Boolean, Float, or Double,ArrayList,HashMap等类用的.<br /><br /> A type is serializable and can be used in a service interface if it<br />    * is primitive, such as char, byte, short, int, long, boolean, float, or double;<br />    * is String, Date, or a primitive wrapper such as Character, Byte, Short, Integer, Long, Boolean, Float, or Double;<br />    * is an array of serializable types (including other serializable arrays);<br />    * is a serializable user-defined class; or<br />    * has at least one serializable subclass<br /><br />Java源文件建议使用utf-8编码,否则会乱码.
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/39079#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 14 Dec 2006 19:31:38 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/39079</link>
        <guid>http://gwbasic.javaeye.com/blog/39079</guid>
      </item>
      <item>
        <title>JAVA SE6.0 发布</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/38608" style="color:red;">http://gwbasic.javaeye.com/blog/38608</a>&nbsp;
          发表时间: 2006年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          今天Java se6.0发布了吗?<br /><br />http://java.sun.com好慢呀
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/38608#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 11 Dec 2006 22:21:58 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/38608</link>
        <guid>http://gwbasic.javaeye.com/blog/38608</guid>
      </item>
      <item>
        <title>JIRA安装</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/38464" style="color:red;">http://gwbasic.javaeye.com/blog/38464</a>&nbsp;
          发表时间: 2006年12月11日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          本次安装环境<br />JAVA: JAVA 1.6 beta2<br />APPSERVER: TOMCAT 5.5.20<br />DATABASE: MSSQL 2000<br /><br />1.下载JIRA(ZIP版)<br />http://www.atlassian.com/software/jira/<br /><br />2.解压缩到<strong>{JIRA_DIR}</strong><br /><br />3. 修改<strong>{JIRA_DIR}</strong>\edit-webapp\WEB-INF\classes\entityengine.xml<br />   &lt;!-- 数据库改成mssql --><br />  &lt;datasource name="defaultDS" field-type-name="<strong>mssql</strong>"<br />        helper-class="org.ofbiz.core.entity.GenericHelperDAO"<br />      check-on-start="true"<br />      use-foreign-keys="false"<br />      use-foreign-key-indices="false"<br />      check-fks-on-start="false"<br />      check-fk-indices-on-start="false"<br />      add-missing-on-start="true"<br />      check-indices-on-start="true"><br /><br />4. 编译JIRA系统,DOS下运行命令<br />   {JIRA_DIR}\build war<br /><br />5.下载TOMCAT下必须的库文件<br />http://www.atlassian.com/software/jira/docs/servers/jars/3.6.5/jira-jars-tomcat5.zip<br />参见:<br />http://www.atlassian.com/software/jira/docs/latest/servers/tomcat55.html<br /><br />6. 修改 TOMCAT下 server.xml,增加如下内容<br />   <br />&lt;Context path="/jira" docBase="<strong>{JIRA_DIR}</strong>\dist-tomcat\atlassian-jira-3.6.5.war" debug="0"><br /><br /> &lt;Resource name="jdbc/JiraDS" auth="Container" type="javax.sql.DataSource"<br />            username="<strong>数据库用户名</strong>"<br />            password="<strong>数据库密码</strong>"<br />            driverClassName="net.sourceforge.jtds.jdbc.Driver"<br />            url="jdbc:jtds:sqlserver://localhost:1433/jiradb"<br />            /><br /><br />          &lt;Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction"<br />            factory="org.objectweb.jotm.UserTransactionFactory" jotm.timeout="60"/><br />          &lt;Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="false"/><br />&lt;/Context><br /><br />7.在mssql里,新建数据库 jiradb<br /><br />8.启动tomcat5,安装jira.<br /><br /><br />jira序列号,购买,开源项目(免费),盗版(google搜索)
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/38464#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, 11 Dec 2006 10:41:34 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/38464</link>
        <guid>http://gwbasic.javaeye.com/blog/38464</guid>
      </item>
      <item>
        <title>Javascript 解析,格式化日期</title>
        <author>gwbasic</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://gwbasic.javaeye.com">gwbasic</a>&nbsp;
          链接：<a href="http://gwbasic.javaeye.com/blog/36904" style="color:red;">http://gwbasic.javaeye.com/blog/36904</a>&nbsp;
          发表时间: 2006年12月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="js">
/*
  将String类型解析为Date类型.
  parseDate('2006-1-1') return new Date(2006,0,1)
  parseDate(' 2006-1-1 ') return new Date(2006,0,1)
  parseDate('2006-1-1 15:14:16') return new Date(2006,0,1,15,14,16)
  parseDate(' 2006-1-1 15:14:16 ') return new Date(2006,0,1,15,14,16);
  parseDate('2006-1-1 15:14:16.254') return new Date(2006,0,1,15,14,16,254)
  parseDate(' 2006-1-1 15:14:16.254 ') return new Date(2006,0,1,15,14,16,254)
  parseDate('不正确的格式') retrun null
*/
function parseDate(str){
  if(typeof str == 'string'){
    var results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) *$/);
    if(results && results.length>3)
      return new Date(parseInt(results[1]),parseInt(results[2]) -1,parseInt(results[3])); 
    results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2}) *$/);
    if(results && results.length>6)
      return new Date(parseInt(results[1]),parseInt(results[2]) -1,parseInt(results[3]),parseInt(results[4]),parseInt(results[5]),parseInt(results[6])); 
    results = str.match(/^ *(\d{4})-(\d{1,2})-(\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})\.(\d{1,9}) *$/);
    if(results && results.length>7)
      return new Date(parseInt(results[1]),parseInt(results[2]) -1,parseInt(results[3]),parseInt(results[4]),parseInt(results[5]),parseInt(results[6]),parseInt(results[7])); 
  }
  return null;
}

/*
  将Date/String类型,解析为String类型.
  传入String类型,则先解析为Date类型
  不正确的Date,返回 ''
  如果时间部分为0,则忽略,只返回日期部分.
*/
function formatDate(v){
  if(typeof v == 'string') v = parseDate(v);
  if(v instanceof Date){
    var y = v.getFullYear();
    var m = v.getMonth() + 1;
    var d = v.getDate();
    var h = v.getHours();
    var i = v.getMinutes();
    var s = v.getSeconds();
    var ms = v.getMilliseconds();   
    if(ms>0) return y + '-' + m + '-' + d + ' ' + h + ':' + i + ':' + s + '.' + ms;
    if(h>0 || i>0 || s>0) return y + '-' + m + '-' + d + ' ' + h + ':' + i + ':' + s;
    return y + '-' + m + '-' + d;
  }
  return '';
}
</pre>
          <br/>
          <span style="color:red;">
            <a href="http://gwbasic.javaeye.com/blog/36904#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 01 Dec 2006 17:13:09 +0800</pubDate>
        <link>http://gwbasic.javaeye.com/blog/36904</link>
        <guid>http://gwbasic.javaeye.com/blog/36904</guid>
      </item>
  </channel>
</rss>