﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-每日一得-随笔分类-java</title><link>http://www.blogjava.net/alex/category/5488.html</link><description>不求多得,只求一得
about java,hibernate,spring,design,database,Ror,ruby,快速开发&lt;br/&gt;
最近关心的内容:Jboss Seam框架，JSF,EJB3 &lt;br/&gt;
本站的官方站点是:&lt;a href="www.foxlog.org"&gt;www.foxlog.org&lt;/a&gt;
</description><language>zh-cn</language><lastBuildDate>Sat, 01 Sep 2007 05:48:58 GMT</lastBuildDate><pubDate>Sat, 01 Sep 2007 05:48:58 GMT</pubDate><ttl>60</ttl><item><title>java框架库：选一款适合你的武器行走江湖</title><link>http://www.blogjava.net/alex/archive/2007/09/01/141902.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sat, 01 Sep 2007 04:42:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/09/01/141902.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/141902.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/09/01/141902.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/141902.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/141902.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 很多东西是拿来被利用的，被 Fuck的，不是让你消磨时间的.&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/09/01/141902.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/141902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-09-01 12:42 <a href="http://www.blogjava.net/alex/archive/2007/09/01/141902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring中的service之间如何调用</title><link>http://www.blogjava.net/alex/archive/2007/05/14/117228.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 14 May 2007 01:05:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/05/14/117228.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/117228.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/05/14/117228.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/117228.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/117228.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/05/14/117228.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/117228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-05-14 09:05 <a href="http://www.blogjava.net/alex/archive/2007/05/14/117228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谈谈方法中的返回值类型和参数类型</title><link>http://www.blogjava.net/alex/archive/2007/05/13/117126.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sun, 13 May 2007 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/05/13/117126.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/117126.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/05/13/117126.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/117126.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/117126.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/05/13/117126.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/117126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-05-13 17:15 <a href="http://www.blogjava.net/alex/archive/2007/05/13/117126.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>简单就是美 -- 简化hibernate,简化dao</title><link>http://www.blogjava.net/alex/archive/2007/05/13/117118.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sun, 13 May 2007 08:41:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/05/13/117118.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/117118.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/05/13/117118.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/117118.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/117118.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/05/13/117118.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/117118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-05-13 16:41 <a href="http://www.blogjava.net/alex/archive/2007/05/13/117118.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在oracle application server中部署jstl和struts,以及log4j</title><link>http://www.blogjava.net/alex/archive/2007/05/08/116023.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 08 May 2007 11:11:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/05/08/116023.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/116023.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/05/08/116023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/116023.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/116023.html</trackback:ping><description><![CDATA[<p>key words: jstl,struts,log4j<br><br>1.jstl<br>jstl的配置参考这篇文章：<br><a href="http://foolmouse.cnblogs.com/archive/2006/04/20/380695.html">http://foolmouse.cnblogs.com/archive/2006/04/20/380695.html</a><br><br>在iAS904服务器上的jstl的版本只能用1.0 的<br>"standard.jar和jstl.jar文件拷贝到\WEB-INF\lib\<br>"<br><br>2.struts<br>struts的配置主要是把 相关jar文件(struts.jar,struts-legacy.jar)拷贝到\WEB-INF\lib<br>,另外，struts需要用到一些apache的commons的包(commons-beanutils.jar,commons-collections-2.1.1.jar,commons-digester.jar)<br><br>3.log4j<br>log4j经常有莫名其妙的问题，有时候能出来log有时候又不能出来log，最后把log4j.xml统一改为log4j.properties,暂时看好像有效果。<br><br>4。web.xml配置<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">http://java.sun.com/jsp/jstl/core</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/c-1_0.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-bean.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-bean.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-html.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-html.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-logic.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-uri</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000">/WEB-INF/struts-logic.tld</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib-location</span><span style="COLOR: #0000ff">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.blogjava.net/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">&lt;/</span><span style="COLOR: #800000">taglib</span><span style="COLOR: #0000ff">&gt;</span></div>
<br><br>今天终于先在iAS里部署完了struts,下一步把hibernate放进去，上次部署过一次，没有成功，据说是和toplink有点冲突。 知道的兄弟分享下oc4j中部署hibernate<br>
<img src ="http://www.blogjava.net/alex/aggbug/116023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-05-08 19:11 <a href="http://www.blogjava.net/alex/archive/2007/05/08/116023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]插入图片到数据库(BLOB大字段保存对象)</title><link>http://www.blogjava.net/alex/archive/2007/03/28/107018.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 28 Mar 2007 08:55:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/03/28/107018.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/107018.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/03/28/107018.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/107018.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/107018.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/03/28/107018.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/107018.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-03-28 16:55 <a href="http://www.blogjava.net/alex/archive/2007/03/28/107018.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hashMap不排序啊</title><link>http://www.blogjava.net/alex/archive/2007/03/20/105020.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 20 Mar 2007 08:23:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/03/20/105020.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/105020.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/03/20/105020.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/105020.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/105020.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/03/20/105020.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/105020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-03-20 16:23 <a href="http://www.blogjava.net/alex/archive/2007/03/20/105020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>真正理解面向接口编程</title><link>http://www.blogjava.net/alex/archive/2007/03/12/103185.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sun, 11 Mar 2007 16:40:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/03/12/103185.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/103185.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/03/12/103185.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/103185.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/103185.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2007/03/12/103185.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/103185.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-03-12 00:40 <a href="http://www.blogjava.net/alex/archive/2007/03/12/103185.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[讨论]上传文件放在哪里比较合适?</title><link>http://www.blogjava.net/alex/archive/2007/01/31/96831.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 31 Jan 2007 01:06:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/01/31/96831.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/96831.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/01/31/96831.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/96831.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/96831.html</trackback:ping><description><![CDATA[key words: 上传文件<br><br><em><font color=#800080>目里面有上传文件的需求,我想了一下不外乎下面两种处理方法: </font></em>
<p><em><font color=#800080>1. 在数据库表中建立一个blob字段存放用户上传文件. <br>2. 在服务器上建立一个文件夹保存用户上传文件,数据库表中只存放该文<wbr>件的url地址.</wbr></font></em></p>
<p><em><font color=#800080>我本人现在比较倾向于第2种方案, 主要原因是担心方案1的效率（我用的是mysql数据库）。 但是处理过程中除了维护数据库中表的字段还要维护上传的文件<wbr>,稍微麻烦一点。</wbr></font></em></p>
<p><em><font color=#800080>大家在项目里面又是怎么做呢？ 给我点建议！谢谢</font></em></p>
<br>讨论内容见: <a onclick="return top.js.OpenExtLink(window,event,this)" href="http://www.javaeye.com/topic/18515?page=1" target=_blank>javaeye</a><br><br>robin更建议第二种方案，放在数据库中主要的问题是 AppServer吃不消，开销比较大.<br><br>上面是摘录，不过我们这里用的是Oracle9i AS,在Oracle的协作套间里一般文档或者上传的文件都是保存在数据库里，还把这个特性作为Oracle 与别的协作套件之间不同的卖点。<br><br>大家以为如何? 我直觉是Oracle的DB和oc4j的AppServer对付这个似乎没有开销上的担心，但是没有实际检测过。 <br><br>换句话说，文件的管理是放在文件夹里方便还是数据库里方便? 有点为难 <br><br>update (2007-5-13):<br><span style="COLOR: #0000ff">还有一种方案结合了数据库和IO，我认为比较可行，就是文件存在数据库，但是下载的时候第一次从数据库下载，然后第一次这个文件保存在一个临时文件夹下面，以后每次下载的时候总是先检查此临时文件夹，如果已经存在则直接下载，如果没有则从数据库重复这个动作。当然，保存在临时文件夹下的文件的命名需要唯一，这个应该没有问题。</span>
<img src ="http://www.blogjava.net/alex/aggbug/96831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-01-31 09:06 <a href="http://www.blogjava.net/alex/archive/2007/01/31/96831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>2007计划</title><link>http://www.blogjava.net/alex/archive/2007/01/03/91656.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 03 Jan 2007 15:31:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2007/01/03/91656.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/91656.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2007/01/03/91656.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/91656.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/91656.html</trackback:ping><description><![CDATA[key words: 2007 plans<br /><br />新的一年开始了，制定一个计划吧<br /><br />说说你有什么计划<br /><br />如图:<br /><br /><img height="767" alt="2007-plans.png" src="http://www.blogjava.net/images/blogjava_net/alex/images/2007-plans.png" width="503" border="0" /><img src ="http://www.blogjava.net/alex/aggbug/91656.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2007-01-03 23:31 <a href="http://www.blogjava.net/alex/archive/2007/01/03/91656.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Unsupported major.minor version 49.0错误</title><link>http://www.blogjava.net/alex/archive/2006/11/08/79775.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 08 Nov 2006 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/11/08/79775.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/79775.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/11/08/79775.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/79775.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/79775.html</trackback:ping><description><![CDATA[key words:jdk错误，Unsupported major.minor version<br /><br />今天用一个工作流的产品，非要用jdk1.4的版本，没办法，只好切换回来，但是换回来后打开页面jsp出错，提示Unsupported major.minor version 49.0错误,到网上查了一下，49.0错误属于jdk1.5的错误，但是我的jdk1.5已经删除了啊？怎么回事呢?<br /><br />最后想起来，可能是jboss中的1.5 版本产生临时文件class文件删除，删除后ＯＫ<br /><br /><br />资料:<a href="http://blog.csdn.net/seave/archive/2006/06/05/774943.aspx">Unsupported major.minor version 49.0</a><img src ="http://www.blogjava.net/alex/aggbug/79775.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-11-08 10:13 <a href="http://www.blogjava.net/alex/archive/2006/11/08/79775.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]RBAC 模型初探</title><link>http://www.blogjava.net/alex/archive/2006/10/26/77481.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 26 Oct 2006 13:31:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/10/26/77481.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/77481.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/10/26/77481.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/77481.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/77481.html</trackback:ping><description><![CDATA[
		<p>
				<strong>
						<font size="3">访问控制背景</font>
				</strong>
		</p>
		<p>   
访问控制技术是由美国国防部（Department of Defense,
DoD）资助的研究和开发成果演变而来的。这一研究导致两种基本类型访问控制的产生：自主访问控制（Discretionary Access
Control, DAC）和强制访问控制（Mandatory Access Control,
MAC）。最初的研究和应用主要是为了防止机密信息被未经授权者访问，近期的应用主要是把这些策略应用到为商业领域。</p>
		<p>    自主访问控制，允许把访问控制权的授予和取消留给个体用户来判断。为没有访问控制权的个体用户授予和废除许可。自主访问控制机制允许用户被授权和<br />取
消访问其控制之下的任何客体（object），换句话说，用户就是他们控制下的客体的拥有者。然而，对于多数组织来说，最终用户对所访问的信息没有拥有
权。对于这些组织，公司或代理机构是事实上的系统客体和处理他们的程序的拥有者。访问优先权受组织控制，而且也常常基于雇员功能而不是数据所有权。</p>
		<p>  
强制访问控制，在美国国防部 Trusted Computer Security Evaluation Criteria (TCSEC)
中定义如下：“一种限制访问客体的手段，它以包含在这些客体中的信息敏感性和访问这些敏感性信息的主体的正式授权信息（如清除）为基础”。<br />   <br />  
以上访问控制策略对于处理一些无需保密但又敏感的信息的政府和行业组织的需求并不是特别的适合。在这样的环境下，安全目标支持产生于现有法律、道德规范、
规章、或一般惯例的高端组织策略。这些环境通常需要控制个体行为的能力，而不仅仅是如何根据信息的敏感性为其设置标签从而访问这一信息的个人能力。<br />     </p>
		<p>
				<br />
				<strong>
						<font size="3">什么是基于角色访问控制（Role-Based Access Control, RBAC）？NIST 有如下定义。<br /></font>
				</strong>   <br />  
访问是一种利用计算机资源去做某件事情的的能力，访问控制是一种手段，通过它这种能力在某些情况下被允许或者受限制（通常是通过物理上和基于系统的控
制）。基于计算机的访问控制不仅可规定是“谁”或某个操作有权使用特定系统资源，而且也能规定被允许的访问类型。这些控制方式可在计算机系统或者外部设备
中实现。<br />   <br />    就基于角色访问控制而言，访问决策是基于角色的，个体用户是某个组织的一部分。用户具有指派的角色（比如医生、护士、出纳、经理）。定义角色的过程应该基于对组织运转的彻底分析，应该包括来自一个组织中更广范围用户的输入。<br />    <br />    访问权按角色名分组，资源的使用受限于授权给假定关联角色的个体。例如，在一个医院系统中，医生角色可能包括进行诊断、开据处方、指示实验室化验等；而研究员的角色则被限制在收集用于研究的匿名临床信息工作上。<br />    <br />    控制访问角色的运用可能是一种开发和加强企业特殊安全策略，进行安全管理过程流程化的有效手段。<br />      </p>
		<p>
				<br />
				<strong>
						<font size="3">用户（User）和角色（Role）</font>
				</strong>
		</p>
		<p>   
用户指访问系统中的资源的主体，一般为人，也可为 Agent
等智能程序。角色指应用领域内一种权力和责任的语义综合体，可以是一个抽象概念，也可以是对应于实际系统中的特定语义体，比如组织内部的职务等。针对角色
属性的不同，某些模型中将角色进一步细分为普通角色和管理员角色（可理解为全局角色）。</p>
		<p> </p>
		<p>
				<font size="3">
						<strong>许可（Permissions）和权限（Permission）</strong>
				</font>
		</p>
		<p>   
许可描述了角色对计算机资源的访问和操作所具有的权限，其反映的是授权的结果。比如授予某个角色对计算机资源有读的权限，则代表了一个许可的存在，这个许
可表示：角色获取了对计算机资源的读许可。针对操作来说，其描述的是许可和操作之间的一种关联关系，而这层关系则表示了某一角色对某一操作所具有的权限及
权限状态。</p>
		<p>
				<br />      <br /><strong><font size="3">角色和指派（Assignment）</font></strong></p>
		<p>    指派包含两个方面，用户指派和许可指派。用户指派表示的是，将用户指派给特定的角色。许可指派表示的是为角色指派计算机资源的访问和操作许可。</p>
		<p> </p>
		<p>
				<strong>
						<font size="3">会话（session）</font>
				</strong>
		</p>
		<p>    会话表示的是用户和角色之间的关系。用户每次必须通过建立会话来激活角色，得到相应的访问权限。</p>
		<p> </p>
		<p>
				<strong>
						<font size="3">角色和角色等级（Role Hierarchies）</font>
				</strong>
		</p>
		<p>   
角色本身仅仅只是一个名词，其本身并不能代表权限的大小。比如，我们可以定一个“Director”的角色，也可以定一个“Project
Leader”的角色。对于现实中我们来说，看到这样两个角色，就清楚 DIR 的权限要比一个 PL
的权限级别高。但是对计算机来说，这两个角色仅仅是两个“词语”，是等同的。可以采用分等级角色，在角色上实现层次化来解决这些问题。也可以采用复合角色
（其表示的就是一个角色组的概念），对角色实现一定的分组和复合，以便于权限指派。在一些 OA 产品中经常出现分等级角色。<br />    </p>
		<p>
				<br />
				<font size="3">
						<strong>限制（Constraints）</strong>
				</font>
				<br />    <br />   
模型中的职责分离关系（Separation of Duty），用于控制冲突（Conflict）。静态职责分离（Static
SD）指定角色的互斥关系，用于用户指派阶段。避免同一用户拥有互斥的角色。实现简单，角色互斥语义关系清楚，便于管理不够灵活，不能处理某些实际情况。
动态职责分离（Dynamic
SD）指定角色的互斥关系，用于角色激活阶段。允许同一用户拥有某些互斥的角色，但是不允许该用户同时激活互斥的角色。更灵活，直接与会话挂钩，适应实际
管理需要，实现复杂，不易管理。</p>
		<p>              <br /></p>
		<p> </p>
		<p>
				<font size="3">
						<strong>  </strong>
				</font>
		</p>
		<p>
				<font size="3">
						<strong>参考文献</strong>
				</font>
		</p>《AN INTRODUCTION TO ROLE-BASED ACCESS CONTROL》 NIST<p>《工作流授权控制模型》        胡长城</p><p>《基于角色的权限管理综述》 俞诗鹏</p><p> </p><p> </p><p>最后，感谢宏云博士对本文翻译提供的指导。    <br /><br /><br /><strong><font color="#ff0000" size="2">请注意！引用、转贴本文应注明原作者：Rosen Jiang 以及出处：</font></strong><a href="../../rosen"><strong><font color="#ff0000" size="2">http://www.blogjava.net/rosen</font></strong></a></p><img src ="http://www.blogjava.net/alex/aggbug/77481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-10-26 21:31 <a href="http://www.blogjava.net/alex/archive/2006/10/26/77481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Java 学习方法浅谈  </title><link>http://www.blogjava.net/alex/archive/2006/09/20/70747.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 20 Sep 2006 04:12:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/20/70747.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/70747.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/20/70747.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/70747.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/70747.html</trackback:ping><description><![CDATA[
		<p>转自 <a href="http://www.javaeye.com/topic/42">robin</a><br /></p>
		<p>Java本身是一种设计的非常简单，非常精巧的语言，所以Java背后的原理也很简单，归结起来就是两点： </p>
		<p>1、JVM的内存管理 </p>
		<p>理解了这一点，所有和对象相关的问题统统都能解决 </p>
		<p>2、JVM Class Loader </p>
		<p>理解了这一点，所有和Java相关的配置问题，包括各种App Server的配置，应用的发布问题统统都能解决 </p>
		<p>就像张无忌学太极剑，本质就是一圈一圈的画圆，你要是懂得了太极剑的本质，那么太极剑就那么一招而已，本身是很容易学的，只是难度在于你要能够举一
反三，化一式剑意为无穷无尽的剑招，这就需要一点悟性和不断的实践了；反过来说，如果学剑不学本质，光学剑招，你就是学会了1万招，碰到了第1万零1招，
还是不会招架，败下阵来。 </p>
		<p>技术世界本来就是丰富多彩，企图统一标准，实际上也做不到，但是世界本质其实并不复杂。学习技术，特别是某种具体的软件工具的时候，<b>应该学会迅速把
握事物的本质</b>，不要过多搅缠细节。软件工具应该为我所用，而不是我被工具所驾驭。当你具备了对整个J2EE架构的设计和实施的能力，你还会被具体的工具束
缚吗？哪种工具适合你的架构，你就用什么，哪种不适合你，你就抛弃它，软件皆臣服于你的脚下，而不是你被什么软件牵着鼻子走，到了这种程度，你难道还害怕
学习什么新的软件？ </p>
		<p>我自己也在一直朝着这个方向努力，在我心中，<font color="#ff1493">设计软件，架构是第一位的，采用什么技术要为架构服务</font>。如果我发现什么技术对我的架构来说很重要，那么
我会花时间去学习，去钻研，就像我花时间去钻研ORM一样，<font color="#0000ff">如果我觉得什么技术对我的架构来说没有用，即使技术再火爆，我也不去碰它</font>。 </p>
		<p>总之要学会抓住本质，驾驭技术，而不是被技术所驾驭。当你掌握了本质原理，其实学什么都很快，毕竟都是相通的，我先看JDO，后看
Hibernate，其实两者就很类似，所以学得很快，以后如果有工作需要，要我学习别的ORM，那我也不会觉得有什么困难的，一样手到拿来。 </p>
		<p>更有说服力的是Unix类的操作系统，那就更相似了，只要抓住了Unix最本质的几点，例如shell命令和编程，文件系统结构和配置，系统启动原
理和过程，所有的Unix都是无师自通的。我自己会用Linux，FreeBSD，SCO Unix， Solaris，HP-UX 和
AIX等6种Unix，更体会到一通百通的道理。 </p>
		<p>拿刚出了光明顶密道的张无忌来说吧，(我很喜欢张无忌这个角色)，他也没有练过什么武功，但是他已经把天下武学之本质：九阳神功 +
乾坤大挪移学会了，所以不管什么功夫，他都是看一遍就会，马上为我所用，看了空性用了一遍龙爪手，就会用龙爪手来破对方；和昆仑派打了一架，就会用昆仑剑
法和灭绝师太过招；七伤拳更是无师自通；太极拳也是看一遍就会。 </p>
		<p>总之，学习方法还是很重要，别被五花八门的技术给搞不清学习方向了。</p>
<img src ="http://www.blogjava.net/alex/aggbug/70747.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-20 12:12 <a href="http://www.blogjava.net/alex/archive/2006/09/20/70747.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Effective Java读书笔记</title><link>http://www.blogjava.net/alex/archive/2006/09/11/69002.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 11 Sep 2006 10:14:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/11/69002.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/69002.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/11/69002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/69002.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/69002.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 终于翻开这本James都称赞的java经典书籍了，发现比一般的英语书籍要难懂一些。但是里面的Item都是非常实用的，是java程序员应该理解的。 Creating and Destroying ObjectItem 1:考虑用静态工厂方法替代构造器例如：public static Boolean valueOf(boolean b)     {          return (b?Boolean...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/09/11/69002.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/69002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-11 18:14 <a href="http://www.blogjava.net/alex/archive/2006/09/11/69002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>web开发的瑞士军刀 javawebparts</title><link>http://www.blogjava.net/alex/archive/2006/09/08/68600.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Fri, 08 Sep 2006 13:18:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/08/68600.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68600.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/08/68600.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68600.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68600.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 引言:最近在看一个开源的聊天室AjaxChat 时看到一个被引用的包:javawebparts,处于好奇去看了一下，突然发现这么好的一个常用web组件不去用实在是太可惜了，下面逐一介绍，详细文档大家可以去官方文档看看，最好看它的Demo,很直观。		javawebparts的口号是:不用重新发明轮子 !														对这点我是严重支持啊，在我的身边看到N多所谓...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/09/08/68600.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/68600.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-08 21:18 <a href="http://www.blogjava.net/alex/archive/2006/09/08/68600.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用Digester解析xml到bean</title><link>http://www.blogjava.net/alex/archive/2006/09/06/68148.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Wed, 06 Sep 2006 15:32:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/06/68148.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/68148.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/06/68148.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/68148.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/68148.html</trackback:ping><description><![CDATA[key words: Digester  解析xml<br /><br />假设有下列xml文件:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;?</span><span style="color: rgb(255, 0, 255);">xml version='1.0' encoding='utf-8'</span><span style="color: rgb(0, 0, 255);">?&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">address-book</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">contact </span><span style="color: rgb(255, 0, 0);">myType</span><span style="color: rgb(0, 0, 255);">="individual"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Zane Pasolini</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">address</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">999 W. Prince St.</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">address</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">city</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">New York</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">city</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">province</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">NY</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">province</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">postalcode</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">10013</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">postalcode</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">country</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">USA</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">country</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">telephone</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">1-212-345-6789</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">telephone</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">contact</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">contact </span><span style="color: rgb(255, 0, 0);">myType</span><span style="color: rgb(0, 0, 255);">="business"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">SAMOFIX d.o.o.</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">address</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Ilica 47-2</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">address</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">city</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Zagreb</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">city</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">province</span><span style="color: rgb(0, 0, 255);">&gt;&lt;/</span><span style="color: rgb(128, 0, 0);">province</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">postalcode</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">10000</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">postalcode</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">country </span><span style="color: rgb(255, 0, 0);">from</span><span style="color: rgb(0, 0, 255);">="cn"</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">Croatia</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">country</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />        </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">telephone</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">385-1-123-4567</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">telephone</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">contact</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">address-book</span><span style="color: rgb(0, 0, 255);">&gt;</span></div><br />这是一份常用到的文件，现在我们需要将之映射到java bean,用Digester解析显得非常简单 <br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> AddressBookParser<br />{<br />    </span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br />     * Prints the contact information to standard output.<br />     *<br />     * </span><span style="color: rgb(128, 128, 128);">@param</span><span style="color: rgb(0, 128, 0);"> contact the &lt;code&gt;Contact&lt;/code&gt; to print out<br />     </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> addContact(Contact contact)<br />    {<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">TYPE: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getType());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">NAME: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getName());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    ADDRESS:    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getAddress());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    CITY:       </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getCity());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    PROVINCE:   </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getProvince());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    POSTALCODE: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getPostalcode());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    COUNTRY:    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getCountry());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    COUNTRY-From:    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getCountryFrom());<br />        System.out.println(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">    TELEPHONE:  </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> contact.getTelephone());<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br />     * Configures Digester rules and actions, parses the XML file specified<br />     * as the first argument.<br />     *<br />     * </span><span style="color: rgb(128, 128, 128);">@param</span><span style="color: rgb(0, 128, 0);"> args command line arguments<br />     </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> main(String[] args) </span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);"> IOException, SAXException<br />    {<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> instantiate Digester and disable XML validation</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        Digester digester </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Digester();<br />        digester.setValidating(</span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">);<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> instantiate AddressBookParser class</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        digester.addObjectCreate(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, AddressBookParser.</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> );<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> instantiate Contact class</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        digester.addObjectCreate(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, Contact.</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> );<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> set type property of Contact instance when 'type' attribute is found<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">对有属性的值通过setProperties方法</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />        digester.addSetProperties(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,         </span><b><font color="#ff0000"><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">myType</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">type</span><span style="color: rgb(0, 0, 0);">"</span></font></b><span style="color: rgb(0, 0, 0);"><font color="#ff0000"> </font>);<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> set different properties of Contact instance using specified methods<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">addCallMethod与addBeanPropertySetter等价<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 参数 0代表一个参数，默认就是当前读的数据</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);"><br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/name</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,       </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setName</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/address</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setAddress</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/address</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setAddress</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/city</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,       </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setCity</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/province</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,   </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setProvince</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/postalcode</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setPostalcode</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/country</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setCountry</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br /><br /><br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">增加country的属性 : from</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        digester.addSetProperties(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/country</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><u><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">from</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">countryFrom</span><span style="color: rgb(0, 0, 0);">"</span></u><span style="color: rgb(0, 0, 0);">);<br />        digester.addCallMethod(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact/telephone</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,  </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setTelephone</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">);<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> call 'addContact' method when the next 'address-book/contact' pattern is seen</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        digester.addSetNext(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">address-book/contact</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,               </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">addContact</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> );<br /><br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> now that rules and actions are configured, start the parsing process</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        AddressBookParser abp </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (AddressBookParser) digester.parse(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> File(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">c:\\addressbook.xml</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">));<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br />     * JavaBean class that holds properties of each Contact entry.<br />     * It is important that this class be public and static, in order for<br />     * Digester to be able to instantiate it.<br />     </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Contact<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String type;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String name;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String address;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String city;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String province;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String postalcode;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String country;<br /></span><span style="color: rgb(0, 128, 0);">        //</span><span style="color: rgb(0, 128, 0);">增加一个country的属性: from</span><br /><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String countryFrom;</span><span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> String telephone;<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setType(String newType)<br />        {<br />            type </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newType;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getType()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> type;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setName(String newName)<br />        {<br />            name </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newName;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getName()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> name;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setAddress(String newAddress)<br />        {<br />            address </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newAddress;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getAddress()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> address;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setCity(String newCity)<br />        {<br />            city </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newCity;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getCity()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> city;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setProvince(String newProvince)<br />        {<br />            province </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newProvince;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getProvince()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> province;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setPostalcode(String newPostalcode)<br />        {<br />            postalcode </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newPostalcode;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getPostalcode()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> postalcode;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setCountry(String newCountry)<br />        {<br />            country </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newCountry;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getCountry()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> country;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setTelephone(String newTelephone)<br />        {<br />            telephone </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> newTelephone;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getTelephone()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> telephone;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> String getCountryFrom() {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> countryFrom;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> setCountryFrom(String countryFrom) {<br />            </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.countryFrom </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> countryFrom;<br />        }<br />    }<br />}</span></div><br /><br />在 <a href="http://struts.sourceforge.net/ajaxchat/index.html">AjaxChat</a> 中的读取房间信息的方式显得更简洁<br />房间的xml配置文件如下:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">rooms</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="1"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="General Topics"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="2"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Programming"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="3"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Movies"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="4"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Music"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="5"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Television"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">rooms</span><span style="color: rgb(0, 0, 255);">&gt;</span></div><br />解析代码如下 :<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">synchronized</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> init(InputStream isConfigFile) {<br /><br />        log.debug(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">init()</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />        </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (isConfigFile </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">) {<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Read in rooms config and create beans, hand off to DAO.</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            Digester digester </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Digester();<br />            digester.setValidating(</span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">);<br />            digester.push(</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">);<br />            digester.addObjectCreate(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,<br />                    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">org.apache.struts.apps.ajaxchat.dto.RoomDTO</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />              //注意这里，如果xl的属性名称和bean的属性名称完全对应，则直接提供xml的位置即可<br />            digester.addSetProperties(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);</span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"><br />            digester.addSetNext(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">addRoom</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />            </span><span style="color: rgb(0, 0, 255);">try</span><span style="color: rgb(0, 0, 0);"> {<br />                digester.parse(isConfigFile);<br />                log.info(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">***** Rooms = </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> rooms);<br />            } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> (IOException ioe) {<br />                ioe.printStackTrace();<br />            } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> (SAXException se) {<br />                se.printStackTrace();<br />            }<br />        }<br /><br />    } </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> End init().</span></div><br />如果在xml文件中增加非attribute则更改后的配置文件如下:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">rooms</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="1"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="General Topics"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="2"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Programming"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="3"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Movies"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="4"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Music"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room </span><span style="color: rgb(255, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">="5"</span><span style="color: rgb(255, 0, 0);"> name</span><span style="color: rgb(0, 0, 255);">="Television"</span><span style="color: rgb(255, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">/&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">shit</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">room</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">room</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">7</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">id</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">haha</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">room</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">rooms</span><span style="color: rgb(0, 0, 255);">&gt;</span></div>对应的解析如下:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">synchronized</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> init(InputStream isConfigFile) {<br /><br />        log.debug(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">init()<img src="http://www.blogjava.net/images/dot.gif" /></span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />        </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (isConfigFile </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">) {<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> Read in rooms config and create beans, hand off to DAO.</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            Digester digester </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Digester();<br />            digester.setValidating(</span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">);<br />            digester.push(</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">);<br />            digester.addObjectCreate(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,<br />                    </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">org.apache.struts.apps.ajaxchat.dto.RoomDTO</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />            digester.addSetProperties(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />              //增加addCallMethod方法<br />            <b>digester.addCallMethod(</b></span><b><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room/id</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setId</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">0</span></b><span style="color: rgb(0, 0, 0);"><b>);</b><br />            <b>digester.addCallMethod(</b></span><b><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room/name</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">setName</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">0</span></b><span style="color: rgb(0, 0, 0);"><b>);</b><br />            digester.addSetNext(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">rooms/room</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">addRoom</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />            </span><span style="color: rgb(0, 0, 255);">try</span><span style="color: rgb(0, 0, 0);"> {<br />                digester.parse(isConfigFile);<br />                log.info(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">***** Rooms = </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> rooms);<br />            } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> (IOException ioe) {<br />                ioe.printStackTrace();<br />            } </span><span style="color: rgb(0, 0, 255);">catch</span><span style="color: rgb(0, 0, 0);"> (SAXException se) {<br />                se.printStackTrace();<br />            }<br />        }<br /><br />    } </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> End init().</span></div><br /><img src ="http://www.blogjava.net/alex/aggbug/68148.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-06 23:32 <a href="http://www.blogjava.net/alex/archive/2006/09/06/68148.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Struts国际化处理</title><link>http://www.blogjava.net/alex/archive/2006/09/05/67905.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Tue, 05 Sep 2006 14:22:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/05/67905.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/67905.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/05/67905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/67905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/67905.html</trackback:ping><description><![CDATA[key words:struts国际化 <br /><br /><p>一、Struts的国际化<br />    Struts是一种支持国际化的MVC的Web 
Framework。可是如何来使用struts国际化是一个问题。下面我们来探讨一下，如何实现Struts的国际化。Web程式的国际化涉及到3个层面的东西。第一、jsp部分的输入/输出；第二、应用处理程序的国际化；第三、DB的国际化问题。这里主要探讨的是jsp部分的输入/输出问题。</p><p>二、静态部分的国际化<br />   
Struts的jsp页面静态内容（包括静态文字，静态图片）国际化问题，是通过资源文件来实现的。要实现国际化，需要做如下几项工作：1、定义web.xml的动ActionServlet的参数；2、定义资源文件；3、定义JSP页面的字符集合；4、在JSP页面获取资源文件里面的内容。<br />1、定义web.xml的动ActionServlet的参数<br /></p><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">servlet</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">servlet-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">action</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">servlet-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">servlet-class</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">org.apache.struts.action.ActionServlet</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">servlet-class</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">   <br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">config</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">/WEB-INF/struts-config.xml</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">application</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-name</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">ApplicationResources</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">param-value</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 0);">&lt;!--</span><span style="color: rgb(0, 128, 0);"> 默认资源文件名 </span><span style="color: rgb(0, 128, 0);">--&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">init-param</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br />  </span><span style="color: rgb(0, 0, 255);">&lt;</span><span style="color: rgb(128, 0, 0);">load-on-startup</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">load-on-startup</span><span style="color: rgb(0, 0, 255);">&gt;</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">&lt;/</span><span style="color: rgb(128, 0, 0);">servlet</span><span style="color: rgb(0, 0, 255);">&gt;</span></div><br /><p>2、定义资源文件<br />在/WEB-INF/classes下面添加UTF-8资源束文件。每一个资源文件是“键－值”对的集合。在JSP页面里面可以通过键来找到相应的数据值。本例子的文件名是ApplicationResources，所以相应的资源文件束是(包括e文，简体中文，繁体中文)<br />ApplicationResources.properties 
: 
默认资源文件。当在其他资源文件里面找不到某个资源的时候，就使用该资源文件里面的定义。<br /><font color="#ff0000">ApplicationResources_zh_CN.properties：简体中文资源文件。<br />ApplicationResources_zh_TW.properties：繁体中文资源文件。</font><br />资源文件的格式为：默认资源文件名_国别_语言.properties。其中每个文件都是通过<font color="#660000">%JAVA_HONE%/BIN/native2ascii.exe</font>工具转换而来。你也可以使用其他工具来处理得到(<a href="http://java.sun.com/products/jilkit/">http://java.sun.com/products/jilkit/</a> 
有一个工具Internationalization Java Internationalization and Localization Toolkit 
可以处理)。下面是一个例子,我们显示如何使用%JAVA_HONE%/BIN/native2ascii.exe命令来定义资源束文件。<br />2.1 
准备文件<br />//ApplicationResources.properties 
；默认资源文件，通常里面的内容是英文的。<br />label.username=USERNAME :<br />label.password=PASSWORD 
:</p><p>//ApplicationResources_zh_CN.bak 
；简体中文的资源文件。里面的内容是中文的。它需要工具将其中的内容处理成UTF-8<br />label.username=用户名 
:<br />label.password=密  码 :</p><p>//ApplicationResources_zh_TW.bak : 
繁体中文的资源文件。里面的内容是中文的。它需要工具将其中的内容处理成UTF-8,下面的内容是繁体码。<br />label.username=ノめ?W 
:<br />label.password=ノめ?W :</p><p>2.2 准备完成以后，使用如下的命令创建UTF-8资源文件束<br /><font color="#ff0000">native2ascii -encoding gb2312 
ApplicationResources_zh_CN.bak 
ApplicationResources_zh_CN.properties</font><br />native2ascii -encoding big5 Applica 
tionResources_zh_TW.bak ApplicationResources_zh_TW.properties</p><p>3、定义JSP页面的字符集合<br />定义JSP页面的语言为UTF-8。在每个JSP页面，必须有如下的内容（如果使用的模板技术，则只是需要在模板页面添加，其他使用该模板的页面无需添加）<br />&lt;%@ 
page contentType="text/html;charset=UTF-8"%&gt;</p><p>4、在JSP页面获取资源文件里面的内容。<br />在JSP里面需要显示静态内容的地方使用&lt;bean:message /&gt;strus的bean 
tag包里面的message标签。例如下面的页面</p><p>&lt;table&gt;<br />  &lt;tr&gt;<br />    &lt;td align="right"&gt;&lt;bean:message 
key="label.username" /&gt;&lt;/td&gt;    <br />  &lt;/tr&gt;<br />  
&lt;tr&gt;<br />    &lt;td align="right"&gt;&lt;bean:message key="label.password" 
/&gt;&lt;/td&gt;<br />  &lt;/tr&gt;<br />&lt;/table&gt;</p><p>好了，在这个页面显示的时候，如果客户的IE的语言集合是zh_CN的话，就会显示<br />用户名：<br />口  令：</p><p>如果是客户的IE的语言是zh_TW的话，就会显示<br />用户名：<br />用户名：</p><p>可以在IE的工具-&gt;Internet选项-&gt;语言的地方，来选择，定义IE的语言。</p><p>三、表单的数据的处理。<br /><b>对于表单数据的处理，我们是通过添加一个Filter来实现的。所有提交的请求，都需要做字符处理。然后在web.xml里面定义该Filter。这样我们就不需要在程序里面做任何的字符处理。</b><br />3.1 
定义Filter。下面是一个例子。<br />package com.webapps.commons;</p><p>import java.io.*;<br />import javax.servlet.*;</p><p>public class CharsetEncodingFilter implements Filter{<br />  private 
FilterConfig config = null;<br />  private String defaultEncode = "UTF-8";</p><p>  public void init(FilterConfig config) throws ServletException {<br />    
this.config = config;<br />    
if(config.getInitParameter("Charset")!=null){<br />        
defaultEncode=config.getInitParameter("Charset");<br />    }<br />  }</p><p>  public void destroy() {<br />    this.config = null;<br />  }</p><p>  public void doFilter(ServletRequest request, ServletResponse 
response,<br />                       FilterChain chain) throws IOException, 
ServletException {<br />    ServletRequest srequest=request;<br />    
srequest.setCharacterEncoding(defaultEncode);<br />    
chain.doFilter(srequest,response);<br />  }<br />}</p><p>3.2 在web.xml里面声明使用该Filter<br />&lt;filter&gt;<br />  &lt;filter-name&gt;Character 
Encoding&lt;/filter-name&gt;<br />  
&lt;filter-class&gt;com.webapps.commons.CharsetEncodingFilter&lt;/filter-class&gt;<br />&lt;/filter&gt;<br />&lt;filter-mapping&gt;<br />  
&lt;filter-name&gt;Character Encoding&lt;/filter-name&gt;<br />  
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />&lt;/filter-mapping&gt;</p><p>四、扩展<br />待续的是应用程序部分的国际化问题，和DB的国际化问题。</p><br /><img src ="http://www.blogjava.net/alex/aggbug/67905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-05 22:22 <a href="http://www.blogjava.net/alex/archive/2006/09/05/67905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]使用 AppFuse 的七个理由</title><link>http://www.blogjava.net/alex/archive/2006/09/04/67669.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 04 Sep 2006 12:34:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/09/04/67669.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/67669.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/09/04/67669.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/67669.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/67669.html</trackback:ping><description><![CDATA[
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr valign="top">
								<td width="100%">
										<h1>使用 AppFuse 的七个理由</h1>
										<p id="subtitle">
												<em>学习 Java 开放源码工具 —— 并使用这些工具提高生产效率</em>
										</p>
										<img alt="" src="http://www.ibm.com/i/c.gif" class="display-img" height="6" width="1" />
								</td>
								<td class="no-print" width="192">
										<br />
								</td>
						</tr>
				</tbody>
		</table>
		<table border="0" cellpadding="0" cellspacing="0" width="100%">
				<tbody>
						<tr valign="top">
								<td width="10">
										<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
								</td>
								<td width="100%">
										<table class="no-print" align="right" border="0" cellpadding="0" cellspacing="0" width="160">
												<tbody>
														<tr>
																<td width="10">
																		<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
																</td>
														</tr>
												</tbody>
										</table>
										<p>级别: 初级</p>
										<p>
												<a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#author">Matt Raible</a> (<a href="mailto:mraible@virtuas.com?subject=%E4%BD%BF%E7%94%A8%20AppFuse%20%E7%9A%84%E4%B8%83%E4%B8%AA%E7%90%86%E7%94%B1&amp;cc=jaloi@us.ibm.com">mraible@virtuas.com</a>), 开放源码实践先驱, Virtuas Open Source Solutions<br /></p>
										<p>2006 年  8 月  31 日</p>
										<blockquote>开
始学习在 Java™ 平台上使用诸如 Spring、Hibernate 或 MySQL 之类的开放源码工具时可能非常困难。再加上 Ant 或
Maven，以及与 DWR 一起的小 Ajax，还有 Web 框架 —— 即 JSF，我们必须睁大眼睛盯着如何配置应用程序。AppFuse
减少了集成开放源码项目的痛苦。它可以把测试变成一等公民，让我们可以从数据库表生成整个 UI，并使用 XFire 来支持 Web
服务。另外，AppFuse 的社区也非常健全，这是不同 Web 框架用户可以一起融洽相处的地方之一。</blockquote>
										<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
										<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
										<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
										<p>AppFuse
是一个开放源码的项目和应用程序，它使用了在 Java 平台上构建的开放源码工具来帮助我们快速而高效地开发 Web
应用程序。我最初开发它是为了减少在为客户构建新 Web 应用程序时所花费的那些不必要的时间。从核心上来说，AppFuse
是一个项目骨架，类似于通过向导创建新 Web 项目时 IDE 所创建的东西。当我们使用 AppFuse
创建一个项目时，它会提示我们将使用开放源码框架，然后才创建项目。它使用 Ant
来驱动测试、代码生成、编译和部署。它提供了目录和包结构，以及开发基于 Java 语言的 Web 应用程序所需要的库。</p>
										<p>与大部分 “new project” 向导不同，AppFuse
创建的项目从最开始就包含很多类和文件。这些文件用来实现特性，不过它们同时也会在您开发应用程序时被用作示例。通过使用 AppFuse
启动新项目，我们通常可以减少一到两周的开发时间。我们不用担心如何将开放源码框架配置在一起，因为这都已经完成了。我们的项目都已提前配置来与数据库进
行交互，它会部署到应用服务器上，并对用户进行认证。我们不必实现安全特性，因为这都早已集成了。</p>
										<p>当我最初开发 AppFuse 时，它只支持 Struts 和 Hibernate。经过几年的努力，我发现了比 Struts 更好的
Web 框架，因此我还添加了为这些 Web 框架使用的选项。现在，AppFuse 可以支持 Hibernate 或 iBATIS
作为持久性框架。对于 Web 框架来说，我们可以使用 JavaServer Faces（JSF）、Spring
MVC、Struts、Tapestry 或 WebWork。</p>
										<p>AppFuse 提供了很多应用程序需要的一些特性，包括：</p>
										<ul>
												<li>认证和授权</li>
												<li>用户管理</li>
												<li>Remember Me（这会保存您的登录信息，这样就不用每次都再进行登录了）</li>
												<li>密码提醒</li>
												<li>登记和注册</li>
												<li>SSL 转换</li>
												<li>E-mail</li>
												<li>URL 重写</li>
												<li>皮肤</li>
												<li>页面修饰</li>
												<li>模板化布局</li>
												<li>文件上载</li>
										</ul>
										<p>这种 “开箱即用” 的功能是 AppFuse 与其他 <i>CRUD 代</i> 框架的区别之一（CRUD 取自<i>创建、检索、更新</i> 和<i>删除</i> 几个操作的英文首字母），包括 Ruby on Rails、Trails 和 Grails。上面提到的这些框架，以及 AppFuse，都让我们可以从数据库表或现有的模型对象中生成主页/细节页。</p>
										<p>图 1 阐述了一个典型 AppFuse 应用程序的概念设计：</p>
										<br />
										<a name="fig1">
												<b>图 1. 典型的 AppFuse 应用程序</b>
										</a>
										<br />
										<img alt="典型的 AppFuse 应用程序" src="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/appfuse_application.gif" height="547" width="572" />
										<br />
										<p>清单 1 给出了我们在创建 <i>devworks</i> 项目时所使用的命令行交互操作，同时还给出了所生成的结果。这个项目使用了 WebWork 作为自己的 Web 框架（请参考下面 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a> 一节给出的链接）。</p>
										<br />
										<a name="listing1">
												<b>清单 1. 使用 AppFuse 创建新项目</b>
										</a>
										<br />
										<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<code>
																		</code>
																		<pre class="section">alotta:~/dev/appfuse mraible$ ant new<br />Buildfile: build.xml<br /><br />clean:<br />     [echo] Cleaning build and distribution directories<br /><br />init:<br /><br />new:<br />     [echo] <br />     [echo] +-------------------------------------------------------------+<br />     [echo] |    -- Welcome to the AppFuse New Application Wizard! --     |<br />     [echo] |                                                             |<br />     [echo] | To create a new application, please answer the following    |<br />     [echo] | questions.                                                  |<br />     [echo] +-------------------------------------------------------------+<br /><br />    [input] What would you like to name your application [myapp]?<br />devworks<br />    [input] What would you like to name your database [mydb]?<br />devworks<br />    [input] What package name would you like to use [org.appfuse]?<br />com.ibm<br />    [input] What web framework would you like to use [webwork,tapestry,spring,js<br />f,struts]?<br />webwork<br />     [echo] Creating new application named 'devworks'...<br />     [copy] Copying 359 files to /Users/mraible/Work/devworks<br />     [copy] Copying 181 files to /Users/mraible/Work/devworks/extras<br />     [copy] Copying 1 file to /Users/mraible/Work/devworks<br />     [copy] Copying 1 file to /Users/mraible/Work/devworks<br /><br />install:<br />     [echo] Copying WebWork JARs to ../../lib<br />     [copy] Copying 6 files to /Users/mraible/Work/devworks/lib<br />     [echo] Adding WebWork entries to ../../lib.properties<br />     [echo] Adding WebWork classpath entries<br />     [echo] Removing Struts-specific JARs<br />   [delete] Deleting directory /Users/mraible/Work/devworks/lib/struts-1.2.9<br />   [delete] Deleting directory /Users/mraible/Work/devworks/lib/strutstest-2.1.3<br />     [echo] Deleting struts_form.xdt for XDoclet<br />   [delete] Deleting directory /Users/mraible/Work/devworks/metadata/templates<br />     [echo] Deleting Struts merge-files in metadata/web<br />   [delete] Deleting 7 files from /Users/mraible/Work/devworks/metadata/web<br />     [echo] Deleting unused Tag Libraries and Utilities<br />   [delete] Deleting 2 files from /Users/mraible/Work/devworks/src/web/org/appfu<br />se/webapp<br />     [echo] Modifying appgen for WebWork<br />     [copy] Copying 12 files to /Users/mraible/Work/devworks/extras/appgen<br />     [echo] Replacing source and test files<br />   [delete] Deleting directory /Users/mraible/Work/devworks/src/web/org/appfuse/<br />webapp/form<br />   [delete] Deleting directory /Users/mraible/Work/devworks/src/web/org/appfuse/<br />webapp/action<br />     [copy] Copying 13 files to /Users/mraible/Work/devworks/src<br />   [delete] Deleting directory /Users/mraible/Work/devworks/test/web/org/appfuse<br />/webapp/form<br />   [delete] Deleting directory /Users/mraible/Work/devworks/test/web/org/appfuse<br />/webapp/action<br />     [copy] Copying 5 files to /Users/mraible/Work/devworks/test<br />     [echo] Replacing web files (images, scripts, JSPs, etc.)<br />   [delete] Deleting 1 files from /Users/mraible/Work/devworks/web/scripts<br />     [copy] Copying 34 files to /Users/mraible/Work/devworks/web<br />   [delete] Deleting: /Users/mraible/Work/devworks/web/WEB-INF/validator-rules-c<br />ustom.xml<br />     [echo] Modifying Eclipse .classpath file<br />     [echo] Refactoring build.xml<br />     [echo] ----------------------------------------------<br />     [echo] NOTE: It's recommended you delete extras/webwork as you shouldn't ne<br />ed it anymore.<br />     [echo] ----------------------------------------------<br />     [echo] Repackaging info written to rename.log<br />     [echo] <br />     [echo] +-------------------------------------------------------------+<br />     [echo] |           -- Application created successfully! --           |<br />     [echo] |                                                             |<br />     [echo] | Now you should be able to cd to your application and run:   |<br />     [echo] | &gt; ant setup test-all                                        |<br />     [echo] +-------------------------------------------------------------+<br /><br />BUILD SUCCESSFUL<br />Total time: 15 seconds</pre>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
												<tbody>
														<tr>
																<td width="10">
																		<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
																</td>
																<td>
																		<table border="1" cellpadding="5" cellspacing="0" width="100%">
																				<tbody>
																						<tr>
																								<td bgcolor="#eeeeee">
																										<a name="sidebar1">
																												<b>为什么使用 WebWork？</b>
																										</a>
																										<br /> Struts 社区最近在热情地拥抱
WebWork，这种结合导致为 Java 平台提供了一个非常优秀的新 Web 框架：Struts 2。当然，Spring MVC
是一个非常优秀的基于请求的框架，但是它不能像 Struts 2 一样支持 JSF。基于内容的框架（例如 JSF 和
Tapestry）也都很好，但是我发现 WebWork 更为直观，更容易使用（更多有关 Structs 2 和 JSF 的内容请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>）。
</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<p>在创建一个新项目之后，我们就得到了一个类似于图 2 所示的目录结构。Eclipse 和 Intellij IDEA 项目文件都是作为这个过程的一部分创建的。</p>
										<br />
										<a name="fig2">
												<b>图 2. 项目的目录结构</b>
										</a>
										<br />
										<img alt="项目的目录结构" src="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/project_directory_structure.jpg" height="366" width="173" />
										<br />
										<p>这个目录结构与 Sun 为 Java 2 Platform Enterprise Edition（J2EE）Web
应用程序推荐的目录结构非常类似。在 2.0 版本的 AppFuse 中，这个结构会变化成适合 Apache Maven
项目的标准目录结构（有关这两个目录介绍的内容，请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>
中的链接）。AppFuse 还会从 Ant 迁移到 Maven 2 上，从而获得相关下载的能力和对生成 IDE 项目文件的支持。目前基于
Ant 的系统要求提交者维护项目文件，而 Maven 2 可以通过简单地使用项目的 pom.xml 文件生成 IDEA、Eclipse 和
NetBeans 项目文件。（这个文件位于您项目的根目录中，是使用 Maven 构建应用程序所需要的主要组件）。它与利用 Ant 所使用的
build.xml 文件非常类似。）</p>
										<p>现在我们对 AppFuse 是什么已经有一点概念了，在本文剩下的部分中，我们将介绍使用 AppFuse 的 7 点理由。即使您选择不使用
AppFuse 来开始自己的项目，也会看到 AppFuse 可以为您提供很多样板代码，这些代码可以在基于 Java 语言的 Web
应用程序中使用。由于它是基于 Apache 许可证的，因此非常欢迎您在自己的应用程序中重用这些代码。</p>
										<p>
												<a name="1">
														<span class="atitle">理由 1：测试</span>
												</a>
										</p>
										<p>测试是在软件开发项目中很少被给予足够信任的一个环节。注意我并不是说在软件开发的一些刊物中没有得到足够的信任！很多文章和案例研究都给出了测试
优先的开发方式和足够的测试覆盖面以提高软件的质量。然而，测试通常都被看作是一件只会延长项目开发时间的事情。实际上，如果我们使用测试优先的方法在编
写代码之前就开始撰写测试用例，我相信我们可以发现这实际上会<i>加速</i> 开发速度。另外，测试优先也可以使维护和重用<i>更加</i> 容易。如果我们不编写代码来测试自己的代码，那么就需要手工对应用程序进行测试 —— 这通常效率都不高。自动化才是关键。</p>
										<p>当我们首次开始使用 AppFuse 时，我们可能需要阅读这个项目 Web 站点上提供的快速入门指南和教程（请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>
中的链接）。这些教程的编写就是为了您可以首先编写测试用例；它们直到编写接口和/或实现之后才能编译。如果您有些方面与我一样，就会在开始编写代码之前
就已经编写好测试用例了；这是真正可以加速编写代码的惟一方式。如果您首先编写了代码的实现，通过某种方式验证它可以工作，那么您可能会对自己说，“哦，
看起来不错 —— 谁需要测试呢？我还有更多的代码需要编写！”这种情况不幸的一面是您通常都会做<i>一些事情</i> 来测试自己的代码；您简单地跳过了可以自动化进行测试的地方。</p>
										<p>AppFuse 的文档展示了如何测试应用程序的<i>所有</i> 层次。它从数据库层开始入手，使用了 DbUnit（请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>）在运行测试之前提前使用数据来填充自己的数据库。在数据访问（DAO）层，它使用了 Spring 的 <code>AbstractTransactionalDataSourceSpringContextTests</code> 类（是的，这的确是一个类的名字！）来允许简单地加载 Spring 上下文文件。另外，这个类对每个 <code>testXXX()</code> 方法封装了一个事务，并当测试方法存在时进行回滚。这种特性使得测试 DAO 逻辑变得非常简单，并且不会对数据库中的数据造成影响。</p>
										<p>在服务层，jMock （请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>）用来编写那些可以消除 DAO 依赖的<i>真正</i> 单元测试。这允许进行验证业务逻辑正确的快速测试；我们不用担心底层的持久性逻辑。</p>
										<table align="right" border="0" cellpadding="0" cellspacing="0" width="40%">
												<tbody>
														<tr>
																<td width="10">
																		<img alt="" src="http://www.ibm.com/i/c.gif" height="1" width="10" />
																</td>
																<td>
																		<table border="1" cellpadding="5" cellspacing="0" width="100%">
																				<tbody>
																						<tr>
																								<td bgcolor="#eeeeee">
																										<a name="sidebar2">
																												<b>HtmlUnit 支持</b>
																										</a>
																										<br /> 
HtmlUnit 团队在 1.8 发行版中已经完成了相当多的工作来确保包可以与流行的 Ajax 框架（Prototype 和 Scriptaculous）很好地工作。
</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<p>在 Web 层，测试会验证操作（Struts/WebWork）、控件（Spring MVC）、页面（Tapestry）和管理
bean（JSF）如我们所期望的一样进行工作。Spring 的 spring-mock.jar
可以非常有用地用来测试所有这些框架，因为它包含了一个 Servlet API 的仿真实现。如果没有这个有用的库，那么测试 AppFuse 的
Web 框架就会变得非常困难。</p>
										<p>UI 通常是开发 Web 应用程序过程中最为困难的一部分。它也是顾客最经常抱怨的地方 ——
这既是由于它并不是非常完美，也是由于它的工作方式与我们期望的并不一样。另外，没有什么会比在客户面前作演示的过程中看到看到异常堆栈更糟糕的了！您的
应用程序可能会非常可怕，但是客户可能会要求您做到十分完美。永远不要让这种事情发生。Canoo WebTest 可以对 UI 进行测试。它使用了
HtmlUnit 来遍历测试 UI，验证所有的元素都存在，并可以填充表单的域，甚至可以验证一个假想的启用 Ajax 的 UI
与我们预期的工作方式一样。（有关 WebTest 和 HTMLUnit 的链接请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>。）</p>
										<p>为了进一步简化 Web 的测试，Cargo（请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>）对 Tomcat 的启动和停止（分别在运行 WebTest 测试之前和之后）进行了自动化。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="2">
														<span class="atitle">理由 2：集成</span>
												</a>
										</p>
										<p>正如我在本文简介中提到的一样，很多开放源码库都已经预先集成到 AppFuse 中了。它们可以分为以下几类：
</p>
										<ul>
												<li>
														<b>编译、报告和代码生成：</b>Ant、Ant Contrib Tasks、Checkstyle、EMMA、Java2Html、PMD 和 Rename Packages</li>
												<li>
														<b>测试框架：</b>DbUnit、Dumbster、jMock、JUnit 和 Canoo WebTest</li>
												<li>
														<b>数据库驱动程序：</b>MySQL 和 PostgreSQL</li>
												<li>
														<b>持久性框架：</b>Hibernate 和 iBATIS</li>
												<li>
														<b>IoC 框架：</b>Spring</li>
												<li>
														<b>Web 框架：</b>JSF、Spring MVC、Struts、Tapestry 和 WebWork</li>
												<li>
														<b>Web 服务：</b>XFire</li>
												<li>
														<b>Web 工具：</b>Clickstream、Display Tag、DWR、JSTL、SiteMesh、Struts Menu 和 URL Rewrite Filter</li>
												<li>
														<b>Security：</b>Acegi Security</li>
												<li>
														<b>JavaScript 和 CSS：</b>Scriptaculous、Prototype 和 Mike Stenhouse 的 CSS Framework</li>
										</ul>
										<p>除了这些库之外，AppFuse 还使用 Log4j 来记录日志，使用 Velocity 来构建 e-mail 和菜单模板。Tomcat
可以支持最新的开发，我们可以使用 1.4 或 5 版本的 Java 平台来编译或构建程序。我们应该可以将 AppFuse 部署到任何 J2EE
1.3 兼容的应用服务器上；这已经经过了测试，我们知道它在所有主要版本的 J2EE 服务器和所有主要的 servlet 容器上都可以很好地工作。</p>
										<p>图 3 给出了上面创建的 <i>devworks</i> 项目的 lib 目录。这个目录中的 lib.properties 文件控制了每个依赖性的版本号，这意味着我们可以简单地通过把这些包的新版本放到这个目录中并执行诸如 <code>ant test-all -Dspring.version=2.0</code> 之类的命令来测试这些包的新版本。</p>
										<br />
										<a name="fig3">
												<b>图 3. 项目依赖性</b>
										</a>
										<br />
										<img alt="AppFuse 项目依赖性" src="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/project_lib_directory.jpg" height="598" width="197" />
										<br />
										<p>预先集成这些开放源码库可以在项目之初极大地提高生产效率。尽管我们可以找到很多文档介绍如何集成这些库，但是定制工作示例并简单地使用它来开发应用程序要更加简单。</p>
										<p>除了可以简化 Web 应用程序的开发之外，AppFuse 让我们还可以将 Web 服务简单地集成到自己的项目中。尽管 XFire 也在 AppFuse 下载中一起提供了，不过如果我们希望，也可以自己集成 Apache Axis（请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a> 中有关 Axis 集成的教程）。另外，Spring 框架和 XFire 可以一起将服务层作为 Web 服务非常简单地呈现出来，这就为我们提供了开发面向服务架构的能力。</p>
										<p>另外，AppFuse 并不会将我们限定到任何特定的 API
上。它只是简单地对可用的最佳开放源码解决方案重新进行打包和预先集成。AppFuse 中的代码可以处理这种集成，并实现了 AppFuse
的基本安全性和可用性特性。只要可能，就会减少代码，以便向 AppFuse 的依赖框架添加一个特性。例如，AppFuse 自带的
Remember Me 和 SSL 切换特性最近就因为类似的特性而从 Acegi Security 中删除了。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="3">
														<span class="atitle">理由 3：自动化</span>
												</a>
										</p>
										<p>Ant 使得简化了从编译到构建再到部署的自动化过程。Ant 是 AppFuse 中的一等公民，这主要是因为我发现在命令行中执行操作比从 IDE 中更加简单。我们可以使用 Ant 实现编译、测试、部署和执行任何代码生成的任务。</p>
										<p>尽管这种能力对于有些人来说非常重要，但是它并不适用于所有的人。很多 AppFuse 用户目前都使用 Eclipse 或 Intellij
IDEA 来构建和测试自己的项目。在这些 IDE 中运行 Ant 的确可以工作，但是这样做的效率通常都不如使用 IDE 内置的 JUnit
支持来运行测试效率高。</p>
										<p>幸运的是，AppFuse 支持在 IDE 中运行测试，不过管理这种特性对于 AppFuse 开发人员来说就变得非常困难了。最大的痛苦在于
XDoclet 用来生成 Hibernate 映射文件和 Web 框架所使用的一些工件（例如 ActionForms 和 Struts 使用的
struts-config.xml）。IDE 并不知道需要生成的代码，除非我们配置使用 Ant 来编译它们，或者安装了一些可以认识
XDoclet 的插件。</p>
										<p>这种对知识的缺乏是 AppFuse 2.0 切换到 JDK 5 和 Maven 2 上的主要原因。JDK 5、注释和 Struts 2
将让我们可以摆脱 XDoclet。Maven 2 将使用这些生成的文件和动态类路径来生成 IDE
项目文件，这样对项目的管理就可以进行简化。目前基于 Ant 的编译系统已经为不同的层次生成了一些工件（包括
dao.jar、service.jar 和 webapp.war），因此切换到 Maven 的模型上应该是一个非常自然的调整。</p>
										<p>除了 Ant 之外（它对于编译、测试、部署和报告具有丰富的支持），对于 CruiseControl 的支持也构建到了 AppFuse
中。CruiseControl 是一个 Continuous Integration
应用程序，让我们可以在源代码仓库中代码发生变化时自动运行所有的测试。extras/cruisecontrol 目录包含了我们为基于
AppFuse 的项目快速、简单地设置 Continuous Integration 时所需要的文件。</p>
										<p>设置 Continuous Integration 是软件开发周期中我们首先要做的事情之一。它不但激发程序员去编写测试用例，而且还通过 “You broke the build!” 游戏促进了团队之间的合作和融合。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="4">
														<span class="atitle">理由 4：安全特性和可扩展性</span>
												</a>
										</p>
										<p>AppFuse 最初是作为我为 Apress 编写的书籍 <i>Pro JSP</i>
中示例应用程序的一部分开发的。这个示例应用程序展示了很多安全特性和用于简化 Struts 开发的特性。这个应用程序中的很多安全特性在 J2EE
的安全框图中都不存在。使用容器管理认证（CMA）的认证方法非常简单，但是 Remember Me、密码提示、SSL
切换、登记和用户管理等功能却都不存在。另外，基于角色的保护方法功能在非 EJB 环境中也是不可能的。</p>
										<p>最初，AppFuse 使用自己的代码和用于 CMA 的解决方案完全实现了这些特性。我在 2004 年年初开始学习 Spring
时就听说过有关 Acegi Security 的知识。我对 Acegi 所需要的 XML 的行数（175）与 web.xml 中所需要的
CMA 的行数（20）进行了比较，很快就决定丢弃 Acegi 了，因为它太过复杂了。</p>
										<p>一年半之后 —— 在为另外一本书 <i>Spring Live</i> 中编写了一章有关使用 Acegi Security 的内容之后 —— 我就改变了自己的想法。Acegi <i>的确</i>（目
前仍然）需要很多 XML，但是一旦我们理解了这一点，它实际上是相当简单的。当我们最终作出改变，使用 Acegi Security
的特性来全部取代 AppFuse 的特性之后，我们最终删除了大量的代码。类之上的类都已经没有了，“Acegi handles that
now” 中消失的部分现在全部进入了 CVS 的 Attic 中了。</p>
										<p>Acegi Security 是 J2EE 安全模型中曾经出现过的最好模型。它让我们可以实现很多有用的特性，这些特性在 Servlet
API 的安全模型中都不存在：认证、授权、角色保护方法、Remember Me、密码加密、SSL
切换、用户切换和注销。它让我们还可以将用户证书存储到 XML 文件、数据库、LDAP 或单点登录系统（例如 Yale 的 Central
Authentication Service (CAS) 或者 SiteMinder）中。</p>
										<p>AppFuse 对很多与安全性相关的特性的实现从一开始都是非常优秀的。现在 AppFuse 使用了 Acegi
Security，这些特性 —— 以及更多特性 —— 都非常容易实现。Acegi 有很多地方都可以进行扩充：这是它使用巨大的 XML
配置文件的原因。正如我们已经通过去年的课程对 Acegi 进行集成一样，我们已经发现对很多 bean 的定义进行定制可以更加紧密地与
AppFuse 建立联系。</p>
										<p>Spring IoC 容器和 Acegi Security 所提供的简单开发、容易测试的代码和松耦合特性的组合是 AppFuse
是这么好的一种开发平台的主要原因。这些框架都是不可插入的，允许生成干净的可测试代码。AppFuse
集成了很多开放源码项目，依赖注入允许对应用程序层进行简单的集成。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="5">
														<span class="atitle">理由 5：使用 AppGen 生成代码</span>
												</a>
										</p>
										<p>有些人会将代码生成称为<i>代码气味的散播（code smell）</i>。在他们的观点中，如果我们需要生成代码，那么很可能就会做一些错事。我倾向于这种确定自己代码使用的模式和自动化生成代码的能力应该称为<i>代码香味的弥漫（code perfume）</i>。如果我们正在编写类似的 DAO、管理器、操作或控件，并且不想为它们生成代码，那么这就需要根据代码的气味来生成代码。当然，当语言可以为我们提供可以简化任务的特性时，一切都是那么美好；不过代码生成通常都是一个必需 —— 通常其生产率也非常高 —— 的任务。</p>
										<p>AppFuse 中提供了一个基于 Ant 和 XDoclet 的代码生成工具，名叫 <i>AppGen</i>。默认情况下，常见的 DAO 和管理器都可以允许我们对任何普通老式 Java 对象（POJO）进行 CRUD 操作，但是在 Web 层上这样做有些困难。AppGen 有几个特性可以用来执行以下任务：</p>
										<ul>
												<li>（使用 Middlegen 和 Hibernate 工具）从数据库表中生成 POJO</li>
												<li>从 POJO 生成 UI</li>
												<li>为 DAO、管理器、操作/控制器和 UI 生成测试</li>
										</ul>
										<p>在运行 AppGen 时，您会看到提示说 AppGen 要从数据库表或 POJO 中生成代码。如果在命令行中执行 <code>ant install-detailed</code>，AppGen 就会安装 POJO 特定的 DAO、管理器以及它们的测试。运行 <code>ant install</code> 会导致 Web 层的类重用通用的 DAO 和默认存在的管理器。</p>
										<p>为了阐述 AppGen 是如何工作的，我们在 <i>devworks</i> MySQL 数据库中创建了如清单 2 所示的表：</p>
										<br />
										<a name="listing2">
												<b>清单 2. 创建一个名为 cat 的数据库表</b>
										</a>
										<br />
										<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<code>
																		</code>
																		<pre class="section">    create table cat (<br />      cat_id int(8) auto_increment,<br />      color varchar(20) not null,<br />      name varchar(20) not null,<br />      created_date datetime not null,<br />      primary key (cat_id)<br />    ) type=InnoDB;<br /></pre>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<p>在 extras/appgen 目录中，运行 <code>ant install-detailed</code>。这个命令的输出结果对于本文来说实在太长了，不过我们在清单 3 中给出了第一部分的内容：</p>
										<br />
										<a name="listing3">
												<b>清单 3. 运行 AppGen 的 install-detailed 目标</b>
										</a>
										<br />
										<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<code>
																		</code>
																		<pre class="section">$ ant install-detailed<br />Buildfile: build.xml<br /><br />init:<br />    [mkdir] Created dir: /Users/mraible/Work/devworks/extras/appgen/build<br />     [echo] <br />     [echo] +-------------------------------------------------------+<br />     [echo] |             -- Welcome to the AppGen! --              |<br />     [echo] |                                                       |<br />     [echo] | Use the "install" target to use the generic DAO and   |<br />     [echo] | Manager, or use "install-detailed" to general a DAO   |<br />     [echo] | and Manager specifically for your model object.       |<br />     [echo] +-------------------------------------------------------+<br /><br />    [input] Would you like to generate code from a table or POJO? (table,pojo)<br />table<br />    [input] What is the name of your table (i.e. person)?<br />cat<br />    [input] What is the name, if any, of the module for your table (i.e. organization)?<br /><br />     [echo] Running Middlegen to generate POJO...<br /></pre>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<p>要对 cat 表使用这个新生成的代码，我们需要修改
src/dao/com/ibm/dao/hibernate/applicationContext-hibernate.xml，来为
Hibernate 添加 Cat.hbm.xml 映射文件。清单 3 给出了我们修改后的 <code>sessionFactory</code> bean 的样子：</p>
										<br />
										<a name="listing4">
												<b>清单 4. 将 Cat.hbm.xml 添加到 sessionFactory bean 中</b>
										</a>
										<br />
										<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<code>
																		</code>
																		<pre class="section">    &lt;bean id="sessionFactory" class="..."&gt;<br />    &lt;property name="dataSource" ref="dataSource"/&gt;<br />    &lt;property name="mappingResources"&gt;<br />        &lt;list&gt;<br />            &lt;value&gt;com/ibm/model/Role.hbm.xml&lt;/value&gt;<br />            &lt;value&gt;com/ibm/model/User.hbm.xml&lt;/value&gt;<br />            &lt;value&gt;com/ibm/model/Cat.hbm.xml&lt;/value&gt;<br />        &lt;/list&gt;<br />    &lt;/property&gt;<br />    ...<br />&lt;/bean&gt;<br /></pre>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<p>在运行 <code>ant setup deploy</code> 之后，我们就应该可以在部署的应用程序中对 cat 表执行 CRUD 操作了：</p>
										<br />
										<a name="fig4">
												<b>图 4. Cat 列表</b>
										</a>
										<br />
										<img alt="所生成的主屏幕" src="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/cat_list.jpg" height="379" width="572" />
										<br />
										<br />
										<a name="fig5">
												<b>图 5. Cat 表单</b>
										</a>
										<br />
										<img alt="所生成的详细屏幕" src="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/cat_detail.jpg" height="379" width="572" />
										<br />
										<p>我们在上面的屏幕快照中看到的记录都是作为代码生成的一部分创建的，因此现在就有测试数据了。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<table border="0" cellpadding="0" cellspacing="0">
																				<tbody>
																						<tr>
																								<td valign="middle">
																										<br />
																								</td>
																								<td align="right" valign="top">
																										<br />
																								</td>
																						</tr>
																				</tbody>
																		</table>
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="6">
														<span class="atitle">理由 6：文档</span>
												</a>
										</p>
										<p>我们可以找到 AppFuse 各个风味的教程，并且它们都以 6 种不同的语言给出了：中文、德语、英语、韩语、葡萄牙语和西班牙语。使用<i>风味（flavor）</i>
一词，我的意思是不同框架的组合，例如 Spring MVC 加上 iBATIS、Spring MVC 加上 Hibernate 或 JSF
加上 Hibernate。使用这 5 种 Web 框架和两种持久框架，可以有好几种组合。有关它们的翻译，AppFuse 为自己的默认特性提供了
8 种翻译。可用语言包括中文、荷兰语、德语、英语、法语、意大利语、葡萄牙语和西班牙语。</p>
										<p>除了核心教程之外，还添加了很多教程（请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>） 来介绍与各种数据库、应用服务器和其他开放源码技术（包括 JasperReports、Lucene、Eclipse、Drools、Axis 和 DWR）的集成。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="7">
														<span class="atitle">理由 7：社区</span>
												</a>
										</p>
										<p>Apache 软件基金会对于开放源码有一个有趣的看法。它对围绕开放源码项目开发一个开放源码社区最感兴趣。它的成员相信如果社区非常强大，那么产生高质量的代码就是一个自然的过程。下面的内容引自 Apache 主页：</p>
										<blockquote>
“我们认为自己不仅仅是一组共享服务器的项目，而且是一个开发人员和用户的社区。”
</blockquote>
										<p>AppFuse 社区从 2003 年作为 SourceForge 上的一个项目（是 struts.sf.net
的一部分）启动以来，已经获得了极大的增长。通过在 2004 年 3 月转换到 java.net 上之后，它已经成为这里一个非常流行的项目，从
2005 年 1 月到 3 月成为访问量最多的一个项目。目前它仍然是一个非常流行的项目（有关 java.net 项目统计信息的链接，请参看 <a href="http://www-128.ibm.com/developerworks/cn/java/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn#resources">参考资料</a>），不过在这个站点上它正在让位于 Sun 赞助的很多项目。</p>
										<p>在 2004 年年末，Nathan Anderson 成为继我之后第一个提交者。此后有很多人都加入了进来，包括 Ben
Gill、David Carter、Mika G?ckel、Sanjiv Jivan 和 Thomas
Gaudin。很多现有的提交者都已经通过各种方式作出了自己的贡献，他们都帮助 AppFuse 社区成为一个迅速变化并且非常有趣的地方。</p>
										<p>邮件列表非常友好，我们试图维护这样一条承诺 “没有问题是没有人理会的问题”。我们的邮件列表归档文件中惟一一条 “RTFM”
是从用户那里发出的，而不是从开发者那里发出的。我们绝对信奉 Apache 开放源码社区的哲学。引用我最好的朋友 Bruce Snyder
的一句话，“我们为代码而来，为人们而留下”。目前，大部分开发者都是用户，我们通常都喜欢有一段美妙的时间。另外，大部分文档都是由社区编写的；因此，
这个社区的知识是非常渊博的。</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="8">
														<span class="atitle">结束语</span>
												</a>
										</p>
										<p>我们应该尝试使用 AppFuse 进行开发，这是因为它允许我们简单地进行测试、集成、自动化，并可以安全地生成 Web 应用程序。其文档非常丰富，社区也非常友好。随着其支撑框架越来越好，AppFuse 也将不断改进。</p>
										<p>从 AppFuse 2.0 开始，我们计划迁移到 JDK 5（仍然支持部署到 1.4）和 Maven 2 上去。这些工具可以简化使用
AppFuse 的开发、安装和升级。我们计划充分利用 Maven 2 的功能来处理相关依赖性。我们将碰到诸如
appfuse-hibernate-2.0.jar 和 appfuse-jsf-2.0.jar 之类的工件。这些工件都可以在 pom.xml
文件中进行引用，它们负责提取其他相关依赖性。除了在自己的项目中使用 AppFuse 基类之外，我们还可以像普通的框架一样在 JAR
中对这些类简单地进行扩展，这应该会大大简化它的升级过程，并鼓励更多用户将自己希望的改进提交到这个项目中。</p>
										<p>如果没有其他问题，使用 AppFuse 可以让您始终处于 Java Web 开发的技术前沿上 —— 就像我们一样！</p>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="resources">
														<span class="atitle">参考资料 </span>
												</a>
										</p>
										<b>学习</b>
										<br />
										<ul>
												<li>您可以参阅本文在 developerWorks 全球站点上的 <a href="http://www.ibm.com/developerworks/java/library/j-appfuse/index.html?S_TACT=105AGX52&amp;S_CMP=cn-a-j" target="_blank">英文原文</a> 。<br /><br /></li>
												<li>
														<a href="http://appfuse.org/">AppFuse</a>：该项目的主页。
<br /><br /></li>
												<li>
														<a href="http://appfuse.org/demos.html">AppFuse Demos</a>：查看演示和视频。
<br /><br /></li>
												<li>
														<a href="http://jroller.com/page/mrdon?entry=unification_struts_action_and_jsf">Struts 2 和 JSF</a>：了解为什么要将这些技术放到一起工作。
<br /><br /></li>
												<li>
														<a href="http://java.sun.com/blueprints/code/projectconventions.html">Sun 的 J2EE 项目目录结构指南</a>：AppFuse 非常接近于这些指南。
<br /><br /></li>
												<li>
														<a href="http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html">Maven 的 Standard Directory Layout</a>：AppFuse 2.0 将转换到这个目录结构上。
<br /><br /></li>
												<li>
														<a href="http://appfuse.org/wiki/QuickStart.html">AppFuse 快速入门指南</a>：快速入门并使用 AppFuse。
<br /><br /></li>
												<li>
														<a href="http://appfuse.org/wiki/Articles.html">AppFuse 教程</a>：深入学习更多有关使用 AppFuse 的知识。
<br /><br /></li>
												<li>
														<a href="http://raibledesigns.com/wiki/AppFuseAxis.html">Apache Axis 集成</a>：如何将 Apache Axis 集成到自己的 AppFuse 项目中。
<br /><br /></li>
												<li>Java.net 项目状态：请查看 2005 年 <a href="http://community.java.net/projects/toparchive.csp?year=2005&amp;month=January">1 月</a>、<a href="http://community.java.net/projects/toparchive.csp?year=2005&amp;month=February">2 月</a> 和 <a href="http://community.java.net/projects/toparchive.csp?year=2005&amp;month=March">3 月</a> 的动态。还可以查看 <a href="http://community.java.net/projects/top.csp">java.net 上的最佳项目 </a>。
<br /><br /></li>
										</ul>
										<br />
										<b>获得产品和技术</b>
										<br />
										<ul>
												<li>
														<a href="https://appfuse.dev.java.net/servlets/ProjectDocumentList">AppFuse on java.net</a>：下载不同风味的 AppFuse。
<br /><br /></li>
												<li>
														<a href="http://opensymphony.com/webwork">WebWork</a>：了解这个易于使用的 Web 框架。
<br /><br /></li>
												<li>
														<a href="http://www.dbunit.org/">DbUnit</a>：查看更多有关 JUnit 扩展的内容。
<br /><br /></li>
												<li>
														<a href="http://www.jmock.org/">jMock</a>：创建动态仿真对象来简化真正的单元测试。
<br /><br /></li>
												<li>
														<a href="http://webtest.canoo.com/">Canoo WebTest</a>：自动化 Web 应用程序的 UI 测试。
<br /><br /></li>
												<li>
														<a href="http://htmlunit.sf.net/">HtmlUnit</a>：WebTest 的优秀 JavaScript 支持背后的基础。
<br /><br /></li>
												<li>
														<a href="http://cargo.codehaus.org/">Cargo</a>：自动启动和停止容器。
<br /><br /></li>
												<li>
														<a href="http://greenbox.dev.java.net/">Greenbox</a>：一种代码生成框架。
<br /><br /></li>
										</ul>
										<br />
										<b>讨论</b>
										<br />
										<ul>
												<li>
														<a href="http://www.nabble.com/AppFuse-f2369.html">AppFuse 论坛</a>：与同行开发人员交流技巧。</li>
										</ul>
										<br />
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td>
																		<img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%" />
																		<br />
																		<img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8" />
																</td>
														</tr>
												</tbody>
										</table>
										<table class="no-print" align="right" cellpadding="0" cellspacing="0">
												<tbody>
														<tr align="right">
																<td>
																		<img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%" />
																		<br />
																		<br />
																</td>
														</tr>
												</tbody>
										</table>
										<br />
										<br />
										<p>
												<a name="author">
														<span class="atitle">关于作者</span>
												</a>
										</p>
										<table border="0" cellpadding="0" cellspacing="0" width="100%">
												<tbody>
														<tr>
																<td colspan="3">
																		<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%" />
																</td>
														</tr>
														<tr align="left" valign="top">
																<td>
																		<p>
																				<img alt="" src="http://www.ibm.com/developerworks/i/p-mraible.jpg" align="left" height="80" width="64" />
																		</p>
																</td>
																<td>
																		<img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4" />
																</td>
																<td width="100%">
																		<p>Matt Raible 居住在美国科罗拉多州的丹佛，他在那里是 Spring 和 Web 框架对 <a href="http://virtuas.com/">Virtuas Open Source Solutions</a> 的实践先驱。他在开放源码领域具有丰富的经验，是这个领域的专家。他在这个领域中既是用户，又是一名开发人员。Matt 是 <a href="http://sourcebeat.com/">SourceBeat Publishing</a> 上 <i><a href="http://springlive.com/">Spring Live</a></i> 的作者。他还为 Apress 的书籍 <i><a href="http://www.apress.com/book/bookDisplay.html?bID=256">Pro JSP Third Edition</a></i> 作出了很大的贡献。他是很多开放源码会议的积极倡导者，包括 ApacheCon、MySQL User's Conference 和 OSCON，同时他还是 <a href="http://raibledesigns.com/">http://raibledesigns.com</a> 上一名非常活跃的博客。Raible 的大部分生活都被计算机所包围了，尽管他是在连电都没有的 Montana 长大的。当不工作的时候时，他总是试图让妻子 Julie 成为世界上最幸福的女人，或者与他们的孩子 Abbie 和 Jack 一起玩耍。</p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/alex/aggbug/67669.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-09-04 20:34 <a href="http://www.blogjava.net/alex/archive/2006/09/04/67669.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(7)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66836.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:29:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66836.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66836.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66836.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66836.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="_Toc53800166">
						<span lang="EN-IE">7  Jive</span>
				</a>
				<span style="font-family: 楷体_GB2312;">安装调试运行</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">默认编码方式是</span>
				<span lang="EN-IE">ISO8859_1</span>
				<span style="font-family: 宋体;">。下面以安装在英文</span>
				<span lang="EN-IE">Linux</span>
				<span style="font-family: 宋体;">操作系统上为例：</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">（</span>
				<span lang="EN-IE">1</span>
				<span style="font-family: 宋体;">）安装数据库。在</span>
				<span lang="EN-IE">database</span>
				<span style="font-family: 宋体;">目录中选择对应数据库，如果数据库是</span>
				<span lang="EN-IE">MySQL</span>
				<span style="font-family: 宋体;">，则使用</span>
				<span lang="EN-IE">jive_mysql.sql</span>
				<span style="font-family: 宋体;">，然后通过数据库的管理工具将</span>
				<span lang="EN-IE">jive_mysql.sql</span>
				<span style="font-family: 宋体;">导入相应数据库中。</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">所需要的数据库都已经准备完成。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">（</span>
				<span lang="EN-IE">2</span>
				<span style="font-family: 宋体;">）由于</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">Servlet/JSP</span>
				<span style="font-family: 宋体;">系统，必须在</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">容器支持下才能运行。因此，必须安装</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">服务器软件，例如</span>
				<span lang="EN-IE">Tomcat</span>
				<span style="font-family: 宋体;">等。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">最后需要将</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">部署到</span>
				<span lang="EN-IE">Tomcat</span>
				<span style="font-family: 宋体;">中。有两种办法，其中直接复制的办法比较简单，修改</span>
				<span lang="EN-IE">server.xml</span>
				<span style="font-family: 宋体;">办法可以见其他章节介绍。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">将</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">application</span>
				<span style="font-family: 宋体;">目录下所有文件复制到</span>
				<span lang="EN-IE">Tomcat</span>
				<span style="font-family: 宋体;">应用目录</span>
				<span lang="EN-IE">webapps</span>
				<span style="font-family: 宋体;">的指定目录下，如</span>
				<span lang="EN-IE">Tomcat/webapps/jive</span>
				<span style="font-family: 宋体;">下。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">（</span>
				<span lang="EN-IE">3</span>
				<span style="font-family: 宋体;">）在运行设置</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">之前，还需要设定</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的初始值，在上述应用目录的</span>
				<span lang="EN-IE">WEB-INF/classes/</span>
				<span style="font-family: 宋体;">下，创建或编辑</span>
				<span lang="EN-IE">jive_init.properties</span>
				<span style="font-family: 宋体;">，加入行：</span>
		</p>
		<p class="60" style="margin: 3pt 0cm;">
				<span lang="EN-IE">jiveHome=C:\\javasource\\jive\\WEB-INF\\jiveHome</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这是指定</span>
				<span lang="EN-IE">jivHome</span>
				<span style="font-family: 宋体;">的目录，</span>
				<span lang="EN-IE">jiveHome</span>
				<span style="font-family: 宋体;">主要放置</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的配置文件和搜索等内部工作文件，一般是建立在</span>
				<span lang="EN-IE">WEB-INF</span>
				<span style="font-family: 宋体;">目录下，这样，</span>
				<span lang="EN-IE">jiveHome</span>
				<span style="font-family: 宋体;">的内容就不会被外界通过浏览器直接访问到，要注意是绝对路径。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">（</span>
				<span lang="EN-IE">4</span>
				<span style="font-family: 宋体;">）可以安装设置</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统。通过浏览输入网址：</span>
				<span lang="EN-IE">
						<a href="http://localhost:8080/jive/admin/setup/">http://localhost:8080/jive/admin/setup/</a>
				</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的安装导航程序会自动进行安装检查。由于</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">编码是</span>
				<span lang="EN-IE"> ISO8859_1</span>
				<span style="font-family: 宋体;">，如果涉及需要设置</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">编码方式的提问，都设置为英文。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">管理员密码最好更改一下，默认用户名和密码是</span>
				<span lang="EN-IE">admin </span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">admin</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">全部设置完成后，进入</span>
				<span lang="EN-IE">http://localhost:8080/jive/</span>
				<span style="font-family: 宋体;">可以浏览。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">进入</span>
				<span lang="EN-IE">http://localhost:8080/jive/admin</span>
				<span style="font-family: 宋体;">可以实现论坛管理，可以设置全局过滤器，一般设置如下过滤器：</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">TextStyle </span>
				<span style="font-family: 宋体;">文本格式。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">Newline </span>
				<span style="font-family: 宋体;">新一行。</span>
				<span lang="EN-IE">
				</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">Profanity </span>
				<span style="font-family: 宋体;">过渡亵渎或不恰当词语。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">URLConverter URLConverter</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">ImageFilter ImageFilter </span>
				<span style="font-family: 宋体;">支持上传图片。</span>
				<span lang="EN-IE">        </span>
		</p>
		<p class="22" style="margin-left: 38.25pt; text-indent: -17pt;">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">CodeHighlighter CodeHighlighter</span>
				<span style="font-family: 宋体;">。</span>
				<span lang="EN-IE">
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">另外，缓存设置也很重要，可根据访问量、缓存击中率以及实际内存大小调整，可以提高论坛的性能。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">图片上传路径的设置需要通过手工修改</span>
				<span lang="EN-IE">jiveHome</span>
				<span style="font-family: 宋体;">下的</span>
				<span lang="EN-IE">jive_config.xml</span>
				<span style="font-family: 宋体;">。打开</span>
				<span lang="EN-IE">jive_config.xml</span>
				<span style="font-family: 宋体;">会发现，所有在管理配置中配置的信息都保存在这里，找到下列配置：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">&lt;upload&gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        &lt;dir&gt;/home/bqlr/jive/upload/&lt;/dir&gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        &lt;relurl&gt;upload/&lt;/relurl&gt;</span>
		</p>
		<p class="7">
				<span lang="EN-IE">&lt;/upload&gt;</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">其中，</span>
				<span lang="EN-IE">dir</span>
				<span style="font-family: 宋体;">是上传图片存放的绝对路径；</span>
				<span lang="EN-IE">relurl</span>
				<span style="font-family: 宋体;">是网址的相对路径，比如</span>
				<span lang="EN-IE">upload/</span>
				<span style="font-family: 宋体;">，那就表示输入下列网址：“</span>
				<span lang="EN-IE">
						<a href="http://localhost:8080/jive/upload/xxxx.jpg">http://localhost:8080/jive/upload/xxxx.jpg</a>
				</span>
				<span style="font-family: 宋体;">”，就可以看到上传的图片。因为上传图片有自动缩小功能，因此需要</span>
				<span lang="EN-IE">Linux</span>
				<span style="font-family: 宋体;">安装时是带图形</span>
				<span lang="EN-IE">X86</span>
				<span style="font-family: 宋体;">的完全安装。用户如为中文名，将影响图片文件名。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">以上是</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛的安装</span>
				<span style="font-family: 宋体;">。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:29 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(8)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66837.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:29:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66837.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66837.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66837.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66837.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66837.html</trackback:ping><description><![CDATA[
		<br />
		<p>
		</p>
		<div>
				<a class="adHeadline" target="_top" href="http://www.adbrite.com/mb/commerce/purchase_form.php?opid=129862&amp;afsid=1">Your Ad Here</a>
		</div>
		<!-- End: AdBrite -->
		<h2>
				<a name="_Toc60649970">
				</a>
				<a name="_Toc55117357">
				</a>
				<a name="_Toc55116013">
				</a>
				<a name="_Toc53800167">
						<span lang="EN-IE">8  </span>
				</a>
				<span style="font-family: 楷体_GB2312;">小结</span>
		</h2>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">本章主要介绍了一个基于</span>
				<span lang="EN-IE">J2EE Web</span>
				<span style="font-family: 宋体;">技术进行设计开发的论坛系统，通过这个系统的剖析，能够了解和掌握</span>
				<span lang="EN-IE">GOF</span>
				<span style="font-family: 宋体;">设计模式，学会</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">实战中一些处理技巧和技术。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">使用</span>
				<span lang="EN-IE">GOF</span>
				<span style="font-family: 宋体;">设计模式的主要优点：使得复杂系统的架构变得更加清晰而且有条理，而这一点正是许多程序员在开发实用系统中所缺乏的，可能导致的结果是大大降低</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">系统可维护性以及可拓展性，重新回到了传统编程语言的陷阱中。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">因此，</span>
				<span lang="EN-IE">GOF</span>
				<span style="font-family: 宋体;">设计模式对于</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">设计编程的重要性是无论怎么强调也不过分，它能够帮助程序员更加深入地理解</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">完全面向对象特性，从而以真正的面向对象设计概念进行实用系统的设计和开发。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统是一个完全的</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">系统，整个系统的最大特点是自我定制实现，它为了提高数据库的访问性能，使用了自己开发的数据库连接池；为了提高系统的数据处理系统，它使用了缓存机制；为了实现用户安全管理机制，它使用</span>
				<span lang="EN-IE">Proxy</span>
				<span style="font-family: 宋体;">模式实现了角色权限的定位和检查等。这些模块功能在很多系统中都是需要的，但是如果想从</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统提炼出这些模块功能以达到重用，又是非常困难的。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">因此，开发者需要一种具有一定高度的框架技术。在这个框架技术中，所有这些通用技术都能够自动实现，无需再自行设计和开发，能够将更多精力投入到与业务有关的特定功能开发中。</span>
				<span lang="EN-IE">J2EE</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">技术实际就是这种框架技术。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">学习和研究</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛系统也非常有助于程序员学习和理解</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">J2EE</span>
				<span style="font-family: 宋体;">完整的框架技术，因为它们的目的都是一样，只不过实现的途径不一样而已。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66837.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:29 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66837.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(6)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66835.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:28:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66835.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66835.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66835.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66835.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66835.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="_Toc53800163">
						<span lang="EN-IE">6  Jive</span>
				</a>
				<span style="font-family: 楷体_GB2312;">图形处理</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">提供了强大的论坛功能，但是有些功能离实际需求还是有一定的距离，例如论坛是用于信息交流讨论的场所。而信息不只是文字，有时还包括图片或一些</span>
				<span lang="EN-IE">PDF</span>
				<span style="font-family: 宋体;">等类型的文件，那么如何在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中实现这样的功能呢？</span>
		</p>
		<h3>
				<a name="_Toc60649967">
				</a>
				<a name="_Toc55117354">
				</a>
				<a name="_Toc55116010">
				</a>
				<a name="_Toc53800164">
						<span lang="EN-US">6.1  </span>
				</a>
				<span style="font-family: 黑体;">图片上传处理</span>
		</h3>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">HTML</span>
				<span style="font-family: 宋体;">中，使用表单</span>
				<span lang="EN-IE">Form</span>
				<span style="font-family: 宋体;">主要是用来向服务器提交数据，格式如下：</span>
		</p>
		<p class="60">
				<span style="font-family: 宋体;">＜</span>
				<span lang="EN-IE">FORM ACTION="URL" </span>
		</p>
		<p class="5" style="text-indent: 57.7pt;">
				<span lang="EN-IE">METHOD="GET|POST" </span>
		</p>
		<p class="5" style="text-indent: 57.7pt;">
				<span lang="EN-IE">ENCTYPE="…" TARGET="..."</span>
				<span style="font-family: 宋体;">＞</span>
		</p>
		<p class="5" style="text-indent: 57.7pt;">
				<span lang="EN-IE">. . .</span>
		</p>
		<p class="7">
				<span style="font-family: 宋体;">＜</span>
				<span lang="EN-IE">/FORM</span>
				<span style="font-family: 宋体;">＞</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">enctype</span>
				<span style="font-family: 宋体;">指定了表单提交给服务器时的内容形式（</span>
				<span lang="EN-IE">Content-Type</span>
				<span style="font-family: 宋体;">），默认值是</span>
				<span lang="EN-IE">"application/x-www-form-urlencoded"</span>
				<span style="font-family: 宋体;">，这时，表单信息一般采用</span>
				<span lang="EN-IE">URL</span>
				<span style="font-family: 宋体;">编码制。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">但是，当向服务器传送图片或文件这样包含非</span>
				<span lang="EN-IE">ASCII</span>
				<span style="font-family: 宋体;">字符或二进制数的数据时，根据</span>
				<span lang="EN-IE">RFC1867</span>
				<span style="font-family: 宋体;">规定，就必须使用“</span>
				<span lang="EN-IE">multipart/form-data</span>
				<span style="font-family: 宋体;">”内容类型。</span>
				<span lang="EN-IE">
				</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">其实无论是默认表单信息，还是图片文件，这些内容都是装载在</span>
				<span lang="EN-IE">HTTP</span>
				<span style="font-family: 宋体;">协议的正文内容部分，都可以看成</span>
				<span lang="EN-IE">HTTP</span>
				<span style="font-family: 宋体;">协议携带的对象，只是两种正文内容形式不一样。前者是</span>
				<span lang="EN-IE">String</span>
				<span style="font-family: 宋体;">字符串类型，而后者则是一个通用的数据对象类型（</span>
				<span lang="EN-IE">Object</span>
				<span style="font-family: 宋体;">）。在以后章节中将专门讨论</span>
				<span lang="EN-IE">HTTP</span>
				<span style="font-family: 宋体;">协议装载数据对象的底层细节。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">使用“</span>
				<span lang="EN-IE">multipart/form-data</span>
				<span style="font-family: 宋体;">”上传文件的格式写法如下：</span>
		</p>
		<p class="60">
				<span style="font-family: 宋体;">＜</span>
				<span lang="EN-IE">FORM ACTION="URL" METHOD="GET|POST" ENCTYPE=" multipart/form-data "</span>
				<span style="font-family: 宋体;">＞</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  &lt;INPUT TYPE</span>
				<span style="font-family: 宋体;">＝</span>
				<span lang="EN-IE">FILE NAME</span>
				<span style="font-family: 宋体;">＝</span>
				<span lang="EN-IE">file1&gt;</span>
		</p>
		<p class="7">
				<span style="font-family: 宋体;">＜</span>
				<span lang="EN-IE">/FORM</span>
				<span style="font-family: 宋体;">＞</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">文件通过</span>
				<span lang="EN-IE">HTTP</span>
				<span style="font-family: 宋体;">协议传送到服务器端后，需要在服务器端对该文件进行专门的接受。</span>
				<span lang="EN-IE">HttpServletRequest</span>
				<span style="font-family: 宋体;">没有提供直接获取文件数据的方法，因此需要开发专门的服务器文件处理组件。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">目前有两种上传文件处理组件：一种是基于完全</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">结构的，使用</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">来处理上传的文件，以</span>
				<span lang="EN-IE">SmartUpload</span>
				<span style="font-family: 宋体;">（</span>
				<span lang="EN-IE">http://www.jspsmart.com</span>
				<span style="font-family: 宋体;">）最常用；还有一种是完全的</span>
				<span lang="EN-IE">JavaBeans</span>
				<span style="font-family: 宋体;">组件：</span>
				<span lang="EN-IE">Cos</span>
				<span style="font-family: 宋体;">文件上传组件包（</span>
				<span lang="EN-IE">http://www.servlets.com/cos/index.html</span>
				<span style="font-family: 宋体;">），</span>
				<span lang="EN-IE">Cos</span>
				<span style="font-family: 宋体;">可以使用在</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">中，也可以使用在</span>
				<span lang="EN-IE">Servlet</span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">Servlet Filter</span>
				<span style="font-family: 宋体;">中。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">由于在实际应用中，文件上传功能往往和其他正常表单参数一起混合使用，而不是独立使用的。因此，可以设定一个</span>
				<span lang="EN-IE">Servlet</span>
				<span style="font-family: 宋体;">专门用来处理这类混合表单的请求，在将文件接受处理后，自动导向到处理表单正常参数的</span>
				<span lang="EN-IE">JSP/Servlet</span>
				<span style="font-family: 宋体;">去处理。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">表单调用示例如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">&lt;form action="&lt;%=request.getContextPath()%&gt;/multipartformserv"</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     method="post" enctype="multipart/form-data"&gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="hidden" name="FORWARDNAME" value="login.jsp" &gt;  </span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="file" name="file1" &gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="hidden" name="maxwidth" value="120" &gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="hidden" name="maxheight" value="60" &gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="text" name="username" &gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   &lt;input type="text" name="password" &gt;</span>
		</p>
		<p class="7">
				<span lang="EN-IE">&lt;/form&gt;</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在这个表单中，既有文件提交，也有</span>
				<span lang="EN-IE">username</span>
				<span style="font-family: 宋体;">这样正常的参数需要提交，提交的</span>
				<span lang="EN-IE">Servlet</span>
				<span style="font-family: 宋体;">名为</span>
				<span lang="EN-IE">multipartformserv</span>
				<span style="font-family: 宋体;">。由</span>
				<span lang="EN-IE">multipartformserv</span>
				<span style="font-family: 宋体;">来处理上传的文件，然后再自动转交到</span>
				<span lang="EN-IE">FORWARDNAME</span>
				<span style="font-family: 宋体;">的值</span>
				<span lang="EN-IE">login.jsp</span>
				<span style="font-family: 宋体;">进行</span>
				<span lang="EN-IE">username</span>
				<span style="font-family: 宋体;">等正常参数的处理。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在表单中，如果设定</span>
				<span lang="EN-IE">maxwidth</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">maxiheight</span>
				<span style="font-family: 宋体;">，那么表示如果上传的图片超过这个尺寸，服务器将缩小图片到这个尺寸。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">编制一个专门用来统一处理</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统中所有文件处理的</span>
				<span lang="EN-IE">Servlet</span>
				<span style="font-family: 宋体;">，这样有利于简化系统。编制</span>
				<span lang="EN-IE">MultipartFormServ</span>
				<span style="font-family: 宋体;">如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public class MultipartFormServ extends HttpServlet {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  static final private String CONTENT_TYPE = "text/html";</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  //</span>
				<span style="font-family: 宋体;">文件上传处理</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  private static MultipartFormHandle mf = MultipartFormHandle.getInstance();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  //</span>
				<span style="font-family: 宋体;">文件上传后存放的临时目录</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  private String dirName;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  private ServletContext context;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  public void init() throws ServletException {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    // </span>
				<span style="font-family: 宋体;">从</span>
				<span lang="EN-IE">web.xml</span>
				<span style="font-family: 宋体;">中读取上传目录参数</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    dirName = mf.getUploaddir();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    if (dirName == null) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      throw new ServletException("Please supply uploadDir parameter");</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">  //</span>
				<span style="font-family: 宋体;">处理带有文件内容的请求</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  public void doPost(HttpServletRequest request, HttpServletResponse response) </span>
		</p>
		<p class="5">
				<span lang="EN-IE">         throws ServletException, IOException {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    try {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       mf.init(dirName,request); //</span>
				<span style="font-family: 宋体;">调用文件上传处理器处理</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       //</span>
				<span style="font-family: 宋体;">得到</span>
				<span lang="EN-IE">FORWARDNAME</span>
				<span style="font-family: 宋体;">参数值</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       String forward=mf.getForwardProgram();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      if (forward.equals(""))</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">         errorMessage("no forward program", response);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">         return;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      String param=mf.getForwardProgramParam(); </span>
		</p>
		<p class="5">
				<span lang="EN-IE">      mf.clear();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       //</span>
				<span style="font-family: 宋体;">引导分流到</span>
				<span lang="EN-IE">forward</span>
				<span style="font-family: 宋体;">参数值进行其他文本参数处理</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      getServletConfig().getServletContext().</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           getRequestDispatcher("/"+forward+"?"+param).forward(request, response);</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }catch (Exception Ex) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">          throw new ServletException(Ex.getMessage());</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  }</span>
		</p>
		<div>
				<table align="left" cellpadding="0" cellspacing="0" height="234" hspace="0" vspace="0" width="392">
						<tbody>
								<tr>
										<td style="padding: 0cm 9pt;" align="left" height="234" valign="top">
												<p class="a4">
														<span lang="EN-US">
																<img src="http://www.chinaitpower.com/A-A-B/Image/2005/07/23/image009.jpg" alt="" border="0" height="130" width="200" />
														</span>
												</p>
												<p class="a5">
														<span style="font-family: 宋体;">图</span>
														<span lang="EN-US">3-8  </span>
														<span style="font-family: 宋体;">上传文件处理框架</span>
												</p>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">MultipartFormHandler</span>
				<span style="font-family: 宋体;">主要调用</span>
				<span lang="EN-IE">Cos</span>
				<span style="font-family: 宋体;">组件处理上传文件，对上传文件图形大小进行处理，然后将图形搬迁到指定的目录；同时也将请求信号中的正常参数提取出来，以作为转发使用。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这样一个图形或文件上传系统已经形成了一个框架结构，可以重复使用在任何需要图片或文件上传处理的系统中，如图</span>
				<span lang="EN-IE">3-8</span>
				<span style="font-family: 宋体;">所示。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">图</span>
				<span lang="EN-IE">3-8</span>
				<span style="font-family: 宋体;">中上传文件处理额</span>
				<span lang="EN-IE">Servlet</span>
				<span style="font-family: 宋体;">相当于请求信号</span>
				<span lang="EN-IE">Request</span>
				<span style="font-family: 宋体;">的一个过滤器，既然正常的</span>
				<span lang="EN-IE">Request</span>
				<span style="font-family: 宋体;">处理机制不能从</span>
				<span lang="EN-IE">Request</span>
				<span style="font-family: 宋体;">提取携带的文件，那么，使用一个过滤器先将文件提取出来，剩余的再通过正常</span>
				<span lang="EN-IE">Request</span>
				<span style="font-family: 宋体;">处理机制去处理。</span>
		</p>
		<h3>
				<a name="_Toc60649968">
				</a>
				<a name="_Toc55117355">
				</a>
				<a name="_Toc55116011">
				</a>
				<a name="_Toc53800165">
						<span lang="EN-US">6.2  </span>
				</a>
				<span style="font-family: 黑体;">服务器端图形处理</span>
		</h3>
		<p class="MsoNormal">
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">最初是以</span>
				<span lang="EN-IE">Applet</span>
				<span style="font-family: 宋体;">等客户端图形处理为技术起点的，而本节讨论的是如何在</span>
				<span lang="EN-IE">Servlet/JSP</span>
				<span style="font-family: 宋体;">中实现图形处理。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，图片可以用来显示用户的头像，用户在上传自己头像图片时，该图片的大小可能不一，但是由于版面原因，显示的头像图片又有大小限制，那么就需要在用户上传图片时对图片大小做一个检查。如果超过规定大小，就进行一定的缩放处理。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">缩放处理有两种方式：是在</span>
				<span lang="EN-IE">HTML</span>
				<span style="font-family: 宋体;">显示时，使用</span>
				<span lang="EN-IE">image </span>
				<span style="font-family: 宋体;">语法的</span>
				<span lang="EN-IE">width</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">height</span>
				<span style="font-family: 宋体;">来
限制大小，但是这样做只是解决了表面问题，无法解决大字节图片传送到客户端带来的性能影响，这个图片因为是用户发言的头像，将会在每个帖子里面显示。如果
头像都是巨大图片，对帖子显示速度的影响是很大，因此必须在服务器端进行缩小后，再传送到客户端，这样提高了论坛系统性能。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">服务器端的图形处理需要使用到</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">的图形处理技术，而且图形处理是在服务器端的</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">容器中进行的。和以往</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">在客户端进行图形处理稍微有所不同，相同的是都要使用计算机的底层图形支持资源。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">J2SE 1.4</span>
				<span style="font-family: 宋体;">提供新的增强的图形处理功能，</span>
				<span lang="EN-IE">JDK1.4</span>
				<span style="font-family: 宋体;">中最新的</span>
				<span lang="EN-IE">javax.imageio.ImageIO</span>
				<span style="font-family: 宋体;">对图片进行读写操作，而使用</span>
				<span lang="EN-IE">java.awt.geom.AffineTransform</span>
				<span style="font-family: 宋体;">对图片进行尺寸缩放处理。</span>
		</p>
		<p class="60">
				<span lang="EN-IE">import java.io.File;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">import java.awt.image.BufferedImage;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">import java.awt.Image;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">import java.awt.image.AffineTransformOp;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">import javax.imageio.ImageIO;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">import java.awt.geom.AffineTransform;</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">public class UploadImg{</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     /**</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * </span>
				<span style="font-family: 宋体;">参数设置</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * @param fromdir </span>
				<span style="font-family: 宋体;">图片的原始目录</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * @param todir </span>
				<span style="font-family: 宋体;">处理后的图片存放目录</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * @param imgfile </span>
				<span style="font-family: 宋体;">原始图片</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * @param sysimgfile </span>
				<span style="font-family: 宋体;">处理后的图片文件名前缀</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     */ </span>
		</p>
		<p class="5">
				<span lang="EN-IE">           public void init(String fromdir,String todir,String imgfile,String sysimgfile)</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  this.fromdir=fromdir;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  this.todir=todir;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  this.imgfile=imgfile;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  this.sysimgfile=sysimgfile;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">             }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    …</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public boolean CreateThumbnail() throws Exception</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        //ext</span>
				<span style="font-family: 宋体;">是图片的格式</span>
				<span lang="EN-IE"> gif</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">JPG </span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">png</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        String ext="" </span>
		</p>
		<p class="5">
				<span lang="EN-IE">        double Ratio=0.0;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        File oldFile = new File(fromdir,imgfile);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (!F.isFile())  //</span>
				<span style="font-family: 宋体;">检查是否存在此图片文件</span>
		</p>
		<p class="5">
				<span lang="EN-IE">             throw new Exception(F+" is not image file error in CreateThumbnail!");</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">         //</span>
				<span style="font-family: 宋体;">首先判断上传的图片是</span>
				<span lang="EN-IE">gif</span>
				<span style="font-family: 宋体;">还是</span>
				<span lang="EN-IE">JPG ImageIO</span>
				<span style="font-family: 宋体;">，只能将</span>
				<span lang="EN-IE">gif</span>
				<span style="font-family: 宋体;">转换为</span>
				<span lang="EN-IE">png</span>
		</p>
		<p class="5">
				<span lang="EN-IE">         if (isJpg(imgfile)){</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            ext="jpg";</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }else{</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           ext="png"; </span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        File newFile = new File(todir,sysimgfile+"."+ext); </span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">        BufferedImage Bi = ImageIO.read(oldFile);  //</span>
				<span style="font-family: 宋体;">读取原始图片</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if ((Bi.getHeight()&gt;120) || (Bi.getWidth()&gt;120)){</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            if (Bi.getHeight()&gt;Bi.getWidth())</span>
		</p>
		<p class="5">
				<span lang="EN-IE">              Ratio = 120.0/Bi.getHeight();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            else</span>
		</p>
		<p class="5">
				<span lang="EN-IE">              Ratio = 120.0/Bi.getWidth();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       //</span>
				<span style="font-family: 宋体;">进行图片转换</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       AffineTransformOp op = </span>
		</p>
		<p class="5">
				<span lang="EN-IE">          new AffineTransformOp(AffineTransform.getScaleInstance(Ratio, Ratio), null);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       Image itemp = op.filter(Bi, null);</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">       try { //</span>
				<span style="font-family: 宋体;">写入转换后的图片</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           ImageIO.write((BufferedImage) itemp, ext, newFile);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       }catch (Exception ex) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            throw new Exception(ex.getMessage()); </span>
		</p>
		<p class="5">
				<span lang="EN-IE">       }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       return (true);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   }</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">该类中由于使用到了</span>
				<span lang="EN-IE">Java </span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">AWT</span>
				<span style="font-family: 宋体;">，虽然没有实际显示，但</span>
				<span lang="EN-IE">Linux</span>
				<span style="font-family: 宋体;">系统下需要</span>
				<span lang="EN-IE">X11 Windows</span>
				<span style="font-family: 宋体;">的支持（安装</span>
				<span lang="EN-IE">Linux</span>
				<span style="font-family: 宋体;">时需安装</span>
				<span lang="EN-IE"> XFree86</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-IE">Linux</span>
				<span style="font-family: 宋体;">完全安装方式包括安装</span>
				<span lang="EN-IE">XFree86</span>
				<span style="font-family: 宋体;">）。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">该缩放功能是在图片上传到服务器后再进行的处理，可以对</span>
				<span lang="EN-IE">JPG</span>
				<span style="font-family: 宋体;">进行缩小放大；对上传是</span>
				<span lang="EN-IE">GIF</span>
				<span style="font-family: 宋体;">的图片，缩放后变成</span>
				<span lang="EN-IE">PNG</span>
				<span style="font-family: 宋体;">图片格式文件。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66835.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:28 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66835.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(4)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66833.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:27:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66833.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66833.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66833.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66833.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66833.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="_Toc53800154">
						<span lang="EN-IE">4  Jive</span>
				</a>
				<span style="font-family: 楷体_GB2312;">的缓存机制</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛的一个主要特点就是其性能速度快，因此很多巨大访问量的网站都采用了</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛。这些都是由于</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">采取了高速缓存机制。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">缓存（</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">）机制是提高系统运行性能必不可少的技术。缓存机制从原理上讲比较简单，就是在原始数据第一次读取后保存在内存中，下次读取时，就直接从内存中读取。原始数据有可能保存在持久化介质或网络上。缓存机制也是代理模式的一种实现。</span>
		</p>
		<h3>
				<a name="_Toc60649958">
				</a>
				<a name="_Toc55117345">
				</a>
				<a name="_Toc55116001">
				</a>
				<a name="_Toc53800155">
						<span lang="EN-US">4.1  </span>
				</a>
				<span style="font-family: 黑体;">缓存原理和实现</span>
		</h3>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">总体来说实现得不是非常精简和有效。它是针对每个具体数据对象逐个实现缓冲，这种“穷尽”的办法不是实践所推荐的用法。通过使用动态代理模式，可以根据具体方法的不同来实现缓存是值得推荐的做法。</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的缓存实现得比较简单，可以用来学习和研究缓存机制。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中的</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">实现了缓存机制的大部分行为，它是将对象用惟一的关键字</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">作标识保存在</span>
				<span lang="EN-IE">HashMap</span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">Hashtable</span>
				<span style="font-family: 宋体;">中。当然，必须知道这些对象的大小，这个前提条件的设定可以保证缓存增长时不会超过规定的最大值。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果缓存增长得太大，一些不经常被访问的对象将首先从缓存中删除。如果设置了对象的最大生命周期时间，即使这个对象被反复频繁访问，也将从缓存中删除。这个特性可以适用于一些周期性需要刷新的数据，如来自数据库的数据。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Cach</span>
				<span style="font-family: 宋体;">中除了</span>
				<span lang="EN-IE">getObject()</span>
				<span style="font-family: 宋体;">方法的性能依据缓存大小，其他方法的性能都是比较快的。一个</span>
				<span lang="EN-IE">HashMap</span>
				<span style="font-family: 宋体;">用来实现快速寻找，两个</span>
				<span lang="EN-IE">LinkedList</span>
				<span style="font-family: 宋体;">中一个以一定的访问顺序来保存对象，叫</span>
				<span lang="EN-IE">accessed LinkedList</span>
				<span style="font-family: 宋体;">；另外一个以它们加入缓存的顺序保存这些对象，这种保存对象只是保存对象的引用，叫</span>
				<span lang="EN-IE"> age LinkedList</span>
				<span style="font-family: 宋体;">。注意，这里的</span>
				<span lang="EN-IE">LinkedList</span>
				<span style="font-family: 宋体;">不是</span>
				<span lang="EN-IE">JDK</span>
				<span style="font-family: 宋体;">中的</span>
				<span lang="EN-IE">LinkedList</span>
				<span style="font-family: 宋体;">，而是</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">自己定义的</span>
				<span lang="EN-IE">LinkedList</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">当对象被加入缓存时，首先被</span>
				<span lang="EN-IE">CacheObject</span>
				<span style="font-family: 宋体;">封装。封装有以下信息：对象大小（以字节计算），一个指向</span>
				<span lang="EN-IE">accessed LinkedList</span>
				<span style="font-family: 宋体;">的引用，一个指向</span>
				<span lang="EN-IE">age LinkedList</span>
				<span style="font-family: 宋体;">的引用。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">当从缓存中获取一个对象如</span>
				<span lang="EN-IE">ObjectA</span>
				<span style="font-family: 宋体;">时，首先，</span>
				<span lang="EN-IE">HashMap</span>
				<span style="font-family: 宋体;">寻找到指向封装</span>
				<span lang="EN-IE">ObjectA</span>
				<span style="font-family: 宋体;">等信息的</span>
				<span lang="EN-IE">CacheObject</span>
				<span style="font-family: 宋体;">对象。然后，这个对象将被移动到</span>
				<span lang="EN-IE">accessed LinkedList</span>
				<span style="font-family: 宋体;">的前面，还有其他一些动作如缓存清理、删除、过期失效等都是在这个动作中一起触发实现的。</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public class Cache implements Cacheable {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    /**</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * </span>
				<span style="font-family: 宋体;">因为</span>
				<span lang="EN-IE">System.currentTimeMillis()</span>
				<span style="font-family: 宋体;">执行非常耗费性能，因此如果</span>
				<span lang="EN-IE">get</span>
				<span style="font-family: 宋体;">操作都执行</span>
		</p>
		<p class="5" style="text-indent: 44.1pt;">
				<span lang="EN-IE">* </span>
				<span style="font-family: 宋体;">这条语句将会形成性能瓶颈，</span>
				<span style="font-family: 宋体;">通过一个全局时间戳来实现每秒更新</span>
		</p>
		<p class="5" style="text-indent: 44.1pt;">
				<span lang="EN-IE">* </span>
				<span style="font-family: 宋体;">当然，这意味着在缓存过期时间计算上有一到几秒的误差</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     */</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected static long currentTime = CacheTimer.currentTime;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //CacheObject</span>
				<span style="font-family: 宋体;">对象</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected HashMap cachedObjectsHash;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //accessed LinkedList </span>
				<span style="font-family: 宋体;">最经常访问的排列在最前面</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected LinkedList lastAccessedList;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">以缓存加入顺序排列，最后加入排在最前面；越早加入的排在最后面</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected LinkedList ageList;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">缓存最大限制</span>
				<span style="font-family: 宋体;">默认是</span>
				<span lang="EN-IE">128k </span>
				<span style="font-family: 宋体;">可根据内存设定，越大性能越高</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected int maxSize =  128 * 1024;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">当前缓存的大小</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected int size = 0;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">最大生命周期时间，默认是没有</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected long maxLifetime = -1;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">缓存的击中率，用于评测缓存效率</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected long cacheHits, cacheMisses = 0L;</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public Cache() {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">构造</span>
				<span lang="EN-IE">HashMap. </span>
				<span style="font-family: 宋体;">默认</span>
				<span lang="EN-IE">capacity </span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">11</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">如果实际大小超过</span>
				<span lang="EN-IE">11</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-IE">HashMap</span>
				<span style="font-family: 宋体;">将自动扩充，但是每次扩充都</span>
		</p>
		<p class="5" style="text-indent: 57.7pt;">
				<span lang="EN-IE">// </span>
				<span style="font-family: 宋体;">是性能开销，因此期初要设置大一点</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cachedObjectsHash = new HashMap(103);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        lastAccessedList = new LinkedList();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        ageList = new LinkedList();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public Cache(int maxSize) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.maxSize = maxSize;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public Cache(long maxLifetime) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.maxLifetime = maxLifetime;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public Cache(int maxSize, long maxLifetime) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.maxSize = maxSize;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.maxLifetime = maxLifetime;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public int getSize() {        return size;    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public int getMaxSize() {        return maxSize;    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public void setMaxSize(int maxSize) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.maxSize = maxSize;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">有可能缓存大小超过最大值，需要激活删除清理动作</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cullCache();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public synchronized int getNumElements() {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return cachedObjectsHash.size();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    /**</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * </span>
				<span style="font-family: 宋体;">增加一个</span>
				<span lang="EN-IE">Cacheable</span>
				<span style="font-family: 宋体;">对象</span>
		</p>
		<p class="5" style="text-indent: 44.75pt;">
				<span lang="EN-IE">* </span>
				<span style="font-family: 宋体;">因为</span>
				<span lang="EN-IE">HashMap</span>
				<span style="font-family: 宋体;">不是线程安全的，所以操作方法要使用同步</span>
		</p>
		<p class="5" style="text-indent: 44.75pt;">
				<span lang="EN-IE">* </span>
				<span style="font-family: 宋体;">如果使用</span>
				<span lang="EN-IE">Hashtable</span>
				<span style="font-family: 宋体;">就不必同步</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     */</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public synchronized void add(Object key, Cacheable object) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">删除已经存在的</span>
				<span lang="EN-IE">key</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        remove(key);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        int objectSize = object.getSize();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">如果被缓存对象的大小超过最大值，就放弃</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (objectSize &gt; maxSize * .90) {            return;        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        size += objectSize;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        //</span>
				<span style="font-family: 宋体;">创建一个</span>
				<span lang="EN-IE">CacheObject</span>
				<span style="font-family: 宋体;">对象</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        CacheObject cacheObject = new CacheObject(object, objectSize);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cachedObjectsHash.put(key, cacheObject);  //</span>
				<span style="font-family: 宋体;">保存这个</span>
				<span lang="EN-IE">CacheObject</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">加入</span>
				<span lang="EN-IE">accessed LinkedList</span>
				<span style="font-family: 宋体;">，</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">自己的</span>
				<span lang="EN-IE">LinkedList</span>
				<span style="font-family: 宋体;">在加入时可以返回值</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">保存引用</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cacheObject.lastAccessedListNode = lastAccessedNode;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">加入到</span>
				<span lang="EN-IE">age LinkedList</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        LinkedListNode ageNode = ageList.addFirst(key);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">这里直接调用</span>
				<span lang="EN-IE">System.currentTimeMillis();</span>
				<span style="font-family: 宋体;">用法值得讨论</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        ageNode.timestamp = System.currentTimeMillis();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">保存引用</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cacheObject.ageListNode = ageNode;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">做一些清理工作</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cullCache();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    /**</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     * </span>
				<span style="font-family: 宋体;">从缓存中获得一个被缓存的对象，这个方法在下面两种情况返回空</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     *    &lt;li&gt;</span>
				<span style="font-family: 宋体;">该对象引用从来没有被加入缓存中</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     *    &lt;li&gt;</span>
				<span style="font-family: 宋体;">对象引用因为过期被清除</span>
				<span lang="EN-IE">&lt;/ul&gt;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">     */</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public synchronized Cacheable get(Object key) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">清除过期缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        deleteExpiredEntries();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        //</span>
				<span style="font-family: 宋体;">以</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">从缓存中获取一个对象引用</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (cacheObject == null) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            // </span>
				<span style="font-family: 宋体;">不存在，增加未命中率</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            cacheMisses++;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            return null;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">存在，增加命中率</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cacheHits++;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">从</span>
				<span lang="EN-IE">accessed LinkedList</span>
				<span style="font-family: 宋体;">中将对象从当前位置删除</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // </span>
				<span style="font-family: 宋体;">重新插入在第一个</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        cacheObject.lastAccessedListNode.remove();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        lastAccessedList.addFirst(cacheObject.lastAccessedListNode);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return cacheObject.object;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    …</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">中，关键字</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">是一个对象，为了再次提高性能，可以进一步将</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">确定为一个</span>
				<span lang="EN-IE">long</span>
				<span style="font-family: 宋体;">类型的整数。</span>
				<span lang="EN-IE">
				</span>
		</p>
		<h3>
				<a name="_Toc60649959">
				</a>
				<a name="_Toc55117346">
				</a>
				<a name="_Toc55116002">
				</a>
				<a name="_Toc53800156">
						<span lang="EN-US">4.2  </span>
				</a>
				<span style="font-family: 黑体;">缓存使用</span>
		</h3>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">建立</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">只是为了提高原来的</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">性能，本身无多大意义，可以将</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">看成与</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">一样的类。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">的关键字</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">以及</span>
				<span lang="EN-IE"> ForumMessage</span>
				<span style="font-family: 宋体;">等</span>
				<span lang="EN-IE">long</span>
				<span style="font-family: 宋体;">类型的</span>
				<span lang="EN-IE">ID</span>
				<span style="font-family: 宋体;">，值</span>
				<span lang="EN-IE">Value</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">以及</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">等的对象。这些基本是通过</span>
				<span lang="EN-IE">DatabaseCacheManager</span>
				<span style="font-family: 宋体;">实现完成，在主要类</span>
				<span lang="EN-IE">DbForumFactory</span>
				<span style="font-family: 宋体;">的初始化构造时，同时构造了</span>
				<span lang="EN-IE">DatabaseCacheManager</span>
				<span style="font-family: 宋体;">的实例</span>
				<span lang="EN-IE">cacheManager</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">前面过滤器功能分析中，</span>
				<span lang="EN-IE">Message</span>
				<span style="font-family: 宋体;">对象获得方法的第一句如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">protected ForumMessage getMessage(long messageID, long threadID, long forumID) throws</span>
		</p>
		<p class="5">
				<span lang="EN-IE">      ForumMessageNotFoundException {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    DbForumMessage message = cacheManager.messageCache.get(messageID);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    …</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">其中，</span>
				<span lang="EN-IE">cacheManager</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">DatabaseCacheManager</span>
				<span style="font-family: 宋体;">的实例，</span>
				<span lang="EN-IE">DatabaseCacheManager</span>
				<span style="font-family: 宋体;">是一个缓存</span>
				<span lang="EN-IE">Facade</span>
				<span style="font-family: 宋体;">类。在其中包含了</span>
				<span lang="EN-IE">5</span>
				<span style="font-family: 宋体;">种类型的缓存，都是针对</span>
				<span lang="EN-IE"> Jive</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">5</span>
				<span style="font-family: 宋体;">个主要对象，</span>
				<span lang="EN-IE">DatabaseCacheManager</span>
				<span style="font-family: 宋体;">主要代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public class DatabaseCacheManager {</span>
		</p>
		<p class="5" style="text-indent: 40.6pt;">
				<span lang="EN-IE">…</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public UserCache userCache;                          //</span>
				<span style="font-family: 宋体;">用户资料缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public GroupCache groupCache;                       //</span>
				<span style="font-family: 宋体;">组资料缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public ForumCache forumCache;                       //Forum</span>
				<span style="font-family: 宋体;">论坛缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public ForumThreadCache threadCache;                //Thread</span>
				<span style="font-family: 宋体;">主题缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public ForumMessageCache messageCache;          //Message</span>
				<span style="font-family: 宋体;">缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public UserPermissionsCache userPermsCache;     //</span>
				<span style="font-family: 宋体;">用户权限缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public DatabaseCacheManager(DbForumFactory factory) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        …</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        forumCache = </span>
		</p>
		<p class="5">
				<span lang="EN-IE">            new ForumCache(new LongCache(forumCacheSize, 6*HOUR), factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        threadCache = </span>
		</p>
		<p class="5">
				<span lang="EN-IE">            new ForumThreadCache(</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  new LongCache(threadCacheSize, 6*HOUR), factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        messageCache = new ForumMessageCache(</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  new LongCache(messageCacheSize, 6*HOUR), factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        userCache = new UserCache(</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  new LongCache(userCacheSize, 6*HOUR), factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        groupCache = new GroupCache(</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                  new LongCache(groupCacheSize, 6*HOUR), factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        userPermsCache = new UserPermissionsCache(</span>
		</p>
		<p class="5">
				<span lang="EN-IE">                new UserPermsCache(userPermCacheSize, 24*HOUR), factory</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        );</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    …</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">从以上代码看出，</span>
				<span lang="EN-IE">ForumCache</span>
				<span style="font-family: 宋体;">等对象生成都是以</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">为基础构建的，以</span>
				<span lang="EN-IE">ForumCache</span>
				<span style="font-family: 宋体;">为例，代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public class ForumCache extends DatabaseCache {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">以</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">构建</span>
				<span lang="EN-IE">ID</span>
				<span style="font-family: 宋体;">缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected Cache forumIDCache = new Cache(128*1024, 6*JiveGlobals.HOUR);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">以</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">构建整个对象缓存</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public ForumCache(LongCache cache, DbForumFactory forumFactory) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        super(cache, forumFactory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public DbForum get(long forumID) throws ForumNotFoundException {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        …</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        DbForum forum = (DbForum)cache.get(forumID);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (forum == null) {    //</span>
				<span style="font-family: 宋体;">如果缓存没有从数据库中获取</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            forum = new DbForum(forumID, factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            cache.add(forumID, forum); </span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return forum;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">public Forum get(String name) throws ForumNotFoundException {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">         //</span>
				<span style="font-family: 宋体;">以</span>
				<span lang="EN-IE">name</span>
				<span style="font-family: 宋体;">为</span>
				<span lang="EN-IE">key</span>
				<span style="font-family: 宋体;">，从</span>
				<span lang="EN-IE">forumIDCache</span>
				<span style="font-family: 宋体;">中获取</span>
				<span lang="EN-IE">ID</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> CacheableLong forumIDLong = (CacheableLong)forumIDCache.get(name);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (forumIDLong == null) { //</span>
				<span style="font-family: 宋体;">如果缓存没有</span>
				<span style="font-family: 宋体;">从数据库获得</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            long forumID = factory.getForumID(name);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            forumIDLong = new CacheableLong(forumID); //</span>
				<span style="font-family: 宋体;">生成一个缓存对象</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            forumIDCache.add(name, forumIDLong);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return get(forumIDLong.getLong());</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    …</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">由此可以看到，</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">封装了</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">的核心功能，而</span>
				<span lang="EN-IE">ForumCache</span>
				<span style="font-family: 宋体;">等类则是在</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">核心外又包装了与应用系统相关的操作，这有点类似装饰（</span>
				<span lang="EN-IE">Decorator</span>
				<span style="font-family: 宋体;">）模式。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">从中也可以看到</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">两种缓存的用法。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">使用</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">时的关键字</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">是任何字段。如上面代码中的</span>
				<span lang="EN-IE">String name</span>
				<span style="font-family: 宋体;">，如果用户大量帖子主题查询中，</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">query + blockID</span>
				<span style="font-family: 宋体;">，见</span>
				<span lang="EN-IE">DbForum</span>
				<span style="font-family: 宋体;">中的</span>
				<span lang="EN-IE">getThreadBlock</span>
				<span style="font-family: 宋体;">方法；而值</span>
				<span lang="EN-IE">Value</span>
				<span style="font-family: 宋体;">则是</span>
				<span lang="EN-IE">Long</span>
				<span style="font-family: 宋体;">类型的</span>
				<span lang="EN-IE">ID</span>
				<span style="font-family: 宋体;">，如</span>
				<span lang="EN-IE">ForumID</span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">ThreadID</span>
				<span style="font-family: 宋体;">等。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">LongCache</span>
				<span style="font-family: 宋体;">的关键字</span>
				<span lang="EN-IE">Key</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">Long</span>
				<span style="font-family: 宋体;">类型的</span>
				<span lang="EN-IE">ID</span>
				<span style="font-family: 宋体;">，如</span>
				<span lang="EN-IE">ForumID</span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">ThreadID</span>
				<span style="font-family: 宋体;">等；而值</span>
				<span lang="EN-IE">Value</span>
				<span style="font-family: 宋体;">则是</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">或</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">等主要具体对象。</span>
		</p>
		<p class="MsoNormal" style="text-indent: 21.75pt;">
				<span style="font-family: 宋体;">在实际使用中，大多数是根据</span>
				<span lang="EN-IE">ID</span>
				<span style="font-family: 宋体;">获得对象。但有时并不是这样，因此根据应用区分了两种</span>
				<span lang="EN-IE">Cache</span>
				<span style="font-family: 宋体;">，这其实类似数据库的数据表，除了主关键字外还有其他关键字。</span>
		</p>
		<h3>
				<a name="_Toc60649960">
				</a>
				<a name="_Toc55117347">
				</a>
				<a name="_Toc55116003">
				</a>
				<a name="_Toc53800157">
						<span lang="EN-US">4.3  </span>
				</a>
				<span style="font-family: 黑体;">小结</span>
		</h3>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">缓存中对象是原对象的映射，如何确保缓存中对象和原对象的一致性？即当原对象发生变化时，缓存中的对象也必须立即更新。这是缓存机制需要解决的另外一个基本技术问题。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中是在原对象发生变化时，立即进行清除缓存中对象，如</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">对象的创建。在</span>
				<span lang="EN-IE">DbForumThread</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">AddMessage</span>
				<span style="font-family: 宋体;">方法中有下列语句：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">factory.cacheManager.threadCache.remove(this.id);</span>
		</p>
		<p class="60" style="margin: 0cm 0cm 6pt;">
				<span lang="EN-IE">factory.cacheManager.forumCache.remove(this.forumID);</span>
		</p>
		<p class="MsoNormal" style="text-indent: 21.75pt;">
				<span style="font-family: 宋体;">即当有新的帖子加入时，将</span>
				<span lang="EN-IE">ForumThreadCache</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">ForumCache</span>
				<span style="font-family: 宋体;">相关缓冲全部清除。这样，当有相关对象读取时，将直接从数据库中读取，这是一种非常简单的缓存更新方式。</span>
		</p>
		<p class="MsoNormal" style="text-indent: 21.75pt;">
				<span style="font-family: 宋体;">在复杂的系统，例如有一台以上的服务器运行着</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统。如果一个用户登陆一台服务器后，通过这台服务器增加新帖。那么按照上述原理，只能更新本服务器</span>
				<span lang="EN-IE">JVM</span>
				<span style="font-family: 宋体;">中的缓存数据，而其他服务器则无从得知这种改变，这就需要一种分布式的缓存机制。</span>
		</p>
		<div>
				<table align="left" cellpadding="0" cellspacing="0" hspace="0" vspace="0" width="403">
						<tbody>
								<tr>
										<td style="padding: 0cm 9pt;" align="left" valign="top">
												<p class="a4">
														<span lang="EN-US">
																<img src="http://www.chinaitpower.com/A-A-B/Image/2005/07/23/image008.jpg" alt="" height="135" width="290" />
														</span>
												</p>
												<p class="a5">
														<span style="font-family: 宋体;">图</span>
														<span lang="EN-US">3-7  Jive</span>
														<span style="font-family: 宋体;">主要对象的访问</span>
												</p>
										</td>
								</tr>
						</tbody>
				</table>
		</div>
		<p class="MsoNormal" style="text-indent: 21.75pt;">
				<span style="font-family: 宋体;">到目前可以发现</span>
				<span style="font-family: 宋体;">，</span>
				<span style="font-family: 宋体;">整个</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统其实是围绕</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">等这些主要对象展开的读取、修改或创建等操作。由于这些对象原先持久化保存在数据库中，为了提高性能和加强安全性，</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">在这些对象外面分别实现两层包装，如图</span>
				<span lang="EN-IE">3-7</span>
				<span style="font-family: 宋体;">所示。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">客户端如果需要访问这些对象，首先要经过它们的代理对象。进行访问权限的检查，然后再从缓存中获取该对象。只有缓存不存在时，才会从数据库中获取。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这套机制是大多数应用系统都面临的必须解决的基本功能，因此完全可以做成一个通用的可重复使用的框架。这样在具体应用时，不必每个应用系统都架设开发这样的机制。其实</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">就是这样一套框架，实体</span>
				<span lang="EN-IE">Bean</span>
				<span style="font-family: 宋体;">都由缓存机制支持，而通过设定</span>
				<span lang="EN-IE">ejb-jar.xml</span>
				<span style="font-family: 宋体;">可以实现访问权限控制，这些工作都直接由</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">容器实现了，不必在代码中自己来实现。剩余的工作是调整</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">容器的参数，使之适合应用系统的具体要求，这些将在以后章节中讨论。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，图</span>
				<span lang="EN-IE">3-7</span>
				<span style="font-family: 宋体;">的机制是通过不同方式实现的。基本上是一配二模式：一个对象有一个缓冲对象和一个代理对象，这样做的一个缺点是导致对象太多，系统变得复杂。这点在阅读</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">源码时可能已经发现。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果建立一个对象工厂，工厂内部封装了图</span>
				<span lang="EN-IE">3-7</span>
				<span style="font-family: 宋体;">机制实现过程，客户端可以根据不同的工厂输入参数获得具体不同的对象。这样也许代码结构要更加抽象和紧凑，</span>
				<span lang="EN-IE">Java</span>
				<span style="font-family: 宋体;">的动态代理</span>
				<span lang="EN-IE">API</span>
				<span style="font-family: 宋体;">也许是实现这个工厂的主要技术基础。有兴趣者可以进一步研究提炼。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66833.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:27 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66833.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(5)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66834.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:27:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66834.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66834.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66834.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66834.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 5  Jive								的其他组件技术								Jive				是一个比较丰富的知识宝藏，从中可以学习到很多新的实战技巧和具体功能实现方式。前面基本介绍了				Jive				中的一些主要架构技术，通过这些技术可以基本上掌握				Jive				论坛系统。								Jive				中还有很多非常实用的组件技术和工具库，分...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/08/31/66834.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/66834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:27 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(2)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66831.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:26:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66831.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66831.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66831.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66831.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66831.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 2  Jive								与设计模式								Jive				论坛系统使用大量设计模式巧妙地实现了一系列功能。因为设计模式的通用性和可理解性，将帮助更多人很快地理解				 Jive				论坛源码，从而可以依据一种“协定”来动态地扩展它。那么使用设计模式还有哪些好处？																												...&nbsp;&nbsp;<a href='http://www.blogjava.net/alex/archive/2006/08/31/66831.html'>阅读全文</a><img src ="http://www.blogjava.net/alex/aggbug/66831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:26 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(3)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66832.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:26:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66832.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66832.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66832.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66832.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66832.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="_Toc53800151">
						<span lang="EN-IE">3  Jive</span>
				</a>
				<span style="font-family: 楷体_GB2312;">安全管理机制</span>
		</h2>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中除了前面介绍的有关设计模式实现组件外，还有其他有一定特点的组件功能，分析研究这些组件功能可以更加完整透彻地理解</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛系统。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">安全管理机制基本是由下列部分组成：</span>
		</p>
		<p class="a0">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span style="font-family: 宋体;">安全验证机制。主要是验证用户名和密码组合是否与数据库中注册时的数据一致，以确认该用户身份为注册用户。这是对所有的</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">访问都进行拦截访问。</span>
		</p>
		<p class="a0">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span style="font-family: 宋体;">访问权限控制（</span>
				<span lang="EN-IE">ACL</span>
				<span style="font-family: 宋体;">）。对不同的数据不同用户拥有不同的访问权限，例如，一个帖子普通用户可以浏览，但是不能更该；但是管理员却可以编辑删除。这部分功能是通过代理模式实现，为每个关键数据都建立一个代理类用来实现访问权限检查，这在前面讨论过。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span style="font-family: 宋体;">用户资料管理系统。主要是管理用户的资料数据，进行用户组和用户关系的建立等。</span>
		</p>
		<h3>
				<a name="_Toc60649955">
				</a>
				<a name="_Toc55117342">
				</a>
				<a name="_Toc55115998">
				</a>
				<a name="_Toc53800152">
						<span lang="EN-US">1  </span>
				</a>
				<span style="font-family: 黑体;">安全验证机制</span>
		</h3>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的安全验证机制是按照比较通用的思路设计的。类似前面“简单的用户注册管理系统”中的介绍，</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">也是在所有的</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">页面中</span>
				<span lang="EN-IE">include</span>
				<span style="font-family: 宋体;">一个安全检验功能的</span>
				<span lang="EN-IE">global.jsp</span>
				<span style="font-family: 宋体;">。由于</span>
				<span lang="EN-IE">global.jsp</span>
				<span style="font-family: 宋体;">是在每个</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">一开始必须执行的功能，因此通过拦截</span>
				<span lang="EN-IE">global.jsp</span>
				<span style="font-family: 宋体;">拦截发往各个</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">页面的请求（</span>
				<span lang="EN-IE">request</span>
				<span style="font-family: 宋体;">）。如果这个请求是合法的，将被允许通过；如果不是，将注明请求者身份是</span>
				<span lang="EN-IE">Anonymous</span>
				<span style="font-family: 宋体;">（匿名者）。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">global.jsp</span>
				<span style="font-family: 宋体;">代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">boolean isGuest = false;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">Authorization authToken = SkinUtils.getUserAuthorization(request, response);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">if (authToken == null) {//</span>
				<span style="font-family: 宋体;">未被验证通过</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    authToken = AuthorizationFactory.getAnonymousAuthorization();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    isGuest=true;</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，以</span>
				<span lang="EN-IE">Authorization</span>
				<span style="font-family: 宋体;">对象作为验证通过的标志，它的接口代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public interface Authorization {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public long getUserID();    </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public boolean isAnonymous();</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">具体实现是</span>
				<span lang="EN-IE">DbAuthorization</span>
				<span style="font-family: 宋体;">，代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public final class DbAuthorization implements Authorization, Serializable {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    private long userID;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    protected DbAuthorization(long userID) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.userID = userID;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public long getUserID() {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return userID;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    public boolean isAnonymous() {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return userID == -1;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">此类只是一个</span>
				<span lang="EN-IE">userID</span>
				<span style="font-family: 宋体;">，因此只是一个象征性的标志。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">SkinUtils</span>
				<span style="font-family: 宋体;">是一个为</span>
				<span lang="EN-IE">JSP</span>
				<span style="font-family: 宋体;">服务的类，它的</span>
				<span lang="EN-IE">getUserAuthorization</span>
				<span style="font-family: 宋体;">代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public static Authorization getUserAuthorization</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        (HttpServletRequest request, HttpServletResponse response)</span>
		</p>
		<p class="5">
				<span lang="EN-IE">  {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    HttpSession session = request.getSession();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    // </span>
				<span style="font-family: 宋体;">从</span>
				<span lang="EN-IE">HttpSession</span>
				<span style="font-family: 宋体;">中获取</span>
				<span lang="EN-IE">Authorization</span>
				<span style="font-family: 宋体;">实例</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    Authorization authToken = </span>
		</p>
		<p class="5">
				<span lang="EN-IE">(Authorization)session.getAttribute(JIVE_AUTH_TOKEN);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    if (authToken != null) {     return authToken;  }</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    // </span>
				<span style="font-family: 宋体;">如果</span>
				<span lang="EN-IE">HttpSession</span>
				<span style="font-family: 宋体;">中没有，检查用户浏览器</span>
				<span lang="EN-IE">cookie </span>
		</p>
		<p class="5">
				<span lang="EN-IE">    Cookie cookie = getCookie(request, JIVE_AUTOLOGIN_COOKIE);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    if (cookie != null) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        try {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           String[] values = decodePasswordCookie(cookie.getValue());</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           String username = values[0];</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           String password = values[1];</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           //</span>
				<span style="font-family: 宋体;">从</span>
				<span lang="EN-IE">cookie</span>
				<span style="font-family: 宋体;">中获得用户名和密码后，进行安全验证</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           authToken = AuthorizationFactory.getAuthorization(username,password);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }catch (Exception e) {}</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // put that token in the user's session:</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        if (authToken != null) {//</span>
				<span style="font-family: 宋体;">如果通过验证，保存</span>
				<span lang="EN-IE">authToken</span>
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">http Session</span>
		</p>
		<p class="5">
				<span lang="EN-IE">           session.setAttribute(JIVE_AUTH_TOKEN, authToken);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">       // return the authorization token</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return authToken;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    return null;</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">用户验证预先通过两个步骤。首先检查</span>
				<span lang="EN-IE">HttpSession</span>
				<span style="font-family: 宋体;">中是否保存了该用户的验证信息，如果用户第一次验证通过，反复访问，这道关口检查就可以通过。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">如果</span>
				<span lang="EN-IE">HttpSession</span>
				<span style="font-family: 宋体;">中没有验证信息，那么从该用户的浏览器</span>
				<span lang="EN-IE">cookie</span>
				<span style="font-family: 宋体;">中寻找用户名和密码。如果该用户激活了</span>
				<span lang="EN-IE">cookie</span>
				<span style="font-family: 宋体;">保存这些登录信息，那么应该可以找到用户名和密码，这样就省却了用户再次从键盘输入用户名和密码，将用户名和密码通过下列语句进行数据库验证：</span>
		</p>
		<p class="60" style="margin: 3pt 0cm;">
				<span lang="EN-IE">authToken = AuthorizationFactory.getAuthorization(username,password);</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">这一举是验证关键。</span>
				<span lang="EN-IE">AuthorizationFactory</span>
				<span style="font-family: 宋体;">是一个抽象类，定义了</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">安全验证机制所需的所有方法，</span>
				<span lang="EN-IE">AuthorizationFactory</span>
				<span style="font-family: 宋体;">的实现类似前面讨论的</span>
				<span lang="EN-IE">ForumFactory</span>
				<span style="font-family: 宋体;">实现，是使用工厂模式加动态类反射机制完成的，代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public abstract class AuthorizationFactory {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">   //</span>
				<span style="font-family: 宋体;">定义一个数据库具体实现</span>
		</p>
		<p class="5">
				<span lang="EN-IE">    private static String className =</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        " com.Yasna.forum.database.DbAuthorizationFactory";</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> </span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    private static AuthorizationFactory factory = null;</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">验证方法</span>
				<span style="font-family: 宋体;">如果没有</span>
				<span lang="EN-IE">UnauthorizedException</span>
				<span style="font-family: 宋体;">抛出，表示验证通过</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    public static Authorization getAuthorization(String username,</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">            String password) throws UnauthorizedException</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    {</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">        loadAuthorizationFactory();</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">        return factory.createAuthorization(username, password);</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">匿名者处理方法</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    public static Authorization getAnonymousAuthorization() {</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">        loadAuthorizationFactory();</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">        return factory.createAnonymousAuthorization();</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">需要具体实现的抽象方法</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    protected abstract Authorization createAuthorization(String username,</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">            String password) throws UnauthorizedException;</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    protected abstract Authorization createAnonymousAuthorization();</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">动态配置</span>
				<span lang="EN-IE">AuthorizationFactory</span>
				<span style="font-family: 宋体;">的具体实现，可以在配置文件中定义一个</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    //</span>
				<span style="font-family: 宋体;">基于</span>
				<span lang="EN-IE">LDAP</span>
				<span style="font-family: 宋体;">的实现。类似</span>
				<span lang="EN-IE">ForumFactory</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">getInstance</span>
				<span style="font-family: 宋体;">方法</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    private static void loadAuthorizationFactory() {</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">        …</span>
		</p>
		<p class="5" style="line-height: 14.5pt;">
				<span lang="EN-IE">    }</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">AuthorizationFactory</span>
				<span style="font-family: 宋体;">看上去很复杂，实际只有一个核心方法</span>
				<span lang="EN-IE">getAuthorization</span>
				<span style="font-family: 宋体;">。实现用户名和密码的验证。如果无法通过验证，有两个信息实现显示：一个是抛出</span>
				<span lang="EN-IE">UnauthorizedException</span>
				<span style="font-family: 宋体;">，另外一个是返回空的</span>
				<span lang="EN-IE">Authorization</span>
				<span style="font-family: 宋体;">对象。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">那么，子类</span>
				<span lang="EN-IE">DbAuthorizationFactory</span>
				<span style="font-family: 宋体;">毫无疑问就是查询数据库，将输入的用户名和密码与数据库保存的用户名和密码进行校验。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">的安全验证机制比较简单易懂，值得在实践中学习借鉴。但是注意到这套安全验证机制只是</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">层的“手工”验证，资源访问权限（</span>
				<span lang="EN-IE">ACL</span>
				<span style="font-family: 宋体;">）也是自己“手工”来实现的。如果使用</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">技术，因为</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">容器本身有一定的资源访问控制体系，因此在</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">层验证通过后，需要将这些登录信息传递到</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">层。当然如果直接使用</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">容器的安全验证机制，那么</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">层与</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">层之间的登录信息传递将由容器实现，这样就更加简单方便。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">这种的安全验证并不是使用</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">容器的安全验证机制，如何使用</span>
				<span lang="EN-IE">Web</span>
				<span style="font-family: 宋体;">容器的安全验证机制将在以后章节介绍。尽管如此，</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">这套安全验证机制对付小型系统的应用也是足够的。</span>
		</p>
		<span style="font-size: 14pt; font-family: Arial;" lang="EN-US">
				<br style="page-break-before: always;" clear="all" />
		</span>
		<h3>
				<a name="_Toc55115999">
				</a>
				<a name="_Toc53800153">
				</a>
				<a name="_Toc60649956">
				</a>
				<a name="_Toc55117343">
						<span lang="EN-US">2  </span>
				</a>
				<span style="font-family: 黑体;">用户资料管理</span>
		</h3>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，用户</span>
				<span lang="EN-IE">User</span>
				<span style="font-family: 宋体;">对象的操作访问类似于论坛</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">对象的访问，与</span>
				<span lang="EN-IE">User</span>
				<span style="font-family: 宋体;">对象有关的操作都封装在一个类中操作，这是外观（</span>
				<span lang="EN-IE">Facade</span>
				<span style="font-family: 宋体;">）模式的应用。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，用户资料管理属于大系统中的一个子系统，在这个子系统中，用户子系统和其他系统又有一定的关系，涉及的类不少，通过建立一个</span>
				<span lang="EN-IE">UserManager</span>
				<span style="font-family: 宋体;">类来统一对外接口，使得整个子系统条目结构清晰。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">UserManager</span>
				<span style="font-family: 宋体;">中无外乎用户数据的管理，如用户的创建、修改、查询和删除。</span>
				<span lang="EN-IE">DbUserManager</span>
				<span style="font-family: 宋体;">是</span>
				<span lang="EN-IE">UserManager</span>
				<span style="font-family: 宋体;">的一个数据库实现，可是看看</span>
				<span lang="EN-IE">DbUserManager</span>
				<span style="font-family: 宋体;">中除了删除功能是直接通过</span>
				<span lang="EN-IE">SQL</span>
				<span style="font-family: 宋体;">语句进行数据库删除操作外，其他都委托给</span>
				<span lang="EN-IE">User</span>
				<span style="font-family: 宋体;">的具体实现</span>
				<span lang="EN-IE">DbUser</span>
				<span style="font-family: 宋体;">实现的。这种实现非常类似于</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">中</span>
				<span lang="EN-IE">Session Bean</span>
				<span style="font-family: 宋体;">和实体</span>
				<span lang="EN-IE">Bean</span>
				<span style="font-family: 宋体;">之间的关系。以创建用户资料为例，代码如下：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">public User createUser(String username, String password, String email)</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            throws UserAlreadyExistsException</span>
		</p>
		<p class="5">
				<span lang="EN-IE"> {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        User newUser = null;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        try {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            //</span>
				<span style="font-family: 宋体;">以</span>
				<span lang="EN-IE">username</span>
				<span style="font-family: 宋体;">查询改用户是否存在</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            User existingUser = getUser(username);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            //</span>
				<span style="font-family: 宋体;">如果没有抛出</span>
				<span lang="EN-IE">UserNotFoundException</span>
				<span style="font-family: 宋体;">异常，表示该用户存在</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            //The user already exists since now exception, so:</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            throw new UserAlreadyExistsException();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        } catch (UserNotFoundException unfe) {</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            //</span>
				<span style="font-family: 宋体;">该用户不存在，创建一个新用户</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            newUser = new DbUser(username, password, email, factory);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        }</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        return newUser;</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">DbUser</span>
				<span style="font-family: 宋体;">的构造方法实际是用户资料的新增创建：</span>
		</p>
		<p class="60">
				<span lang="EN-IE">protected DbUser(String username, String password, String email,</span>
		</p>
		<p class="5">
				<span lang="EN-IE">            DbForumFactory factory)</span>
		</p>
		<p class="5">
				<span lang="EN-IE">{</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.id = SequenceManager.nextID(JiveGlobals.USER);  //</span>
				<span style="font-family: 宋体;">获得自增</span>
				<span lang="EN-IE">ID</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.username = username;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        // Compute hash of password.</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.passwordHash = StringUtils.hash(password);  //</span>
				<span style="font-family: 宋体;">获得加密的密码</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.email = email;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        this.factory = factory;</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        long now = System.currentTimeMillis();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        creationDate = new java.util.Date(now);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        modifiedDate = new java.util.Date(now);</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        properties = new Hashtable();</span>
		</p>
		<p class="5">
				<span lang="EN-IE">        insertIntoDb();              //</span>
				<span style="font-family: 宋体;">数据库插入数据</span>
		</p>
		<p class="7">
				<span lang="EN-IE">}</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中，数据修改的保存是由</span>
				<span lang="EN-IE">DbUser</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">saveToDb</span>
				<span style="font-family: 宋体;">方法实现的，而</span>
				<span lang="EN-IE">saveToDb</span>
				<span style="font-family: 宋体;">方法调用是在每个</span>
				<span lang="EN-IE">setXXXX</span>
				<span style="font-family: 宋体;">方法中。即每当外界调用</span>
				<span lang="EN-IE">DbUser</span>
				<span style="font-family: 宋体;">的</span>
				<span lang="EN-IE">setXXXX</span>
				<span style="font-family: 宋体;">，则表示需要改变某些字段属性值，在这个方法中直接进行数据库存储，这也类似</span>
				<span lang="EN-IE">EJB</span>
				<span style="font-family: 宋体;">中</span>
				<span lang="EN-IE">CMP</span>
				<span style="font-family: 宋体;">实体</span>
				<span lang="EN-IE">Bean</span>
				<span style="font-family: 宋体;">的数据字段修改保存。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中组</span>
				<span lang="EN-IE">Group</span>
				<span style="font-family: 宋体;">与用户</span>
				<span lang="EN-IE">User</span>
				<span style="font-family: 宋体;">处理几乎差不多，只是在</span>
				<span lang="EN-IE">Group</span>
				<span style="font-family: 宋体;">中整合了权限方面的信息，这种做法是有一定的局限性，不是很值得借鉴，要想设计一个动态扩展灵活的权限系统，必须在用户或组与权限之间引入角色概念，也就是比较先进的基于角色的权限系统（</span>
				<span lang="EN-IE">RBAC Roled-Based Access Control</span>
				<span style="font-family: 宋体;">，相关网址：</span>
				<span lang="EN-IE">http://csrc.nist.gov/rbac/</span>
				<span style="font-family: 宋体;">）。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">RBAC</span>
				<span style="font-family: 宋体;">中，用户组只是用户的一个集合，应该是通过角色和权限发生联系。所以</span>
				<span lang="EN-IE">RBAC</span>
				<span style="font-family: 宋体;">认为，如果给用户组赋予权限，那么用户组也接近角色的概念。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66832.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:26 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66832.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]Jive论坛系统完整分析(1)</title><link>http://www.blogjava.net/alex/archive/2006/08/31/66830.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 31 Aug 2006 04:25:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/31/66830.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/66830.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/31/66830.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/66830.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/66830.html</trackback:ping><description><![CDATA[
		<h2>
				<a name="_Toc53800142">
						<span lang="EN-IE">1  Jive</span>
				</a>
				<span style="font-family: 楷体_GB2312;">功能需求</span>
		</h2>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">功能需求分析类似于一个新系统的需求分析。只有了解</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">系统实现了哪些论坛功能，才能进一步研究和学习它是怎样巧妙、优雅地实现这些功能的。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">论坛系统是网络交流的一种主要互动功能系统，如图</span>
				<span lang="EN-IE">3-1</span>
				<span style="font-family: 宋体;">所示。通过论坛系统，用户可以共同就某个话题不断进行讨论，通过发贴功能发布新的话题，通过回贴功能回复别人的话题。</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛系统可以允许管理员动态地创建新的论坛、编辑论坛的内容、设置论坛过滤信息以及管理注册用户等。</span>
		</p>
		<p class="a4">
				<span lang="EN-US">
						<img src="http://www.chinaitpower.com/A-A-B/Image/2005/07/23/image002.gif" alt="" height="230" width="422" />
				</span>
		</p>
		<p class="a5">
				<span style="font-family: 宋体;">图</span>
				<span lang="EN-US">3-1  Jive</span>
				<span style="font-family: 宋体;">用例图</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛系统中，用户角色和权限是紧密联系在一起的。主要分两大角色：普通用户和管理员，具体的表现形式是通过权限组合来体现的。管理方面的权限有：</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">SYSTEM_ADMIN</span>
				<span style="font-family: 宋体;">，系统管理员，可以管理整个系统。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span lang="EN-IE">FORUM_ADMIN</span>
				<span style="font-family: 宋体;">，论坛管理员，可以管理某个特定的论坛。</span>
		</p>
		<p class="22">
				<span style="font-family: Symbol;" lang="EN-IE">·<span style="font-family: 'Times New Roman'; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;">          </span></span>
				<span style="letter-spacing: -0.2pt;" lang="EN-IE">USER_ADMIN</span>
				<span style="font-family: 宋体; letter-spacing: -0.2pt;">和</span>
				<span style="letter-spacing: -0.2pt;" lang="EN-IE">GROUP_ADMIN</span>
				<span style="font-family: 宋体; letter-spacing: -0.2pt;">，用户和组管理员，可以管理一些特定用户和用户</span>
				<span style="font-family: 宋体;">组。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">论坛的读写权限包括：读权限，创建一个新主题，创建一个新的帖子等。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">中没有明确定义普通用户和管理员角色，而是直接通过以上权限组合和具体用户直接建立联系，并将这种直接联系保存到数据库中。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">在权限不是很复杂的情况下，这种没有引入角
色的做法比较简单直接。但由于用户和权限直接挂钩，而用户和权限都可能在不断地动态变化，那么它们之间由于联系太直接和紧密，对各自变化形成了限制。所
以，对于复杂的权限系统，引入了基于角色的权限系统，这将在以后章节中进一步讨论。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛业务对象主要分为</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">、</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">，它们之间的关系如图</span>
				<span lang="EN-IE">3-2</span>
				<span style="font-family: 宋体;">所示。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">每个论坛</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">包含一系列</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">（主题），而每个主题都是由很多内容帖子</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">组成的，这是一个聚集关系。这</span>
				<span lang="EN-IE">3</span>
				<span style="font-family: 宋体;">种对象中每一个对象都涉及到对象数据的创建、编辑、查询和删除，这些对象数据分别保存在数据库中。这</span>
				<span lang="EN-IE">3</span>
				<span style="font-family: 宋体;">个对象对于不同的角色可操作访问权限是不一样的，只有系统管理员和论坛管理员可以对</span>
				<span lang="EN-IE">Forum</span>
				<span style="font-family: 宋体;">相关数据实行操作，普通用户可以创建或编辑</span>
				<span lang="EN-IE">ForumThread</span>
				<span style="font-family: 宋体;">和</span>
				<span lang="EN-IE">ForumMessage</span>
				<span style="font-family: 宋体;">。</span>
		</p>
		<p class="MsoNormal">
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛为了实现不同用户对不同基本对象的不同操作权限，通过设定一个统一的入口，在这个入口将检查客户端每次对数据的操作权限，如图</span>
				<span lang="EN-IE">3-3</span>
				<span style="font-family: 宋体;">所示。</span>
		</p>
		<p class="a4">
				<span lang="EN-US">
						<img src="http://www.chinaitpower.com/A-A-B/Image/2005/07/23/image003.jpg" alt="" height="153" width="225" />   <img src="http://www.chinaitpower.com/A-A-B/Image/2005/07/23/image004.gif" alt="" height="139" width="258" /></span>
		</p>
		<p class="a5">
				<span style="font-family: 宋体;">图</span>
				<span lang="EN-US">3-2  </span>
				<span style="font-family: 宋体;">基本对象关系图</span>
				<span lang="EN-US">                            </span>
				<span style="font-family: 宋体;">图</span>
				<span lang="EN-US">3-3  </span>
				<span style="font-family: 宋体;">入口示意图</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">客户端每次对数据库的操作，都要经过</span>
				<span lang="EN-IE">ForumFactory</span>
				<span style="font-family: 宋体;">入口进入。在</span>
				<span lang="EN-IE">ForumFactory</span>
				<span style="font-family: 宋体;">中会动态生成一个访问控制代理</span>
				<span lang="EN-IE">ForumFactoryProxy</span>
				<span style="font-family: 宋体;">，通过</span>
				<span lang="EN-IE">ForumFactoryProxy</span>
				<span style="font-family: 宋体;">检查客户端访问方法是否符合整体权限访问控制要求。</span>
		</p>
		<p class="MsoNormal">
				<span style="font-family: 宋体;">下面将从</span>
				<span lang="EN-IE">ForumFactory</span>
				<span style="font-family: 宋体;">作为</span>
				<span lang="EN-IE">Jive</span>
				<span style="font-family: 宋体;">论坛系统分析入手，结合设计模式逐步分解论坛功能的具体实现。</span>
		</p>
<img src ="http://www.blogjava.net/alex/aggbug/66830.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-31 12:25 <a href="http://www.blogjava.net/alex/archive/2006/08/31/66830.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于java与javaScript的互相访问</title><link>http://www.blogjava.net/alex/archive/2006/08/21/64850.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Mon, 21 Aug 2006 10:02:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/21/64850.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/64850.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/21/64850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/64850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/64850.html</trackback:ping><description><![CDATA[key words: 脚本编码 中文乱码 js <br />在jsp中，通过js访问java代码比较容易(不过，也有缺陷，比如java代码的声明必须先于js),反过来则不方便,网上看到有通过其他组件的方式来做，感觉也不是很好，其实平时用的更多的是在js中有中文编码，而需要到下一个jsp页面中得到这个对应的值。<br /><br />js中有函数escape和unescape,可惜的是java.net.*中的编码和解码与js的不一致，所以他们不能协同工作，有一个方法就是在java中重新实现一遍js里对应的方法,代码如下:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br /> * java版本的escape和 unescape[对应javaScript里的函数]<br /> </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br /></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> EscapeUnescape {<br />    </span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br />     * escape ==&gt; escape<br />     * </span><span style="color: rgb(128, 128, 128);">@param</span><span style="color: rgb(0, 128, 0);"> src<br />     * </span><span style="color: rgb(128, 128, 128);">@return</span><span style="color: rgb(0, 128, 0);"> String<br />     </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> String escape(String src) {<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> i;<br />        </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> j;<br />        StringBuffer tmp </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> StringBuffer();<br />        tmp.ensureCapacity(src.length() </span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 0);">);<br />        </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> (i </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">; i </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> src.length(); i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">) {<br />            j </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> src.charAt(i);<br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (Character.isDigit(j) </span><span style="color: rgb(0, 0, 0);">||</span><span style="color: rgb(0, 0, 0);"> Character.isLowerCase(j)<br />                    </span><span style="color: rgb(0, 0, 0);">||</span><span style="color: rgb(0, 0, 0);"> Character.isUpperCase(j))<br />                tmp.append(j);<br />            </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (j </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">256</span><span style="color: rgb(0, 0, 0);">) {<br />                tmp.append(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (j </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">)<br />                    tmp.append(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />                tmp.append(Integer.toString(j, </span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">));<br />            } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />                tmp.append(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%u</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />                tmp.append(Integer.toString(j, </span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">));<br />            }<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> tmp.toString();<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">/**</span><span style="color: rgb(0, 128, 0);"><br />     * unescape ===&gt;js<br />     * </span><span style="color: rgb(128, 128, 128);">@param</span><span style="color: rgb(0, 128, 0);"> src<br />     * </span><span style="color: rgb(128, 128, 128);">@return</span><span style="color: rgb(0, 128, 0);"> String<br />     </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> String unescape(String src) {<br />        StringBuffer tmp </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> StringBuffer();<br />        tmp.ensureCapacity(src.length());<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> lastPos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">, pos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />        </span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);"> ch;<br />        </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> (lastPos </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> src.length()) {<br />            pos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> src.indexOf(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">%</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, lastPos);<br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (pos </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> lastPos) {<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (src.charAt(pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">u</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">) {<br />                    ch </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">) Integer.parseInt(src.substring(pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">, pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 0);">), </span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">);<br />                    tmp.append(ch);<br />                    lastPos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">6</span><span style="color: rgb(0, 0, 0);">;<br />                } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />                    ch </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 255);">char</span><span style="color: rgb(0, 0, 0);">) Integer.parseInt(src.substring(pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">, pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">), </span><span style="color: rgb(0, 0, 0);">16</span><span style="color: rgb(0, 0, 0);">);<br />                    tmp.append(ch);<br />                    lastPos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> pos </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">;<br />                }<br />            } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (pos </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) {<br />                    tmp.append(src.substring(lastPos));<br />                    lastPos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> src.length();<br />                } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />                    tmp.append(src.substring(lastPos, pos));<br />                    lastPos </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> pos;<br />                }<br />            }<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> tmp.toString();<br />    }<br />}</span></div><br /><br /><img src ="http://www.blogjava.net/alex/aggbug/64850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-21 18:02 <a href="http://www.blogjava.net/alex/archive/2006/08/21/64850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZT]与Java相关的四十个名字</title><link>http://www.blogjava.net/alex/archive/2006/08/13/63361.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sun, 13 Aug 2006 13:35:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/13/63361.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/63361.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/13/63361.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/63361.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/63361.html</trackback:ping><description><![CDATA[
		<span class="postbody">十大事件
<br /><br />
1990－1994：Java缘起
<br />
文/孟岩
<br /><br />
Larry Wall说，优秀程序员应有的三个特点:懒惰、急躁和傲慢。Java就是诞生在一群懒惰、急躁而傲慢的程序天才之中。
<br />
1990年12月，Sun的工程师Patrick Naughton被当时糟糕的Sun
C++工具折磨的快疯了。他大声抱怨，并威胁要离开Sun转投当时在Steve
Jobs领导之下的NeXT公司。领导层为了留住他，给他一个机会，启动了一个叫做Stealth（秘密行动）的项目。随着James
Gosling等人的加入，这个项目更名为Green。其目标是使用C++为嵌入式设备开发一种新的基础平台技术，James
Gosling本人负责开发一个SGML编辑器。正如人们事后分析的那样，这位天才的程序员太懒惰，所以没有把C++学好，开发中碰了一头包;太急躁——
所以不愿意停下来读读Scott Meyers的新书《Effective
C++》;太傲慢——所以轻易地决定开发一中新的编程语言。他把这种语言命名为C++++--，意思是C++“加上一些好东西，减去一些坏东西”。显然这
个糟糕的名字不可能长命百岁，很快这种颇受同伴喜爱的小语言被命名为Oak。
<br />到了1992年9月，Oak语言连同Green OS和一些应用程序一起发布在称做Start
7的小设备上，从而使之有了第一次精彩的亮相。随后，Sun开了一家名为FirstPerson的公司，整个团队被转移到这家公司里研发机顶盒，以投标时
代华纳公司的一个项目。这帮天才被技术狂热所鼓舞，开发出了一个高交互性的设备，结果没想到时代华纳公司和有线电视服务商并不愿意用户拥有那么大的控制
权，从而在竞标之战中败给了SGI。Oak的锋芒之锐，竟然把客户都给吓懵了。Sun沮丧地关闭了FirstPerson，召回了整个团队。事实证明，传
统行业中那些脑满肥肠的保守主义者是腐朽没落的。回去！回到激情澎湃的IT产业，抓住互联网的大潮，这才是出路！1994年，Oak被命名为Java，针
对互联网的新一轮开发如火如荼，一切已经就绪，熔岩在地下奔流，火山即将喷发。
<br /><br /><br />
1995: Java香浓世界
<br />
文/马伟
<br /><br />1995年，Sun正式对外公布了Java，并且发布了JDK
1.0。这种外形酷似C++，却包含一颗Smalltalk般纯洁的面向对象之心的全新程序设计语言及其平台，几乎在一夜之间就成为软件产业的新宠儿。
Java当时仅仅被用来为网站制作一些动态应用,诸如动画图片之类，但这仍然引起了很多Web开发者们的注意，他们非常渴望有一种安全的语言，可以在静态
的HTML网页上制作动画图片。Sun最终把Java集成到NetScape浏览器。同时因为它具有“只写一次，随处运行”的特性，而引起了很多开发者的
注意，他们可以再也不用为了使程序能够在不同型号的硬件上运行而耗费大量的时间来编译代码了。
<br />当时的Web浏览器的出现也为Java的出现起到了很好的推动作用，通过Java和Web浏览器的结合，人们似乎看到了什么，有人甚至预言PC
将在一两年内退出历史的舞台，取而代之的是基于Java的浏览器应用程序，通过网络计算设备来进行应用。Java的出现为当时的软件产业带来了无限的遐
想。
<br /><br /><br />
1996：Java大跃进，盟主地位就此定
<br />
文/马伟
<br /><br />
SUN在1996年一开始首先成立了JavaSoft组织，并在1月23日正式发布自己的Java 1.0，作为20世纪业界出现的最重要的技术之一，Java引起了编程世界的革命。直到现在，Java仍然是互联网上最流行的语言。
<br />在Sun正式发布Java
1.0之后，Java这门新生的语言就拥有了自己的会议——JavaOne，这次会议初试啼音就吸引了600多名参与者。除了拥有这么多的积极参与者来进
行Java的开发之外，各大知名公司也纷纷向Sun申请Java的许可。一时间，NetScape、惠普、IBM、Oralce、Sybase甚至当时刚
推出Windows 95的微软都是Java的追随者。
<br />
Java的应用就像是世界上的顶级玩家们组成的一个公开联盟，告诉全世界我们大家就是都在用着Java。也正是因为如此，Java也找到了自己的归宿。现在的J2EE已经成为中大型企业级应用的标准，成为承接数据库和Web之间的一个重要桥梁。
<br />
当年Java的机会实在太多了，以至于很难知道到底该做什么。最终Java在应用服务器市场获得了难以取代的地位，也确定了J2EE的发展方向，并且仍将延续下去。
<br /><br /><br />
1997-2001:  微软与Sun的Java官司
<br />
文/孟岩
<br /><br />Java诞生的1995年，正是微软在软件产业地位达到巅峰的时代，Windows
95发布时的风光场面给人们留下的深刻印象至今难忘。尽管如此，作为最卓越的技术领袖，比尔?盖茨仍然敏锐地注意到Java。当他了解了Java的一些细
节之后，给予了这样的评价:“Java是很长时间以来最优秀的程序设计语言。”基于此，微软于1996年3月申请并获得了Java许可证。微软对于
Java的这一热情态度在当时大大提高了人们对Java的兴趣和信心，但也有不少人担心微软会依靠自己强大的影响力在标准之外另立标准，从而破坏Java
的纯洁性。
<br />果然，从1997年发布Visual
J++的第一个版本开始，微软就开始在Java中掺入自己的私有扩展。这毫无疑问引起Sun的高度重视。1997年10月，Sun向美国加州地方法院起诉
微软公司违反两公司就微软使用Java技术所签定的合同，指控微软公司在自己的Java产品中做了“不恰当的修改”，违反了合同中承诺向用户提供Java
兼容产品的条款。这一官司旷日持久，直到2001年1月双方达成和解，微软将继续提供采用Sun开发的Java技术的现有产品（包括测试版）。不过，
Sun有限制地仅对包括Java 1.1.4的微软产品提供许可。到了2001年7月，微软公布新版的Windows
XP将不再支持Sun的JVM，并且推出了.NET平台与Java分庭抗礼。
<br />
现在回过头去看，当时的这一场官司对Java世界产生了深远的影响。如果没有这一场官司，也许很多Java程序员都在使用Visual J++，基于WFC开发Windows客户端程序，同时不得不面对被两个不同的事实标准所分裂的Java世界。
<br /><br /><br />
1998：Java 2平台发布
<br />
文/陶文
<br /><br />1998年，Java
2平台正式发布。经过了三年时间的发展、热热闹闹的攻关宣传、红红火火的众厂商的热情参与，Sun终于知道Java适合干什么了。对比Java刚发明时的
技术定位，与Java的戏剧性触“网”的那段历史，Java 2平台的发布可真算得上是有的放矢了。根据官方的文档，Java
2是Sun意识到“one size doesn’t fit
all”之后，把最初的Java技术打包成三个版本的产物，也就是著名的J2ME、J2SE、J2EE。
<br />之所以说Java自从Java
2平台发布之后，进入了现代。那是因为之前的历史怎么看来都和现在程序员日常开发使用的技术无什么关系，比如Applet，已经很少有人使用了。Java
2之后的历史就不一样了，至少人们在推崇轻量级开发，猛批EJB时还不时会引用J2EE这个词是如何诞生的。而Java
2的三大版本中，除了J2EE得到了长足发展和广泛使用之外，J2ME也在手机市场上取得了遍地开花的结果。相较之下，J2SE难免落寞，只剩SWT这个
血统不纯的家伙在Rich Client回归的时代吸引着人们的眼球了。无论今天看来当时的Java
2有多么的不成熟，至少经过市场和时间的检验，Java 2规划出来的三大方向把Java技术指向了光明的方向是勿庸置疑的。
<br /><br /><br />
1998：JCP成立并正式运作，
<br />
Java开源社群开始蓬勃发展
<br />
文/黄海波
<br /><br />1998年，JCP组织成立，并且开始把握Java的发展方向。JCP组织的开放性，不但使得所有对Java感兴趣的商业公司可以参与Java的
发展，更重要的是JCP允许个人、非盈利组织、学校等加入，这就给Java带来了巨大的活力。随之兴起的Java开源运动的最大贡献是实现和鼓励了知识共
享，在众多热情的开源程序员们的努力和分享下，很多原先只被商业公司掌握的技术、思想和产品可以被所有需要的开发人员免费或者以较低的价格获得使用权,
并通过开放源代码更容易的获得反馈和改进意见从而进一步演化发展。我们知道，所谓知识不是孤立发展认知，而是人们的经验，认识是思考交流和积累的产物。而
开源运动所带来的开放、反馈、交流的风气正是符合人类社会知识形成和发展的规律。
<br />开源运动起源于西方的发达国家，有其现实背景和文化根源。1990年代可以说是IT产业的一个黄金时代。信息时代的兴起对IT人员，特别是软件
人员有着巨大的需求。而软件开发又是一种类似艺术创作的脑力活动，和所有的艺术家、作家们一样，在作品打上自己的印记并流传在世界上是每一个创作人员的梦
想。互联网时代下的高收入的舒适生活，早九晚五的编写公司的代码并不能满足很多有激情的软件开发人员的梦想，再加上西方传统的基督教文化中十分推崇的分享
和交流，开源的出现和兴起也就水到渠成了。今天，开源运动已经不仅仅是一些个人天才程序员们的游乐园地，而是发展成为一项开源软件产业。
<br /><br /><br />
1998：WebLogic打开J2EE的魔匣
<br />
文/霍泰稳
<br /><br />Java语言的出现使得互联网络有了良好的交互性能，但这些很“酷”的技术仅被人们认为是一些小花招，它还无法消除企业级用户对它的怀疑。
1998年，BEA公司宣布收购WebLogic公司，并接着推出由Sun公司第一个授权使用J2EE许可证的WebLogic
Server应用服务器，这个Java版的AppServer一推出就引起业界极大的兴趣。WebLoigc
Server以其对标准的支持、强悍的运算能力和安全的架构设计等特性也很快征服了那些怀疑J2EE应用的人们。推出市场后不到一年，WebLogic
Server就成为业内第一Java应用服务器。
<br />这里我们援引一些当时著名咨询公司的调查数据来说明问题，“在IDC的报告中，BEA在应用服务器和交易服务器领域市场份额第一；在
Gartner的报告中，BEA WebLogic Server拥有业内最广泛的EJB应用安装基础；在Giga Group的报告中，BEA
WebLogic Server市场份额占32%”。
<br />因为应用服务器市场极大的发展潜力，在WebLogic
Server之后，其它的很多公司也推出了自己的AppServer，如IBM的WebSphere、Sun公司的iPlanet等，逐渐地应用服务器取
代了传统意义上的各类中间件，成为企业应用的基础平台。应用服务器的出现使得Java有了真正意义上的发展。
<br /><br /><br />
2002-2004: Sun与微软的法律碰撞最终以喜剧收场
<br />
文/恶魔
<br /><br />
2003年4月2 日，Sun与微软达成16亿美元的法律和解。如果不是晚了一天，许多人会以为这是一个在4月1日愚人节开的玩笑。尽管当时所有人都像是看到“太阳从西边出来了”那样张大了嘴巴，但这的确是事实。
<br />
根据两家公司达成的版权协议，双方会为采用对方的技术而支付专利费用，微软向Sun提前支付3.5亿美元使用费，Sun则承诺，如果Sun集成微软的某些技术，也会向微软付款。
<br />毫无疑问，“私下了结”的方式对双方而言都是最好的结果。就在协议签署的当天，在美国旧金山由Sun和微软为“抛弃十年恩怨、携手合作“举行的新
闻发布会上，尽管比尔?盖茨没有到场，但这并没有防碍现场看起来异常轻松的气氛。麦克尼利和鲍尔默各自穿了一件密歇根州底特律“Red
Wings”曲棍球队的运动服，并谈及了一起在哈佛大学读书的经历，麦克尼利还说:“当时我们两人是非常要好的朋友，当然我们也有吵架的时候。”人与人当
然可能成为终生的知己，但是公司与公司之间有的只能是利益上的分分合合。
<br /><br /><br />
2000-2004: JBoss和Eclipse
<br />
——Java开源软件的王者
<br />
文/莫映
<br /><br />Java和开源几乎就是天生的一对，这可以从无比兴盛繁荣的Java开源软件社区得到佐证。目前最有影响力的Java开源软件项目，要数
JBoss和Eclipse。可以说，几乎所有的Java开发人员都获多或少的听到过或接触和使用过它们。前者是目前最优秀、应用最为广泛的企业级开源
J2EE应用服务器，后者是功能完全可以替代商业产品的Java
IDE。二者的覆盖功能之全、支持工具之广、子项目之多，几乎可以仅凭借它俩来完成企业应用的开发构建到部署实施的全过程，而软件开发者和客户也都可以最
大程度上享受高质量，高可靠Java开源软件所带来的低成本优势。
<br />JBoss和Eclipse的巨大成功，几乎令各自领域的商用竞争者抓狂，其中BEA的WebLogic和IBM的WebSphere在商业利
润上受到JBoss的巨大侵蚀，而Borland的JBuilder、JetBrains的IDEA等诸多优秀的商用开发工具也不得不面对Eclipse
独大的现实。JBoss的CEO兼创始人 Marc
Fleury曾直言不讳地表示，希望占据市场主导地位。“我们希望打败IBM，成为中间件领域里最大的厂商。”JBoss在4.0以前还只是以一个
Group存在，盈利手段主要靠服务和销售文档。但在最近，JBoss已经发展成为一个有限公司，并吸纳多家风险投资，专注于获取利润为目标之一的第二代
开源软件模式（JBoss自己称为“Professional Open
Source”）的创新和运营。这区别于以理论研究为爱好的学院型开源或大公司为基础的非盈利组织开源，如Linux和Apache。当然JBoss的这
种运营方式势必会导致更多的代码控制和专有修改权，但按JBoss的说法是这样更能获得企业客户的信赖。JBoss的这种模式是否能获得成功还要我们拭目
以待。
<br />
不管JBoss和Eclipse的未来发展如何，JBoss和Eclipse的成功已经让我们看到了Java开源软件的威力，祝愿它们一路走好。
<br /><br /><br />
2004：Java 5.0
<br />
文/莫映
<br /><br />
2004年9月30日，代号为“Tiger”，研发历时近三年的J2SE 5.0发布正式版本，这是Java平台历来发布版本中改动面波及最大的一次。
<br />纵观Tiger，“Ease of
development”是其核心主题，这一点着重体现于语言特性上的改进，这在很大程度上，简化了开发人员日常的编程任务，以往一些琐碎的手工劳动都代
之以轻松自然，而又安全可靠的自动化实现。其中的注解功能，以及随之而来的声明式编程，还对构筑于J2SE 5.0之上的J2EE
5.0产生了巨大影响。尽管Tiger在语言特性上做了很大的动作，但作为Java技术的基础支撑，这些改动都是深思熟虑的结果。
<br />Tiger发布至今也有大半年了，那么Sun又是如何规划J2SE的未来蓝图的呢？据悉，J2SE的下两个版本分别是代号为“Mustang”
的J2SE 6.0和代号为“Dolphin”的J2SE
7.0，预计Mustang将于明年发布。在吸取了Tiger研发周期过长的教训之后，Sun副总裁Graham
Hamilton表示，Mustang的发布周期将不会那么长。并且，Sun还将“Becoming more open”
作为Mustang的主题之一。未来JCP对Java技术的影响将会愈加深入，而整个研发过程也将会愈加透明。Mustang在正式发布前的内部版本也会
陆续见诸于众，如此，广大Java开发者便可以更加及时的了解到Java发展的最新情况。在语言层面上的扩展依然会比较谨慎，比如像AOP这样的当下热门
技术，依然不太可能会见诸其中。据Hamilton所言，一个有可能被引入的语法特性被称作“friends”import机制，它将使由多个包组成的大
型项目变得易于管理。<br /><br />----------------------------------------------------------------------------------------<br /><br /><br /></span>
		<span class="postbody">十大人物
<br /><br />
James Gosling : Java之父
<br />
文/陶文
<br /><br />
作为Java之父，James
Gosling的名字可谓是耳熟能详。当人们评论一种编程语言时，总喜欢捎带着把下蛋的母鸡一起带上。Java做为中国的编程语言学习者餐桌上有限的那么
几样餐点中的流行款式，自然是让James Gosling风光不已。虽然James
Gosling现在已经不是领导Java发展潮流的领军人物了，做为Sun的开发者产品组的CTO，怎么算来也是身居高位了，俗事缠身吧，但是这并不妨碍
其对于Java一如既往的爱护，表达着各式各样鲜明的观点，引发一场又一场的争论。
<br />James Gosling是很爱Java的——是啊，哪有当父母的不爱自己的孩子的呢。James
Gosling也是很爱Sun的——是啊，哪有当领导的不爱自己的公司的呢。于是我们在批评.NET的安全性的队伍前头，在褒扬Java性能的队伍前头，
在抨击SWT开倒车的队伍前头，在给NetBeans大唱赞歌的队伍前头，我们都看到了James
Gosling的身影。无论对错、偏见或者固执，至少说明了Gosling的鲜明个性丝毫没有受到年龄的影响。也许也只有这种天才而偏执的人物才能创造出
Java这般伟大的语言来吧。
<br /><br /><br />
Bill Joy : 软件业的爱迪生
<br />
文/徐昊
<br /><br />Joy生于1954年，1982年与Vinod Khosla, Scott McNealy和Andy
Bechtolsheim一起创建了Sun
Microsystems，并从那时起担任首席科学家，直到2003年离开。他是一位令人崇敬的软件天才，他在软件和硬件的历史上留下了无数令人仰止的传
奇。
<br />在上个世纪80年代早期，DARPA与BBN达成协议，准备将Vinton Cerf和Bob
Kahn设计的TCP/IP协议添加到Berkeley UNIX中。Bill
Joy被委派来完成这项任务，然而他却拒绝将BBN的TCP/IP协议栈添加到BSD中，因为在他的眼中BBN的TCP/IP实现还远不够好，于是他就写
了一个高性能的TCP/IP协议栈。John
Gage回忆道，“BBN和DARPA签署了巨额合同来实现TCP/IP协议，然而他们的员工所编写的代码远没有一个研究生所做的好。于是他们邀请
Bill
Joy参加他们的一个会议，这位研究生穿着一件T-Shirt就出现了，他们询问他，‘你是如何做到的呢？’Bill回答说，‘这是非常简单的一件事，你
读一下协议然后就可以编码了’”。除了TCP/IP协议，基于分页的虚拟内存系统最早也是由Bill Joy添加到Berkeley
UNIX内核当中的。同时他还是vi、csh、早期Pascal编译器的作者。
<br />关于Bill
Joy惊人的软件才能流传最广的一个传奇是，据说他在上研究生的时候，想看看自己能不能写一个操作系统出来，于是就在三天里写了一个非常简陋，但是可以使
用的Unix系统, 传说就是BSD的前身。虽然如此夸张的才情令人难以置信，但是考虑到主角是Bill Joy，还是有一定的可信度的。Bill
Joy硕士毕业之后，决定到工业界发展，于是就到了当时只有一间办公室的Sun,
他作为主要设计者参与了SPARC微处理器的设计，负责设计最为关键的一部分电路。这样兼精软硬件的天才实在是让人不得不佩服啊。1995年，Sun发布
了轰动世界的Java语言。当然，Bill
Joy对Java也作出了不少的贡献，首先是JINI——一种针对分布式服务的基础连接技术。任何可以内嵌JVM的电子设备都可以通过JINI相互连接；
JXTA是基于Java的P2P协议，允许互联网上的软件进行点对点交流和协作。
<br />这个其貌不扬的瘦高个，有着凌乱的亚麻色头发，被《财富》杂志誉为“网络时代的爱迪生”的技术狂人，在短短的二十年间，创造了无数令人心动的软
件。在MIT的BBS上曾有一个帖子，说微软电话面试有一道题，问“Who do you think is the best coder, and
why?”虽然回复的帖子中大家都声明列举的best coder排名不分先后，然而大多数人仍把Bill
Joy列在第一位，或许可以从一个侧面验证Bill Joy在广大Programmer心目中的地位吧。
<br /><br /><br />
Joshua Bloch :  Java 2 元勋
<br />
文/莫映
<br /><br />早在1996年，适逢Java刚刚崭露头角，年内好事连连。先是1月份发布JDK
1.0，然后是5月底在旧金山召开首届JavaOne大会，年末又是JDK
1.1紧跟其后。正是在Java技术如火如荼、大展拳脚的背景之下，Joshua
Bloch来到了Sun，开始了他带领Java社区步入“迦南美地”的漫长历程。 <br />
很快，他被从安全组调入核心平台组，从事底层API设计。至此以后，每逢JDK的重大版本发布，总能在其中见到Joshua的“妙笔”。JDK
1.1中的java.math、1.4中的assertions，还有大家所熟识的Collections
Framework皆是Joshua一手打造。其中的Collections Framework还获得了当年的Jolt大奖。到了J2SE
5.0研发阶段，身为平台组构架师的Joshua接掌了Tiger大旗，其核心地位已然无人可以替代。作为Tiger的代言人和领路人，没有谁比
Joshua更清楚Tiger。相信大家一定还记得Joshua当年仿效英国诗人William
Blake所做的咏Tiger诗八首，优雅的笔调，透出大师深厚底蕴的同时，也道出了Tiger的几大重要特性，这些特性是自JDK
1.1引入Inner Class以来，Java最大的语法改进。
<br />Java风雨十年，从JDK 1.1到J2SE 5.0，Joshua实在功不可没。难怪有人戏言，假如将James
Gosling比作Java之父，那么Joshua就是一手将Java
“哺育”成人的Java之母。Joshua对Java的贡献还不止于JDK，提起他的大作《Effective Java》（Addison
Wesley, 2001），相信Java粉丝们一定耳熟能详。该书荣膺2002年度Jolt大奖，且备受James
Gosling推崇。书中57条颇具实用价值的经验规则，来自Joshua多年来在JDK开发工作中，尤其是Collections
Framework设计中的实践心得，各个有理有据，剖析深入，也足见其深厚功力。该书对Java社群的影响，犹如C++社群中的《Effective
C++》。Joshua对JCP的贡献也不小。他是JSR201和JSR175的领导者，前者包含了Tiger四大语言特性，后者则为Java提供了元数
据支持。此外，他还是JSR166的发起人之一（该JSR由Doug
Lea领导），并且是许多其他JSR的参与者。Joshua目前是JCP为数不多的几个执行委员会成员之一。
<br />Joshua
Bloch给人的印象是谦逊平和，行事低调而不喜抛头露面，一个典型的技术人员和实干家。不过即便如此，也丝毫不会减弱他对Java技术的卓越贡献和对
Java社区的绝对影响力。有人说，如果他能更彰显一些，就很有可能成为Java开发者中的领军人物，就有如Don Box之于微软社群。
<br />2004年7月初，就在Tiger发布在即之时，就在Jusha Bloch刚刚荣获Sun“杰出工程师（Distinguished
Engineer）”的称号之时，他突然离开Sun而去了正值发展态势迅猛的Google。当他离开Sun的消息在TSS发布之后，众多拥趸表达了怀念与
不舍之情。一年过去了，我们还没有获知Joshua的任何近闻，似乎又是他行事低调的一贯作风所致，不知他在Google状况如何。希望Joshua依然
能继续“摩西未尽的事业”，以他的影响力推动Java社群继续前行。据称，《Effective Java》的下一版会加入Java
5.0的部分，让我们翘首以待吧。
<br /><br /><br />
Bruce Eckel : 功勋卓著的机会主义分子
<br />
文/孟岩
<br /><br />Bruce
Eckel原本是一位普通的汇编程序员。不知道是什么因缘际会，他转行去写计算机技术图书，却在此大红大紫。他成功的秘诀不外乎两点：超人的表达能力和捕
捉机会的能力。他最早的一本书是1990年代初期的《C++ Inside &amp;
Out》，随后，在1995年他写出了改变自己命运的《Thinking in
C++》。如果说这本书充分表现了他作为优秀技术作家的一面，那么随后他写作《Thinking in
Java》并因此步入顶级技术作家行列，则体现了他作为优秀的机会主义分子善于捕捉机会的另一面。写作中擅长举浅显直接的小例子来说明问题，语言生动，娓
娓道来，特别适合于缺乏实践经验的初学者。因此《Thinking in
Java》俨然成为天字第一号的Java教科书，对Java的普及与发展发挥着不可忽略的作用。不过公允地说，Bruce
Eckel的书欠深刻。比如在“Thinking
in…”系列中对设计模式的解说就有失大师水准。这一方面是因为书的定位非常清晰，另一方面也是因为Bruce太过分心赶潮流，未能深入之故。TIJ之
后，他预言Python将火，就匆匆跑去写了半本《Thinking in
Python》。后来Python并未如期而旺，于是他也就把书稿撂在那里不过问了，机会主义的一面暴露无遗。我们也可以善意的猜测一下，他的下一个投机
对象会是什么呢？Ruby？.NET？MDA？总之，是什么我都不奇怪。
<br /><br /><br />
Rickard Oberg :J2EE奇才
<br />
文/熊节
<br /><br />Oberg的作品很多，流行的代码生成工具XDoclet和MVC框架WebWork都出自他的手笔。这两个框架有一个共同的特点，即它们的功能
虽然简单，但设计都非常优雅灵活，能够很方便地扩展新功能甚至移植到新环境下使用。优雅的设计源自Oberg的过人才华，简单的功能则折射出他玩世不恭的
人生态度。正是这两种特质的融合，才造就了这个不世出的奇才。
<br />1999年，JDK 1.3发布，其中带来了一个重要的新特性：动态代理（Dynamic
Proxy）。当所有人都还在对这项新技术的用途感到迷惑时，Oberg发现用它便可以轻松攻克EJB容器实现中的一些难关。这一发现的产物就是一本
《Mastering RMI》，以及大名鼎鼎的JBoss应用服务器。但Oberg很快又让世人见识了他的玩世不恭。由于和总经理Marc
Fleury在经营理念上不合，Oberg抱怨“法国的天空总让我感到压抑”，甩手离开了自己一手打造的JBoss。此后的几年里，他和老友Hani
Suleiman不断地对JBoss的“专业开源”模式和Marc Fleury的商人味道冷嘲热讽，让众人为他的孩子气扼腕叹息。
<br />2002年10月，微软推出Petstore示例应用的.NET版本，并宣称其性能比Java
Petstore高出数倍。正是Oberg深入分析这个示例应用的源代码，在第一时间指出它大量运用了SQL
Server专有的特性，性能对比根本不具参考价值。后来Oberg又先后关注了AOP和IoC容器，两者都成为了J2EE架构的新宠。
<br /><br /><br />
Doug Lea : 世界上对Java影响力最大的个人
<br />
文/KIT
<br /><br />
如果IT的历史，是以人为主体串接起来的话，那么肯定少不了Doug Lea。这个鼻梁挂着眼镜，留着德王威廉二世的胡子，脸上永远挂着谦逊腼腆笑容，服务于纽约州立大学Oswego分校计算器科学系的老大爷。
<br />说他是这个世界上对Java影响力最大的个人，一点也不为过。因为两次Java历史上的大变革，他都间接或直接的扮演了举足轻重的脚色。一次是由
JDK 1.1到JDK 1.2，JDK1.2很重要的一项新创举就是Collections，其Collection的概念可以说承袭自Doug
Lea于1995年发布的第一个被广泛应用的collections；一次是2004年所推出的Tiger。Tiger广纳了15项JSRs(Java
Specification
Requests)的语法及标准，其中一项便是JSR-166。JSR-166是来自于Doug编写的util.concurrent包。
<br />
值得一提的是: Doug Lea也是JCP (Java小区项目)中的一员。
<br />Doug是一个无私的人，他深知分享知识和分享苹果是不一样的，苹果会越分越少，而自己的知识并不会因为给了别人就减少了，知识的分享更能激荡出
不一样的火花。《Effective JAVA》这本Java经典之作的作者Joshua
Blosh便在书中特别感谢Doug是此书中许多构想的共鸣板，感谢Doug大方分享丰富而又宝贵的知识。这位并发编程的大师级人物的下一步，将会带给
Java怎样的冲击，不禁令人屏息以待。
<br /><br /><br />
Scott McNealy :SUN十年来的掌舵者
<br />
文/KIT
<br /><br />McNealy，Sun的CEO、总裁兼董事长。他曾经狂傲的说:“摧毁微软是我们每个人的任务。”这位英勇的硅谷英雄，似乎带头起义，试图组织
一个反微软阵线联盟，以对抗微软这股庞大的托拉斯恶势力。他时常口出惊人之语，在公开场合大肆的批评微软，并曾经说微软的.NET是.NOT。
<br />Scott
McNealy先后毕业于哈佛大学及史丹佛大学，分别持有经济学学士学位及企管硕士。1982年MBA毕业的他和三个同学共同合伙创建了Sun，并于
1984年成为Sun的执行官。“要么吞了别人，不然就被别人吞了”是Scott
McNealy的名言录之一。他擅长以信念带动员工，鼓舞士气。极富自信的他，对于认定的事，总是坚持自己的想法，因此有人形容他是一个刚愎自用的决策
者。
<br />身为Sun这艘船的掌舵者，Scott McNealy能够看多远，Sun就能走多远。Scott
McNealy认为将来软件界是一个只有服务，没有产品的世代。他希望打造出Sun不是一个纯靠硬件赚钱的公司。从Open Source到Open
Solaris，Sun希望可以成为提供整合性解决方案的服务厂商。Solaris 10 + UltraSPARC是否可以像Scott
McNealy希望的是下一匹世纪黑马呢？Sun是否能以股价来证明华尔街分析师及普罗大众的诽短流长？Scott
McNealy是否能带领着Sun成为继微软之后的下一个巨人，一场场IT界的争霸战值得我们拭目以待。
<br /><br /><br />
Rod Johnson : 用一本书改变了Java世界的人
<br />
文/ 刘铁锋
<br /><br />Rod在悉尼大学不仅获得了计算机学位，同时还获得了音乐学位。更令人吃惊的是在回到软件开发领域之前，他还获得了音乐学的博士学位。有着相当丰
富的C/C++技术背景的Rod早在1996年就开始了对Java服务器端技术的研究。他是一个在保险、电子商务和金融行业有着丰富经验的技术顾问，同时
也是JSR-154（Servlet 2.4）和JDO 2.0的规范专家、JCP的积极成员。
<br />真正引起了人们的注意的，是在2002年Rod Johnson根据多年经验撰写的《Expert One-on-One J2EE
Design and Development》。其中对正统J2EE架构的臃肿、低效的质疑，引发了人们对正统J2EE的反思。这本书也体现了Rod
Johnson对技术的态度，技术的选择应该基于实证或是自身的经验，而不是任何形式的偶像崇拜或者门户之见。正是这本书真正地改变了Java世界。基于
这本书的代码，Rod
Johnson创建了轻量级的容器Spring。Spring的出现，使得正统J2EE架构一统天下的局面被打破。基于Struts+Hibernate
+Spring的J2EE架构也逐渐得到人们的认可，甚至在大型的项目架构中也逐渐开始应用。
<br />Rod Johnson的新作《Expert One-on-one J2EE Development without
JEB》则更让人吃惊，单单“Without EJB”一词就会让大多数J2EE架构师大跌眼镜了。不过Rod
Johnson可能仅仅是想通过“Without EJB”一词表明应该放开门户之见。这也是Rod
Johnson一贯的作风，。也许正是这种思想，促使得Rod Johnson创建了Spring，真正改变了Java世界。
<br /><br /><br /><br />
Alan Kay :Java的精神先锋
<br />
文/徐昊
<br /><br />
Sun的官方Java教材中有一句话，说Java是“C++的语法与Smalltalk语义的结合”。而Smalltalk的创造者就是Alan Kay。
<br />Alan Kay于1970年加入Xerox公司的Palo Alto研究中心。早在70年代初期，Alan
Kay等人开发了世界上第二个面向对象语言Smalltalk，因此，Alan Kay被誉为Smalltalk之父。2003年，Alan
Key因为在面向对象程序设计上的杰出贡献，获得了有计算机界的诺贝尔奖之称的ACM Turing Award。
<br />Alan
Kay成名于Smapltalk和OOP，而Java虽然在语言上类似于C，但是在语义上非常接近Smalltalk，很多Java中的设计思想在
Alan Kay的文献中找到根源，也有些人将Alan Kay尊为Java思想的先驱。不过遗憾的是似乎Alan
Kay老先生对Java并不买账，反倒攻击说Java是存在致命缺陷的编程语言，Java的成功不是由于Java本身的内在价值，而是其商业化的成功。
Alan Kay欣赏的是Lisp，他认为Lisp是软件的麦克斯韦方程，其中的许多想法是软件工程和计算机科学的一部分。看来拥有Alan
Kay这样一位重量级的Java先驱仍是我们Java一厢情愿的单恋吧。
<br /><br /><br /><br />
Kent Beck : 领导的敏捷潮
<br />
文：刘铁锋
<br /><br />
Beck全家似乎都弥漫着技术的味道。生长在硅谷, 有着一个对无线电痴迷的祖父，以及一个电器工程师父亲。从小就引导Kent Beck成为了业余无线电爱好者。
<br />
在俄勒冈州大学读本科期间，Kent Beck就开始研究起模式。然而在他最终拿到计算机学位之前，他却是在计算机和音乐中交替学习。似乎Java大师都能够有这样的能耐，另一Java大牛Rod Johnson同样也拥有音乐学的博士学位。
<br />Kent Beck一直倡导软件开发的模式定义。早在1993年，他就和Grady
Booch（UML之父）发起了一个团队进行这个方面的研究。虽然著有了《Smalltalk Best Practice
Patterns》一书，但这可能并不是Kent
Beck最大的贡献。他于1996年在DaimlerChrysler启动的关于软件开发的项目，才真正地影响后来的软件开发。这次的杰作就是XP（极限
编程）的方法学。
<br />和软件开发大师Martin Fowler合著的《Planning Extreme
Programming》可谓是关于XP的奠基之作。从此，一系列的作品如《Test Driven Development: By
Example》，《Extreme Programming Explained: Embrace
Change》让更多的人领略到了极限编程的精髓，也逐步导致了极限编程的流行。
<br />
Kent Beck的贡献远不仅如此。对于众多的Java程序员来说，他和Erich Gamma共同打造的JUnit，意义更加重大。也许正式这个简单而又强大的工具，让众多的程序员更加认可和信赖极限编程，从而引起了Java敏捷开发的狂潮吧。<br /><br />------------------------------------------------------------------------------------------<br /><br /></span>
		<span class="postbody">十大产品
<br /><br />
Sun JDK :Java的基石
<br />
文/莫映
<br /><br />
众所周知，流传于市的JDK不单Sun一家，比如IBM的JDK、BEA的JRocket、GNU的GCJ，以及如Kaffe这样的开源实现，不一而足。但是，根正苗红的Sun官方JDK一直以来都是备受瞩目的主流，它对Java社区的影响也是举足轻重。
<br />
1996年1月，Sun在成立了JavaSoft部门之后，推出了JDK 1.0，这是Sun JDK（Java Development
Kit）的首个正式版本;当年12月，JDK1.1出炉。该版除了对前序版本部分特性做了改进以外，重写了AWT，采用了新的事件模型。1998年12
月，JDK
1.2正式发布。此时的类库日臻完善，API已从当初的200个类发展到了1600个类。在1.2版本中引入了用100%纯Java代码写就的
Swing，同时，Sun将Java更名为Java 2。
<br />1999年，Java 技术形成了J2SE、J2EE和J2ME三大格局。Sun向世人公布了Java
HotSpot性能引擎技术的研究成果。HotSpot旨在进一步改善JVM性能，提高Java
ByteCode的产生品质，加快Java应用程序的执行速度。J2SE 1.3发布于2000年；2002年2月间，J2SE
1.4问世，这是有JCP参与以来首个J2SE的发行版本。2004年9月30日，代号为“Tiger”的J2SE
5.0终于出笼了，这次发布被誉为Java平台历来发布中特性变动最大的一次。包括泛型在内的若干重大语法改进、元数据支持，包括多线程、JDBC在内的
多项类库改进，都令广大Java程序员激动不已。自此，Sun的官方JDK（J2SE Development Kit）已经步入了一个新的高度。
<br /><br /><br /><br />
Eclipse :以架构赢天下
<br />
文/恶魔
<br /><br />
IBM是在2001年以4000万美元种子基金成立Eclipse联盟，并且捐赠了不少程序代码。如今，该组织有91个会员，包含许多全球最大的软件商。根据Evans Data公司的资料，Eclipse是目前最受欢迎的Java开发工具。 
<br />
Java厂商若要共同对抗微软，彼此之间就要有共同的开发工具才行。 
<br />在Eclipse平台上，程序员可使用好几种不同的语言。在前端方面，用户可整合多种工具来撰写Plug-in程序或Unit
Test。Eclipse最大的特色就在于其完全开放的体系结构，这代表任何人都可下载并修改程序代码，给Eclipse写插件，让它做任何你能想到的事
情，即所谓“Design for everything but nothing in particular”。
<br />
Eclipse基金会的架构比较特别，反映出企业现今对于开放原始码计划也越来越积极主动。Eclipse不像一般开放源码软件容许个人的捐献程序，该基金会是由厂商主导。不论是董事会成员或者是程序赞助者几乎都来自于独立软件开发商(ISVs)的员工。 
<br />Eclipse首席执行官Mike
Milinkovich说，这种厂商会员制是特意设计的；他说Eclispe软件开发快速就是因为会员制的关系，同时又加上开放源码开发模式的临门一脚。
这与一般透过标准组织的做法全然不同。 这其实正好验证了一句老话:“开放即标准”。
<br /><br /><br />
JUnit/Ant : 让Java自动化的绝代双骄
<br />
文/刘铁锋
<br /><br />
在Java程序员必备的工具中，共 同拥有且交口称赞的恐怕就非JUnit、Ant莫属了。一个是单元测试的神兵利器，一个是编译部署的不二之选，它们让Java的开发更简单。
<br />JUnit由XP和TDD的创始人、软件大师Kent Back以及Eclipse架构师之一、设计模式之父Erich
Gamma共同打造。名家的手笔和理念使得JUnit简单而强大，它将Java程序员代入了测试驱动开发的时代。JUnit连任了2001、2002年
“Java World编辑选择奖”以及2003年“Java World最佳测试工具”和2003年“Java
Pro最佳Java测试工具”等众多奖项，深受Java程序员好评。
<br />Ant是开源项目的典范，它让IDE的功能更加强大，从Sun的NetBeans到JBuilder,主流的IDE中处处都有它的身影。
“Another Neat
Tool”原是它的本名，但这已经渐渐不为人知。它彻底地让部署自动化，而程序员需要做的仅仅是几条简单的配置命令。和JUnit一样，Ant也荣获了众
多的殊荣:2003年JavaWorld“最有用的Java社区开发的技术编辑选择奖”, 2003年Java
Pro“最有价值的Java部署技术读者选择奖”，2003年“JDJ编辑选择奖”，也让Ant受到的多方的认可。
<br />
Ant对JUnit的全面集成,则使得一切都变得更加完美。只需简单地配置，从自动测试到报告生成，从编译到打包部署均可自动完成。强大的功能，简单的配置，让Java程序员高枕无忧。实可谓让Java自动化的绝代双骄。
<br /><br />
Websphere : 活吞市场的大鲸
<br />
文/jini
<br /><br />1999年，
IBM与Novell签订合作协议，成功地提供电子商务的解决方案给予原先使用NetWare的用户。同年更是推出了WebSphere
Application Server 3.0，并且推出WebSphere Studio与VisualAge for
Java让工程师可以快速开发相关的程序。2001年，IBM更是宣布将应用服务器、开发工具整合在一起，与DB2、
Tivoli及Lotus结合成为一套共通解决方案，如今、IBM更是并入了Rational Rose ( UML tools
)让开发流程更是完整化。
<br />Sun在Web Services的策略方面远远落后于微软与IBM, 当他们手拉手在研订Web Services规范,
加上IBM买硬件送软件或是买WebSphere送DB2的策略让企业大佬们纷纷转向IBM的阵营,
Sun才惊觉大势已去。WebSphere复杂的安装，深奥的设定，难以理解的出错讯息不断地挑战开发者的耐心与毅力。
<br />IBM如今已经不是将WebSphere定义为单一产品，它已经是一个平台的代名词。它里面的产品目前包含了应用服务器、商业整合、电子商务、
数据讯息管理、网络串流、软件开发流程、系统管理、无线语音等等。非常多样化,也让企业界愿意相信WebSphere可以带给他们一套完整的解决方案。同
时, IBM也在推广SOA的概念, 简单来说, 利用Web Service的耦合性与工作流程的整合, 为企业内部打造以服务为导向的架构。
<br />
IBM捐献出Eclipse带给Java开发人员对IDE的重新掌握。未来是否会捐献出WebSphere的哪一个部分成为OpenSources, 或许, 又是改写Java世界的时刻了。
<br /><br /><br /><br />
WebLogic : 技术人的最爱
<br />
文/jini
<br /><br />1995年, BEA成立了, 初期以Tuxedo数据转换的产品为基础, 成长之迅速是历年来最强的企业。 1998年,
BEA推出以Java为基础的网络解决方案, 提供了完整的中间层架构, 更同时支持EJB 1.0 及微软的COM组件,
方便的管理接口掳掠了工程师的心。 在IBM和Oracle尚未准备好迎击的时候, BEA已经席卷企业应用平台的市场。
WebLogic无论在市场领先度与技术领导性与策略远观性都优于当年的所有应用服务器厂商。
<br />如今WebLogic不仅仅是应用平台服务器的名称, 而是BEA对于整个企业解决方案的总称, 无论是WebLogic
Portal或是WebLogic Integration配合着Workshop开发环境,
来自微软的UI开发团队让Workshop几乎达到所见即所得。 接着, 在下一个版本之中,
BEA的BeeHive开放源代码计划将释出中间层控件的开发模块, 并且与Eclipse合作共同打造新一代的开发环境。 如此强而有力的技术支持,
更是让顾客愿意使用WebLogic平台的最大原因。
<br />代号为“Diablo”的 WebLogic Server 9.0小恶魔已经出现了, 目前虽然仅仅是BETA版, 以Portlet
方式打造的管理接口与完整且美妙的WebServices支持, 实在很难找到可以挑剔的地方, 虽然去年被IBM的技术性推销超越了市场占有率,
不过接下来SOA的平台竞争现在才开始, BEA的LOGO也加入“Think liquid”并且推出新的AquaLogic平台做为数据服务平台,
可见, Java的应用服务器的战争, 还会继续进行着。
<br /><br /><br /><br />
JBuilder : Java开发工具的王者
<br />
文/刘铁锋
<br /><br />Java的开发工具中,最出名的莫过于Borland公司的JBuilder了。对于一些没有弄清楚开发工具与JDK的区别的Java入门者来
说，JBuilder就如同Visual
C++之于C++，以为JBuilder就是Java的全部。比起捆绑在服务器上销售的JDeveloper，JBuilder应该是唯一的仅靠自身的实
力而占领了大部分市场的Java商用开发工具了。而JBuilder作为Java
开发工具的王者，其夺冠之路并非一帆风顺。直到Java的天才Blake Stone成为JBuilder的Architect之后，JBuilder
2.0以及3.0才逐渐推出。2000年3月14日，JBuilder
3.5的推出别具意义，它成为了业界第一个用纯Java打造的开发工具，也风靡了整个Java开发工具市场。在同年11月份推出的JBuilder
4.0乘胜追击，冲破了50%的市场占有率，成为了真正Java开发工具的王者。
<br />Borland以每半年左右推出一个新版本的速度，让众多的对手倒在了沙场。而Microsoft因为与Sun的官司，也使得一个强大的对手退
出了战争。2001年，加入了对企业协作支持的JBuilder 5以及强化了团队开发工具的JBuilder 6打败了最后一个对手Visual
Age For Java。2002年JBuilder 7推出之后，再也没有其他厂商与JBuilder竞争。
<br />孤独的王者并没有停下脚步，在2003年到2005年间，JBuilder也仍然延续了其半年一个版本的速度，推出了8、9、10、2005四
个版本。强大的功能以及持续的改进，也让Java程序员多了一分对能够在开发工具市场上与Microsoft血拼十数年的Borland的敬仰。
<br /><br /><br /><br />
Oracle : Java人永远的情结
<br />
文/熊节
<br /><br />
在林林总总的数据库之中，有一种尤其令人又爱又恨、印象深刻，那就是关系型数据库市场的“大佬”——Oracle。
<br />从公司的角度，Oracle和Sun有着诸多相似之处，例如：两家公司都拥有一位个性鲜明的CEO。早在Java诞生之初的1995年，
Oracle就紧随NetScape从而第二个获得了Java许可证。从那以后，Oracle对Java的鼎力支持是Java能够在企业应用领域大获成功
的重要原因之一。
<br />所有J2EE程序员都知道，Oracle的JDBC驱动虽然与Oracle数据库配合良好，但在不少地方使用了专有特性。其中最为著名的就是
“CLOB/BLOB问题”，诸如此类的问题给开发者带来了很多麻烦。为了同时兼顾不同的数据库，他们不得不经常把自己的一个DAO（数据访问对象）写成
两份版本：针对Oracle的版本和针对其他数据库的版本。有不少人为了开发便利，舍弃了数据库之间的可移植性，将自己的产品绑定在Oracle的专有特
性上。
<br />Oracle提供的Java开发工具也与此大同小异。不管是数据库内置的Java支持还是JDeveloper IDE，
Oracle的Java工具都和Oracle数据库有着千丝万缕的联系。看起来，只要Oracle还是数据库市场上的“头牌”，了解、学习Oracle的
专有特性，周旋于Oracle特有的问题和解决方案之中，就将仍旧是J2EE程序员在数据库基础和SQL之外的必修功课。对Oracle的爱与恨，也将仍
旧是Java人心头一个难解的情结。
<br /><br /><br /><br />
Struts、Hibernate : 让官方框架相形失色的产品
<br />
文/刘铁锋
<br /><br />
好的框架能够让项目的开发和维护更加便捷和顺利。相比Sun官方标准的迟钝以及固执，开源框架也更得到Java程序员的共鸣。Struts以及Hibernate就是这样一类产品，它们简单、优雅，更让官方的产品相形失色。
<br />谈起Struts，不可避免地就要提及MVC（Model-View-Controller）的理念。而准确地讲，MVC的提出却最早源于JSP
的标准。在1998年10月7号，Sun发布的JSP的0.92的规范中提出的Model 2就是MVC的原型。在1999年12月Java
World的大会中，Gavind Seshadri的文章最早阐述了Model
2就是一种MVC的架构，同时也提及了MVC架构是一种最好的开发方法。2000年3月，由Craig
McClanahan发布的Struts成为了最早支持MVC的框架。Struts在设计上虽然存在一些诟病，但是不可否认的是，它使得Java
Web应用的开发更加简洁和清晰，也让更多的程序员爱上了Java，并开始遗忘官方的JSP。时至今日，比起如WebWork、Tapestry以及
Sun官方的JSF，Struts或多或少存在些不足，但是众多成功项目的实施，仍然使其牢牢占据的Java Web应用框架的首位。
<br />Hibernate则在某种程度上改变了人们对构建J2EE的思路。相比其EJB的Entity
Bean的映射技术，Hibernate则显得更加简洁和强大。五分钟就能把Hibernate跑起来，让更多的Java程序员享受到了开发的乐趣。第
15届Jolt大奖中，最优秀数据库、框架以及组件的奖项中，Hibernate当仁不让获得头筹；不仅如此，
Hibernate甚至还影响了官方的标准。在众多Java程序员翘首以待的EJB 3.0的规范中，Hibernate得到了支持。
<br />
Java开源的繁荣不仅让众多Java的开发者享受到了更多的便利，甚至影响了官方的标准。恐怕这也是作为Java人独有的乐趣之一吧。
<br /><br /><br /><br />
PetStore : J2EE人的必修课
<br />
文/陶文
<br /><br />很少有一个例子项目如PetStore这
般广为人知，而这很大程度上要归功于Sun很“英明”地把PetStore做成一个只展示架构而在性能调优上留下了大大余地的例子。围绕着性能话题，产生
了颇为有趣的厂商之间以及平台之间的Pet
Wars。除去这些关于性能的流言蜚语乃至中伤，PetStore在展示J2EE1.3平台的架构、演示什么叫分层方面还是有着很大的功劳的。而且
PetStore在架构方面的丰富性使得其成为J2EE的那些轻量级小兄弟们展示自身的一个必选科目。
<br />不谈那些围绕PetStore的口水，那些数不尽的盗版，PetStore给开发新手带来的最重大的影响，我想应该是架构的观念而不是性能，也
不是业务。做为一种技术的Demo，这无可非议。但是如果你是一个新手，跟着PetStore亦步亦趋地学习J2EE开发，难免会陷入过度设计、华而不实
之类的困境。围绕着.NET的PetStore的克隆PetShop展开的架构与性能的大讨论，是不是也在促使我们学习新技术时应该以解决问题为导向呢？
特别是当你想把一个如PetStore这般的Sample Project的技术照搬到你的现实世界的Real Project来时。
<br />------------------------------------------------------------------------------------------<br /><br /></span>
		<span class="postbody">
十大组织
<br /><br />
Sun : 因为Java而永被荣光
<br />
文/孟岩
<br /><br />
Sun是1980年代初期由斯坦福大学三位年轻学生创立的公司。与一般人的印象不同，“SUN”的本意并不是企图剽窃天上那颗温暖的恒星的威名，而是“斯
坦福大学网络”的意思。Sun在“前Java”时代就因为SPARC芯片、Solaris操作系统和“网络就是计算机”的口号而为人所知。1990年12
月，Sun启动了一个看上去没什么意思的嵌入式软件项目。然而，基于C++的开发很快遇到了麻烦。一个创新型技术公司的特色立刻显示出来，一群天才不是去
深入C++，而是另辟蹊径，发明了Java。这个传奇故事已经尽人皆知，但是其中所包含的精神却始终令人望空凝思。
<br />Java的发明，使得Sun真正有机会在软件的历史天空中放射出太阳的光芒。Sun发明了Java，并且在长达十年的时间里始终走在Java大
潮的最前端。Sun是Java的老家，是Java慈爱的母亲，这一切任何人都改变不了。虽然Sun似乎没能够从Java中获得应有的金钱回报，但这丝毫没
有挫伤Sun对于Java的母爱，还有对于Java大潮的舍我其谁的领导气概。
<br />
所有人都迷恋富有的感觉，但是也迟早会意识到钱不是世上最宝贵的东西。这个世界并不缺少会赚钱的公司，但是能够靠着创新型技术推动整个世界进步的公司却是凤毛麟角。Sun应该感到骄傲，他们将因为Java而在历史的天空里发射出太阳的光芒。
<br /><br /><br /><br />
IBM : Java经济的最大受益人
<br />
文/恶魔
<br /><br />Sun公司是Java的发明人，但IBM却是Java最大的受益者。是IBM抢占了利润丰厚的应用服务器市场的头把交椅，是IBM在Java技术
上投入最多的金钱，拥有最大的影响力和最好的开发者社区。可以毫不夸张地说，Java使IBM的软件体系得到复兴，在某种意义上，甚至可以说，是Java
创造了这种复兴。Java之后又来了Linux，这种建造在不属于自己的平台上以获得成功的理念更是变得非常有影响力。正是这种理念铸就了今天IBM
“按需计算，服务为王”的王者风范。
<br />
2004年三月，IBM以Java的解放者的姿态借机向Sun发难。IBM公司负责新兴技术的副总裁史密斯在一封公开信中表示，IBM愿意与Sun合作成立一个项目，意在通过开放源代码开发模式管理Java的开发工作。
<br />墙内开花，墙外香。面对IBM的成功，到底是谁妒嫉呢？或许去程序的社区中逛逛聊聊，明眼人是不难发现事实真相的。也许Sun应该好好向IBM学
习经营之道。尽管利润额不如硬件及服务部门，但IBM软件部门的利润率是最高的——高达85%的利润率足以令人惊叹。在最近的一个季度里，IBM软件部的
利润率上升了8%，其中WebSphere产品组的利润率上升了14%。
<br />
正是IBM在开源和Java上的全身心地投入又秉承开放性的原则，今日的Java才能以日进千里的速度将许多竞争对手远远抛在后面。Java 10年，IBM功不可没。
<br /><br /><br /><br />
BEA : 用AppServer影响Java阵营
<br />
文/霍泰稳
<br /><br />十年前诞生的Java并不是一开始
就那么引人注目的，虽然用Applet也曾为互联网络带来一抹亮色，但毕竟只是Toy。在企业级应用市场上，Java一直没有什么起色，虽然Java的支
持者一直在鼓吹它有着大型企业级应用的强悍功能。过高的期望与低能的产品，一时间颇让人怀疑Java的路是否已经走到了尽头？可以说是WebLogic
Server的出现逐渐打消了人们的顾虑，BEA公司慧眼独具在2001年收购的这个产品将人们的目光吸引到电信、金融、政府等Java企业级应用方面，
WebLogic
Server以其优良的性能让人们看到Java应用广阔的未来。虽然随后在Java应用服务器方面出现了像IBM公司的WebSpere、开源软件
JBoss等Java应用服务器，但WebLogic Server几乎占领世界前500强所有企业的应用服务器市场地位依然无法撼动。
<br />Java现在已经不单纯是一个语言，从另一方面它也代表着开放与创新。很多以Java产品为基础的公司或者从事Java开发的程序员骨子里都有
着开放与创新的烙印，BEA公司的发展深深地印证了这一点。与合作伙伴的密切合作向Java社区贡献产品基础源代码、加入权威开源组织参与Java标准的
制定等证实着BEA的开放，而其产品从WebLogic Server一种拓展到WebLogic Platform、WebLogic
Portal、WebLogic Workshop等其它领域又证实着它的创新能力。
<br /><br /><br /><br />
Oracle : 早起的鸟儿有虫吃
<br />
文/孟岩
<br />Oracle的老板拉里?艾利森是有名的混世魔王和花花公子，所以尽管他也是软件产业成功人士的代表，却绝不是程序员们心目中的英雄，程序员们毕
竟不是央视《对话》节目里群众演员，没必要为了节目需要而对权贵财阀们做出一副贱骨头状。但是，任何人都不能不钦佩Oracle在技术上的前瞻性和坚决
性。Oracle是1996年获得Java许可证的，紧接着就大胆地将Java作为战略性的发展方向而予以全面支持。要知道当时Java的前景并不是十分
确定的，而Oracle的坚决投入，使得它在后来的Java世界中抢得一席之地。1998年9月发布的Oracle
8i为数据库用户提供了全方位的Java支持。Oracle
8i成为第一个完全整合了本地Java运行时环境的数据库，开发者用Java就可以编写Oracle的存储过程，这意味着可以仅在Oracle数据库中就
完成几乎全部的应用开发。J2EE兴起后，Oracle更是有心进入开发工具市场，因而购买了JBuilder的源码，并在此基础上开发出
JDeveloper。如今Oracle除了数据库稳居第一之外，在Java开发工具世界里也自成一派。这一切不能不归功于当初的眼光远大。
<br /><br /><br />
Apache : 开源软件的品牌保证
<br />
文/陶文
<br /><br />Java程序员的日常工具箱中，我们可以发现Ant、Tomcat、Log4、Lucene这些鼎鼎大名的开源产品。而它们的共同点在于，都是由
Apache Software
Foundation社群中杰出的开发者开发的开源项目。Apache这个名字在Java的世界中实在太出名了，以至于“Apache”这六个字母成为开
源项目品质保证的代名词。Apache是自由开源的一面旗帜，其Apache
License更是成为商业友好的License的首选，只SourceForge上就有1000多个以Apache
License授权的项目，其流行程度可见一斑。
<br />但是，如我们所知，Apache最早闻名IT界是靠高性能的Web服务器，其历史甚至和Java一样长。Apache对于Java的偏爱，以及
其发展的速度也映射出了Java繁荣的一角。现在去它的主页上看看，满目望去全部都是Java的开源项目，早就不光是其C服务器的老本行了。Apache
对Java最大的贡献就是提供了这么一个精品的开放舞台，让杰出的开发者和成熟的开源项目走到一起，共同给Java语言提供一个丰富的工具仓库。对于一种
语言、一个平台来说，其库的丰富程度对于开发者来说的重要性再怎么强调也不为过。勿庸置疑，Aapache上会出现越来越多的Java开源项目，而我们开
发者也将更多地得益于这令人目不暇接的繁荣。
<br /><br /><br /><br />
TheServerSide : 论坛的专业精神
<br />
文/刘天北
<br /><br />成立于2000年5月，TSS最初以一本书而广为人知。它的创始人Ed Roman同时也是J2EE名著《Mastering
EJB》的作者;Roman运营着一个J2EE咨询/培训公司TheMiddlewareCompany（简称TMC），TSS当时是TMC的下属部门；
为了扩大企业的影响，Roman在TSS网站上免费发布了那本书的电子版。J2EE程序员要吃下这个香饵，就得在论坛中注册;注册的同时，多半也会看一眼
论坛的内容；一看之下，大部分人都被吸引住，成了社区的忠实成员。
<br />TSS究竟有什么吸引人的秘诀？首先，它有一支能力过人的运营团队，除了Roman本人之外，其中还有好几人都是J2EE领域的顶尖专家；第
二，TSS和TMC定期会推出专家研讨会/视频访谈、技术白皮书、评测报告，通读TSS提供的这些内容，基本上就可以把握技术的当前趋势。但这还不是全
部。最可贵的还是TSS的社区风格：他们深谙技术，但不盛气凌人；思想敏锐，但不因此缺乏审慎和大局感。其中大多数人都已在自己的开发领域颇有建树，在
TSS上的活动既给他们提供了与同行进行深度交流的机会。一个新成员进入社区，就像参加了一个起点很高的专业俱乐部，这不是一个求解“怎样设置
JAVA_HOME环境变量”之类问题的地方。事实上，在J2EE技术发展的若干转折点上，TSS都起到了关键的推动作用。
<br />
几经易主之后，J2EE咨询培训公司TMC在2004年关闭；TSS则被IT媒体集团TechTarget收购。我们期待着它更加繁荣的未来。
<br /><br />
JBoss : 职业开源软件组织
<br />
文/刘天北
<br /><br />J2EE的婴儿期，“应用服务器”原本是“昂贵”的代名词。但从1999年起，Marc Fleury和Rickard
Oberg等人就已经着手改变这种状况。他们开发的开源EJB容器当时叫做“EJBoss”，在Sun公司的干预下（注意，“EJB”是注册商标），
JBoss获得了今天的名字。虽然从问世起就一直受到关注，但JBoss第一个达到产品化标准的版本可能是它的2.2版。它的易用让人一见难忘：除了标准
部署描述符，无需编写专用的xml配置文件。Oberg自豪地说，“我们的架构并不是按照EJB规范指定的路线设计的，因此也没有走大多数应用服务器走过
的弯路。”
<br />Jboss
3.x版本保持了一贯的创新精神，在用户中间获得了更广泛的认可。但是，文档要收费下载、在邮件列表上提问常常会遭到Fleury等人的斥责。无疑，
JBoss的创始者也意识到了自己的幼稚：开源软件只能靠服务盈利，卖文档赚钱有限、骂用户当然更损害企业形象。
<br />虽然以Oberg为首的许多程序员退出了开发队伍（其中很多人成了JBoss的死敌），在开源软件领域也面临JOnAS
Geronimo等新老对手的竞争，但JBoss还是以不断推出的新版本站稳了脚跟。在技术上，它是策动J2EE演进的重要力量：拟议中的EJB
3也要追随Jboss
4倡导的开发范式，以至于二者的代码样本之间的差别几乎难以分辨；在商业上，JBoss与Sun公司言和修好，甚至还获得了数量可观的风险投资。
JBoss已经像拥护者预期的那样，成为了应用服务器领域的Linux。
<br /><br /><br /><br />
Borland : 深度介入Java
<br />
文/左轻候
<br /><br /><br />除了Sun以外，也许没有一家公司
像Borland这样深层地介入Java。Borland开发了最早的Java编译器之一，Borland的工程师参与了早期JDK的设计，
Borland的JBCL(JavaBeans Component Library) 技术也成为后来Java
Bean规范的基础。但是Borland对Java世界最大的影响还是JBuilder。
<br />1997年11月，Borland JBuilder
1.0发布。虽然第一个版本相对于竞争对手并没有表现出明显的优势，但是Borland凭借深厚的技术实力和正确的市场策略，不断地超越了对手。
JBuilder
3.5成为业界第一个100%基于Java架构的开发工具，并且市场份额很快超过了50%。在随后的版本中，JBuilder持续改进对团队开发、
J2EE架构、Mobile技术等方面的支持，最终成为了Java开发工具市场，特别是大型企业级Java开发市场中的霸主。JBuilder的成功，很
大一个原因来自于Borland坚持的平台中立性，即对不同厂商的解决方案提供一视同仁的支持。
<br />2005年初，随着Eclipse社区的迅速崛起，Borland进入了Eclipse的董事会，成为战略开发者(Strategy
Developer)
，并宣布将推动Borland的其它产品与Eclipse的集成。在随后发布的一份文件中，Borland宣称JBuilder的未来版本将放弃原有的
PrimeTime架构，而基于Eclipse架构。这个代号为“Peloton”的版本预计于2006年下半年发布。
<br />Borland对Java的另外两个主要贡献来自Together和BES(Borland Enterprise
Server)。Together是著名的建模工具，能够与包括JBuilder在内的许多开发工具进行集成，全球市场份额占有率排名第二。BES
AppServer是一种J2EE服务器，在全球市场份额占有率上次于WebLogic和WebSphere，排名第三。
<br /><br /><br /><br />
JCP : Java世界的联合国
<br />
文/黄海波
<br /><br /><br />当联合国正在为安理会改革问题 吵得如火如荼时，Java世界的“联合国安理会”已经成功地运作了七个年头。JCP（Java
Community
Process）在1998年由Sun发起成立，目标是通过一个开放、合作和鼓励参与的非盈利组织来发展和推进Java和相关的技术。正是由于JCP计划
的推出可以让所有对Java感兴趣的软硬件厂商，个人和组织都能参与到技术规范的制定和发展过程中，协调各方的兴趣和利益、集思广益，才可以让Java在
短短的几年内异军突起，成为可以和微软开发平台抗衡的一个主流开发语言。JCP计划既然是一个组织，自然也有一定的架构。JCP组织架构主要包括PMO
(Program Management
Office)、JCP成员、EC、EG。事实上，JCP的架构就好像一个Java世界的联合国。虽然也有不少人批评JCP成为各派利益的角力场，因而效
率低下；但是，它毕竟为Java的顺利发展很好地掌握了方向。
<br /><br /><br /><br />
微软与Java : 不得不说的故事
<br />
文/孟岩
<br /><br /><br />微软跟Java不对付，地球人都知 道。跟Sun和解了又怎么样？
.NET跟Java就是竞争对手，没什么说的。但是有点IT掌故的人都知道，微软并非一开始就跟Java过不去。当年比尔?盖茨盛赞Java是“长期以来
最好的程序设计语言”，而且很早就购买了Java许可证。但是微软作为村里的老大，看着人家的儿子茁壮呈长，不由得生了私心杂念，搞起了小动作，在
Visual J++中加入了一些破坏纯洁性的东西。单独来看，Visual
J++是COM时代微软最棒的开发工具，用WFC写Windows应用程序和COM组件实在是一种享受。但是放在Java大家庭里，这个家伙就显得多少有
点不怀好意。一场官司下来，微软被逐出Java大家庭，Visual
J++无疾而终。以后的事情尽人皆知，.NET出笼，利齿直指Java，几年撕咬下来，没占着便宜也没吃大亏，如今也算是南北朝对峙，二分天下有其一。设
想如果当时微软能够摒弃帝国主义心态，正确对待Java，与其他人一起共建美好的Java“共产主义社会”，那么今天我们的软件开发世界应该会美好得多。
可惜黄粱一梦，终究是蚂蚁的喜事。2004年，微软与Sun实现了和解，但愿到Java 20周年的时候，我们能更正面地描述微软对Java发挥的作用。</span>
		<br />
<img src ="http://www.blogjava.net/alex/aggbug/63361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-13 21:35 <a href="http://www.blogjava.net/alex/archive/2006/08/13/63361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]关于技术发展路线和当前形势</title><link>http://www.blogjava.net/alex/archive/2006/08/13/63354.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Sun, 13 Aug 2006 11:24:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/13/63354.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/63354.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/13/63354.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/63354.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/63354.html</trackback:ping><description><![CDATA[
		<span class="postbody">一、软件开发技术
<br /><br />
1）服务器端
<br /><br />
在最近5年内，Java还是主流，不光是因为当前的普及程度和遗留系统问题，而且除Microsoft几乎所有大公司都投资到Java上面的原因，此外开
源也是一股无法忽略的力量：除了Java方面的开源框架在推动Java，也有Linux在带动java企业应用在普及（别忘记dotnet只能在
Windows Server上面运行）
<br /><br />dotnet有自己的优势，但是在五年内无法和Java取得均势，不光是因为Java普及带来的优势，也不光因为开源界对java的推动，也不光
因为其他大公司在java上面的投资，而是很多公司的行业性质决定了dotnet的出局，例如电信行业，金融行业，电子政务行业等等，是根本没有可能采用
dotnet的。
<br /><br />
Python和Ruby算不上后起，但是很有竞争实力，不过基于上面的原因，仍然不能成为主流。
<br /><br />在Java服务器端技术中，清晰的分为两条路线：高端的商业路线，这条路线是EJB3，J2EE5.0；低端的开源路线，这条路线是
Hibernate， Spring。这两条路线也有重叠的地方，例如开源的Struts几乎成为J2EE
Web层的标准，开源的Hibernate奠定了EJB3的基础。但是划分路线不是基于技术上的区别，而是基于商业运作上的区别。注重技术支持和商业服务
的公司会选择前者，注重成本控制和选择自由的公司会选择后者。
<br /><br />
商业路线的技术方案是：EJB3＋Struts；
<br />
开源路线的技术方案是：Spring＋Hibernate＋Struts/Webwork
<br /><br />
Struts是一个很成功的开源框架，它的地位短期内还无法动摇，JavaEye有一项使命，就是动摇Struts在Java Web领域的地位，把它赶下王座，把Webwork扶上位！
<br /><br />
商业的Web层技术，JSTL算是一个不错的东西，但是和灵活的模板语言如FreeMarker相比，却有很大的差距。JSF基本上是一个没有前途的东西。商业Web层技术因为一直没有出现好的应用，这样也导致了Struts的上位。
<br /><br />服务器端业务层和持久层框架，我非常看好EJB3，原因也不用多谈了，从商业上来说，需要这样一个东西，跨国公司们也需要这样一个产品来卖，来取
代糟糕的
EJB2。开源的方案里面，Spring＋Hibenrate是一个很好的商业方案的开源替代，他们不存在很直接的竞争，而是一个互补的关系。这里比较尴
尬的反而是JDO：JDO是商业产品（目前没有好的开源实现），造成开源应用不会对它感兴趣，JDO没有一个像EJB容器那样的脱管环境，造成商业方案对
它不感兴趣。不过有了JDO，我觉得是对EJB3，对Hibernate形成一个良好的竞争环境，这一点是非常有利的。
<br /><br />
2）客户端技术
<br /><br />
准确的说是RIA应用。虽然我前面对XAML进行了正面的评价，但是我认为我前面有些结论给错了。经过这段时间，我觉得，XAML即时在多年之后，也未必能够成为一个非常成功的解决方案。道理很二：
<br /><br />
1、XAML会带来比ActiveX更严重的安全性问题。
<br />XAML本质上就是一个本地应用程序，虽然号称可以在IE浏览器里面运行，但IE就是一个皮而已，XAML应用具备对本地资源完全的访问能力（就
算IE限制也没有用，IE限制就丧失功能，那样的话，功能并不会比Javascript来得更多；不限制的话，就为所欲为了），因此只要IE具备了运行
XAML的能力，黑客将可以非常轻易的通过IE进行入侵，这仅仅需要引导用户在不知不觉中访问一个恶意的网页就搞定了！用户必须面临选择：要么禁止IE对
XAML的运行能力，要么接受随时被攻击的危险。
<br /><br />
2、XAML应用本质上也是RIA应用，因此必须进行大量的RPC调用
<br />
当前XAML采用XML Web Services进行通讯，这是一种低效的RPC。当前的XAML案例中并没有注意到RPC领域，实际上根据我现在做RIA的体验来说，RPC绝对不是一个简单的事情，要考虑的问题非常多。
<br /><br />
从当前的阶段来说，最实际可用的方案有两个：
<br /><br />
1、AJAX
<br />实际上就是基于XMLHTTP的JS异步交互，这个东西已经出现很多年了，最近随着Google应用和Sun
Blueprint的推出开始火热。我原来对这个东西持否定态度，但是后来转变了。我原来否定态度的一个前提就是：XMLHTTP缺乏成熟的组件库！但是
没有想到的是，现在XMLHTTP从去年下半年开始，如雨后春笋般冒出来。AJAX应用最大的好处就是充分利用现有资源，我认为应成为RIA应用的首选。
<br /><br />
2、Flash
<br />
Flash的优势也很明显，强大的AS支持，强大的组件可视化设计，强大的交互能力和很炫的用户体验，并且Flash
Remoting也已经非常成熟了。Flash的缺点就是Flash虽然嵌入网页，但是和网页没有数据交互能力，Flash另一个缺点就是不适合处理大量
文本内容（HTML最适合）。现在有些人开始滥用Flash了。
<br /><br />
因此比较好的方式可能是两种混用，一般不过度复杂的交互交给AJAX，非常复杂，甚至需要托拽操作的，交给Flash。
<br /><br />
总结一下：
<br /><br />
软件开发领域服务器端技术Java是主流，两个技术路线，一个是EJB3，一个是Spring＋Hibernate，此外iBATIS也有一席之地；客户端技术就是AJAX和Flash。
<br /><br />
二、数据库技术
<br /><br />基本上格局不会发生多大变化，Oracle还是高高在上，SQL
Server进一步蚕食NT平台其他数据库的领地。开源方面，MySQL将一枝独秀，但是开源数据库在很多方面还是和商业数据库有无法拉近的巨大差距。这
也使得商业数据库的地位不可替代。我会比较关注Oracle，MySQL这两个数据库。面向对象数据库仍然不会有什么起色。
<br /><br />
三、桌面编程技术
<br /><br />我还是相信一点，对于桌面应用来说，本地代码的位置永远无法被取代，所以我总觉得XAML那样的东西效率实在很成问题。Longhorn要像成
熟，也不是第一个版本就可以达到的。当前桌面应用开发技术，还是首推Delphi，不过我觉得Python是后起之秀，非常有可能在未来取代Delphi<br /><br /></span>
		<span class="postbody">初探在下一代 Windows 中编写和部署应用程序
<br /><a href="http://www.microsoft.com/china/MSDN/library/windev/longhorn/DevelopAppLonghorn.mspx" target="_blank">http://www.microsoft.com/china/MSDN/library/windev/longhorn/DevelopAppLonghorn.mspx</a><br /><br />
首先，以Microsoft公司的实力和Windows操作系统的占有率来说，Longhorn迟早会被普及，而XAML的开发方式也有可能普及的。记得
当初WindowsXP刚出来的时候，因为资源占用率和新的激活制度招致一片骂声，但是慢慢的，现在也都接受了下来。由此可以推断，Longhorn以其
更加丰富的桌面功能和诱人的外观，会在将来成为主流。
<br /><br />但是Longhorn什么时候才会全面普及，这是很值得琢磨的问题。WindowsXP是2001年推出的，在随后的几年，Microsoft采
用了一些商业手段来迫使用户升级，例如企图取消Windows98的技术支持，不再提供WindowsNT技术支持，不再销售
WindowsNT/Windows98，将Windows2000保持在一个比较高的售价的同时，对WindowsXP推出优惠价格，让
WindowsXP的售价低于Windows2000等等手段。但是直到现在，Windows2000仍然占据了非常高的份额，据我个人的观察是比
WindowsXP略高。按照这种情况来推断，Longhorn要普及，恐怕难度更大，非常多的用户现在仍然是Windows2000的死忠派，
WindowsXP推广了四年还未能超过Windows2000，那么Longhorn究竟要几年才能超过WindowsXP呢？我估计四年以上是起码
的。
<br /><br />XAML应用程序不同以往，它只能跑在Longhorn上面，甚至比Java和dotnet要求更严格，后者仅仅下载安装一个运行环境就可以了，
但是前者要求你必须更新操作系统。XAML在IE浏览器中运行虽然肯定是下一代RIA的主流，但是不可忽视的问题是，只要Longhorn没有彻底淘汰
Windows2000/XP，软件开发商和网站开发商就不敢大面积采用XAML。而根据我的观察，现在企业中，Windows98仍有少部分市场份额。
因此Longhorn必须要等待到彻底的，毫不残留的淘汰Windows98，Windows2000，WindowsXP之后，才会全面普及，而在此之
前，不得不经历一个漫长的过渡期。
<br /><br />就好像现在，假设你开发桌面应用程序，你敢只针对WindowsXP开发吗？而彻底不支持98和2000吗？我想，没有哪个软件开发商敢这样做。
除非
Windows2000几乎被彻底淘汰了，你才敢这样做，但是WindowsXP已经推出四年了，还没有Windows2000占用率高，哪全面淘汰究竟
要几年呢？再看看现在dotnet
winforms应用，推出也已经五年时间了，但是到现在仍然没有普及开来，根本的原因就是Windows2000/WindowsXP没有预装
dotnet framework。仅仅是需要打包安装一个运行环境就使得winforms五年都推广不了，更何况要求你升级操作系统呢？
<br /><br />我个人的估计是，假设2006年Longhorn如期上市，那么将需要7-9年时间来彻底淘汰Windows2000/WindowsXP。
Longhorm上面XAML应用的初步普及也至少需要4-5年时间以后才会有软件开发商大量去做（想向dotnet是2000年开始宣传和推广的，到
2004年开始普及，今年和明年才会全面普及)。因此，基于XAML应用的普及可能是在2010年以后！上面的估计中还没有包括MacOS
和Linux在桌面会否有什么表现。
<br /><br />
先说说服务器端吧：
<br /><br />从可预见的未来来看，服务器和客户端TCP通讯的主流方式一定是HTTP协议（即时通讯软件走UDP端口，不在讨论范围）。在基于HTTP协议之
上，又分为两类：一类是SOAP协议，异构系统支持良好，但是性能很差，目前Microsoft很喜欢用这种方式；一类是轻量级二进制协议，例如
Flash的
AMF协议，Resin的Hessian协议。值得一提的是，不管哪种方式，他们都支持异构的系统，所以完全可用在客户端采用dotnet，在服务器端采
用Java或者Python。因此，XAML的流行不会对服务器端技术产生致命的影响（肯定会提高dotnet的服务器的市场份额）。所以我们可用抛开客
户端影响，单独来看服务器端技术：
<br /><br />
1、Java
<br />Java是当前服务器端技术当之无愧的王者，在未来五年内，也不会有任何动摇（受到dotnet和python的影响，市场份额会下降一些）。
Java特别有利的一点是，现在有太多的现存系统基于Java，这些系统都不会轻易迁移到其他平台上。另外还有一个决定因素是除了Microsoft之外
的几乎全部
IT大公司都在Java方面的投资巨大，放弃Java对他们来说也意味着沉重的打击，甚至毁灭性的打击。这些公司可以列很长很长，IBM，HP，
Oracle，SAP，Sun，BEA，Macromedia等等。
<br /><br />
2、dotnet
<br />由于Microsoft的影响力，dotnet会成为为仅次于Java的第二大服务器端技术，但是Microsoft有一个隐忧，就是Linux
操作系统在服务器端的高速成长。虽然现在Linux在整个服务器端市场的出货量只有13%左右，但是成长率惊人，根据我看到的资料显示，到2008年，将
占据
25%以上的市场份额。考虑到很多公司是自己安装Linux，因此不会被硬件服务器厂商统计进来，因此Linux的服务器端的市场份额应该比25%高一
些。并且现在主要的服务器厂商都对Linux有非常巨大的投入和支持，这些公司包括IBM，HP，Dell（只有Sun不支持），因此Linux在未来会
对Windows在服务器端的市场构成最严重的威胁。
<br /><br />不要忘记dotnet只能在Windows平台上面跑，虽然有mono，但是你不可能移植MTS，COM+，SQL Server
etc。所以只要Linux在服务器市场对Windows构成持续的威胁，dotnet就不可能超过Java，Java的地位还是稳稳的老大。从某种程度
上来说，Java的命运是和Linux联系在一起的，只要Linux在服务器端不输于Windows，Java就稳稳压制dotnet。
<br /><br />
BTW:从未来来看，Linux和Windows会在低端和中端服务器市场成为主要竞争对手，由于各自都有其不可替代性，所以双方都不可能彻底消灭对方，最大的可能性是Linux和Windows平分市场，或者Windows市场份额略高一点。
<br /><br />
3、Python
<br />我个人认为Python会成长为第三大服务器端技术，Python成长于开源，但是又有商业公司来商业运作，并且背后还有大公司的支持，在欧洲普
及的非常好。当然最重要的原因是我觉得Python在技术上非常先进，并且技术发展方向上比较统一，不会出现Java那种吵架的事情。
<br /><br />
4、PHP
<br />PHP这东西是不错，Yahoo也在用，IBM现在也对他感兴趣，但是我还是要说PHP没有太广阔的前途，原因很简单，PHP没有服务端中间件，
例如 Java有App
Server，dotnet有IIS/MTS，Python有Zope，但是PHP他就是一个脚本，没有自己的中间件就是致命问题。Yahoo用PHP有
其特定的原因，主要是从原先自己的技术迁移到PHP很方便，而IBM支持PHP，显然醉翁之意不在酒，IBM意不在推广PHP，而在于争取到那些使用
PHP的商业大客户们，向他们卖服务。
<br /><br />
BTW：感觉欧洲用Python/PHP的很多，似乎开源在欧洲非常深入人心。
<br /><br />从服务器端技术来说，Java还是我们最需要下功夫去学习和掌握的，此外，我会比较倾向于钻研和应用Python，而不是dotnet。原因也很
简单，跟随Micorsoft的技术会很辛苦，Microsoft产生的新概念多，他总是会猛的推出n多种技术，然后让他们在市场上自己生存，最后根据市
场反馈，无情的抛弃某些东西，大力推进有市场前景的东西，这样的例子太多了，举不胜举了。我的感觉就是这种方式会让Microsft经过市场尝试在技术竞
争中筛选最优秀的技术，但是对于Microsoft技术的跟随者来说，未免有点太不公平，整天吭哧吭哧被Microsoft拿来当免费的试验品来用。我特
别不理解的是MSDN宇宙版，Microsoft总是把无穷无尽的文档灌给你，让你永远学不完，但实际上我真的不需要那么多概念，我只需要能够很好的完成
我工作的技术，并且这个技术可以持续的完善就好了。而不是今天给我这样一个东西，明天灌给我无穷的文档，后天当我用顺手以后，又告诉我这东西作废了，你给
我重新学习新东西，然后又是无穷的文档，总之很恼火。
<br /><br />
所以就是：重点学习Java，有时间去学习Python，保持对dotnet的关注即可。
<br /><br /><br />
客户端：
<br /><br />
前面说了那么多XAML的东西，都是和这有关，七年以后肯定是XAML的天下，但是五到七年之内还不是：
<br /><br />
1、Java
<br />Java在客户端真的是扶不起的阿斗，这都怪Sun。Sun造就了Java的成功，又一手毁了Java在客户端的市场。那些个Swing和SWT
的死忠团也不要和我争什么，我也懒得和你们争，你们觉得好就好吧，道不同不相与谋，你觉得好你就用你的，我觉得不好我就用别的。用不着缠着我非逼我说
Java做客户端好，没必要，况且就算你逼我承认又怎样？我就是玉皇大帝金口玉言了？得到我的承认，Java就有前途了？我好像还没有那么大本领吧？就是
IBM， Sun也没有那么大本领，所以好不好也不是我说了算，用不着逼我。
<br /><br />
2、dotnet winforms
<br />由于Windows2000/WindowsXP不带dotnet
CLR，所以winforms一直没有能够普及得很好，等Longhorn一出来，又变成了XAML了，winforms又被淘汰了，所以
winforms的地位特别尴尬，但是在这5-7年中，你想开发既能够在Windows2000/WindowsXP，又能够在Longhorn上面跑的
桌面程序，winforms好像又是Microsoft技术中最好的选择。所以只好一直尴尬下去。
<br /><br />
3、VC，VB
<br />
dotnet出来以后就开始尴尬了，说用吧，好像很落伍了，都dotnet时代了，说不用吧，又没有好的替代品，现阶段开发桌面程序，还真得不得不用，而且还挺好用的。所以VC6SP5，VB6的死忠团也比较多。
<br /><br />
4、Delphi
<br />dotnet出来以后Borland就开始跟风了，这一跟风，连老本都跟没有了。未来的XAML时代，我也不知道Borland怎样找自己的定
位，但不管怎么说，从历史来看，本地代码的应用程序永远有它一席之地！就算XAML又如何如何做得漂亮了，关键的地方，和特定资源处理相关的部分，还是本
地代码的程序管用。你看VB出来多少年了，用VB开发的都是一些上层的项目级别的应用软件，一旦涉及产品领域，还是VC和Delphi管用。所以现在大家
还是不得不用Delphi7阿。
<br /><br />BTW：XAML应用致力于快速开发项目级别的应用，特别是可以跑在IE浏览器里面的，因此是RIA的首选。但是毕竟也有很多不适合用RIA的场
所，特别是例如我要备份某些文件，你用XAML？那性能就不用提了。所以Delphi如果好好发展VCL，封装Windows32
API，我觉得也是一条路，未必比现在跟随dotnet差。
<br /><br />
5、Flash RIA
<br />其实我觉得Flash不适合做RIA的，但是Flash普及率太高，XAML又离普及太遥远，而Flash现在就可以用了，所以是当前RIA的首
选。不过我对Macromedia公司比较失望，如果Macromedia能够公布Flash实现细节，作为一个公开的标准向ISO提交，同时免费开源
Flex，我敢说，Flash
RIA会迅速普及的。等5-7年XAML的时代，由于Flash的市场占有率，XAML就未必能拼得过Flash。可惜的是Macromedia公司目光
过于短浅，只知道赚眼前的小钱。
<br /><br />
6、Python
<br />
这5-7年内，RIA应用和RCP应用不会统一，XAML才具备将RIA和RCP统一的实力。从这5-7年来看，Flash是RIA的首选，而RCP的首选，我要推荐Python。原因前面已经提过，简单总结一下：
<br />
1）wxWidgets是一个比MFC优雅的库，TortoiseCVS用wxWidges而不用MFC，就是因为wxWidgets好用，而不是为了可以移植。
<br />
2）Python的面向对象脚本语言编程适合快速界面开发
<br />
3）Python在服务器端和客户端都非常有前途，可以形成一个统一的解决方案，这一点明显比Java有优势
<br />
4）Python桌面应用程序可以完全编译为本地代码，脱离Python运行环境，这一点比dotnet winforms都有优势
<br />
5）Python可以不受限制的任意调用Windows32 API，所以凡是VC6可以做的事情，Python就可以做
<br /><br />
试想一下，现在我们开发桌面应用程序有什么要求？
<br />
一、不要附带一个JRE或者CLR的累赘
<br />
二、可以快速开发
<br />
三、性能要有保证
<br />
四、方便的远程方法调用支持
<br />
此外如果能够跨平台就最好了
<br /><br />
Java前三点都不符合；dotnet winforms不符合一；VC6不符合二和四，VB6不符合三和四；Delphi7符合前四点；Flash RIA不符合三；Python全部都符合！并且请记住Python是一个完全开源免费的方案！
<br /><br />
客户端技术在这5-7年中，在RIA领域我会学习一下Flash，在RCP领域我会重点学习Python，此外会观望一下XAML。</span>
		<br />
<img src ="http://www.blogjava.net/alex/aggbug/63354.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-13 19:24 <a href="http://www.blogjava.net/alex/archive/2006/08/13/63354.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>POI的一个bug问题</title><link>http://www.blogjava.net/alex/archive/2006/08/10/62823.html</link><dc:creator>Alex</dc:creator><author>Alex</author><pubDate>Thu, 10 Aug 2006 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/alex/archive/2006/08/10/62823.html</guid><wfw:comment>http://www.blogjava.net/alex/comments/62823.html</wfw:comment><comments>http://www.blogjava.net/alex/archive/2006/08/10/62823.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/alex/comments/commentRss/62823.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alex/services/trackbacks/62823.html</trackback:ping><description><![CDATA[key words : POI java读取Excel  <font face="Verdana, Arial" size="2">java.io.IOException Unable to read entire block</font><br /><br />版本:2.5.1final<br />错误提示:<br /><font face="Verdana, Arial" size="2">java.io.IOException Unable to read entire block<br /><br />出这个问题具有随机性，有时候没问题，有时候将Excel里的CellType改一下好像就没问题，但也不总是这样，真是莫名其妙.<br /><br />Google了一下是一个bug,重新下载src文件，将RawDataBlock.java文件的RawDataBlock(final InputStream stream)constructor覆盖:<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> RawDataBlock(</span><span style="color: rgb(0, 0, 255);">final</span><span style="color: rgb(0, 0, 0);"> InputStream stream) </span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);"> IOException<br />    {<br />        _data </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">byte</span><span style="color: rgb(0, 0, 0);">[ POIFSConstants.BIG_BLOCK_SIZE ];<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> count </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> totalBytesRead </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />        </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> ((totalBytesRead </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> POIFSConstants.BIG_BLOCK_SIZE) </span><span style="color: rgb(0, 0, 0);">&amp;&amp;</span><span style="color: rgb(0, 0, 0);"><br />(count </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)) {<br />                count </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> stream.read(_data, totalBytesRead,<br />POIFSConstants.BIG_BLOCK_SIZE </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> totalBytesRead);<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (count </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) {<br />                        totalBytesRead </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> count;<br />                }<br />        }<br />          </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (count </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) {<br />                _eof </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">;<br />          } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />            _eof </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">;<br />        } <br />          </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ((totalBytesRead </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> POIFSConstants.BIG_BLOCK_SIZE) </span><span style="color: rgb(0, 0, 0);">&amp;&amp;</span><span style="color: rgb(0, 0, 0);"> (totalBytesRead </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)) {<br />            String type </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> byte</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> ((totalBytesRead </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);"> (</span><span style="color: rgb(0, 0, 0);">""</span><span style="color: rgb(0, 0, 0);">): (</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">s</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">));<br />            </span><span style="color: rgb(0, 0, 255);">throw</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> IOException(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Unable to read entire block; </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"><br />totalBytesRead </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> type </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> read; expected </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> POIFSConstants.BIG_BLOCK_SIZE </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">bytes</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />        }<br />    }<br /><br /></span></div><br />打包:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">ant jar</span></div><br />重启app，OK!<br /><br />说明:<br />主要问题出在 InputStream的read上，原来的实现用ReadFully方法：<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> readFully(InputStream in, </span><span style="color: rgb(0, 0, 255);">byte</span><span style="color: rgb(0, 0, 0);">[] b, </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> off, </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> len)<br />    </span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);"> IOException<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> total </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />        </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> (;;) {<br />            </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> got </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> in.read(b, off </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> total, len </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> total);<br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (got </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">) {<br />                </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> (total </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">) </span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"> : total;<br />            } </span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);"> {<br />                total </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> got;<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (total </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> len)<br />                    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> total;<br />            }<br />        }<br />    }</span></div><br />InputStream的read不能确保返回的是最大字节数,但是另一个实现却可以:</font><font face="Verdana, Arial" size="2">ByteInputStream<br />所以，下面的方法也可以修改这个问题:<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> read entire stream into byte array:</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    ByteArrayOutputStream byteOS </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ByteArrayOutputStream();<br />    </span><span style="color: rgb(0, 0, 255);">byte</span><span style="color: rgb(0, 0, 0);">[] buffer </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">byte</span><span style="color: rgb(0, 0, 0);">[</span><span style="color: rgb(0, 0, 0);">1024</span><span style="color: rgb(0, 0, 0);">];<br />    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> count;<br />    </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> (count </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> inputStream.read(buffer)) </span><span style="color: rgb(0, 0, 0);">!=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">)<br />        byteOS.append(buffer, </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">, count);<br />    byteOS.close();<br />    </span><span style="color: rgb(0, 0, 255);">byte</span><span style="color: rgb(0, 0, 0);">[] allBytes </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> byteOS.betByteArray();<br /><br /></span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> create workbook from array:</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">InputStream byteIS </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ByteArrayInputStream(allBytes);<br />HSSFWorkbook wb </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> HSSFWorkbook(byteIS);</span></div><br /></font><img src ="http://www.blogjava.net/alex/aggbug/62823.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alex/" target="_blank">Alex</a> 2006-08-10 17:09 <a href="http://www.blogjava.net/alex/archive/2006/08/10/62823.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>