千炮网络捕鱼游戏http://www.oiklr.tw/alex/category/5488.html不求多得,只求一得 about java,hibernate,spring,design,database,Ror,ruby,快速開發<br/> 最近關心的內容:Jboss Seam框架,JSF,EJB3 <br/> 本站的官方站點是:<a href="www.foxlog.org">www.foxlog.org</a> zh-cnSat, 01 Sep 2007 05:48:58 GMTSat, 01 Sep 2007 05:48:58 GMT60java框架庫:選一款適合你的武器行走江湖http://www.oiklr.tw/alex/archive/2007/09/01/141902.htmlAlexAlexSat, 01 Sep 2007 04:42:00 GMThttp://www.oiklr.tw/alex/archive/2007/09/01/141902.htmlhttp://www.oiklr.tw/alex/comments/141902.htmlhttp://www.oiklr.tw/alex/archive/2007/09/01/141902.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/141902.htmlhttp://www.oiklr.tw/alex/services/trackbacks/141902.html閱讀全文

Alex 2007-09-01 12:42 發表評論
]]>
Spring中的service之間如何調用http://www.oiklr.tw/alex/archive/2007/05/14/117228.htmlAlexAlexMon, 14 May 2007 01:05:00 GMThttp://www.oiklr.tw/alex/archive/2007/05/14/117228.htmlhttp://www.oiklr.tw/alex/comments/117228.htmlhttp://www.oiklr.tw/alex/archive/2007/05/14/117228.html#Feedback6http://www.oiklr.tw/alex/comments/commentRss/117228.htmlhttp://www.oiklr.tw/alex/services/trackbacks/117228.html閱讀全文

Alex 2007-05-14 09:05 發表評論
]]>
談談方法中的返回值類型和參數類型http://www.oiklr.tw/alex/archive/2007/05/13/117126.htmlAlexAlexSun, 13 May 2007 09:15:00 GMThttp://www.oiklr.tw/alex/archive/2007/05/13/117126.htmlhttp://www.oiklr.tw/alex/comments/117126.htmlhttp://www.oiklr.tw/alex/archive/2007/05/13/117126.html#Feedback3http://www.oiklr.tw/alex/comments/commentRss/117126.htmlhttp://www.oiklr.tw/alex/services/trackbacks/117126.html閱讀全文

Alex 2007-05-13 17:15 發表評論
]]>
簡單就是美 -- 簡化hibernate,簡化daohttp://www.oiklr.tw/alex/archive/2007/05/13/117118.htmlAlexAlexSun, 13 May 2007 08:41:00 GMThttp://www.oiklr.tw/alex/archive/2007/05/13/117118.htmlhttp://www.oiklr.tw/alex/comments/117118.htmlhttp://www.oiklr.tw/alex/archive/2007/05/13/117118.html#Feedback11http://www.oiklr.tw/alex/comments/commentRss/117118.htmlhttp://www.oiklr.tw/alex/services/trackbacks/117118.html閱讀全文

Alex 2007-05-13 16:41 發表評論
]]>
在oracle application server中部署jstl和struts,以及log4jhttp://www.oiklr.tw/alex/archive/2007/05/08/116023.htmlAlexAlexTue, 08 May 2007 11:11:00 GMThttp://www.oiklr.tw/alex/archive/2007/05/08/116023.htmlhttp://www.oiklr.tw/alex/comments/116023.htmlhttp://www.oiklr.tw/alex/archive/2007/05/08/116023.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/116023.htmlhttp://www.oiklr.tw/alex/services/trackbacks/116023.htmlkey words: jstl,struts,log4j

1.jstl
jstl的配置參考這篇文章:
http://foolmouse.cnblogs.com/archive/2006/04/20/380695.html

在iAS904服務器上的jstl的版本只能用1.0 的
"standard.jar和jstl.jar文件拷貝到\WEB-INF\lib\
"

2.struts
struts的配置主要是把 相關jar文件(struts.jar,struts-legacy.jar)拷貝到\WEB-INF\lib
,另外,struts需要用到一些apache的commons的包(commons-beanutils.jar,commons-collections-2.1.1.jar,commons-digester.jar)

3.log4j
log4j經常有莫名其妙的問題,有時候能出來log有時候又不能出來log,最后把log4j.xml統一改為log4j.properties,暫時看好像有效果。

4。web.xml配置

<taglib>
        
<taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri>
        
<taglib-location>/WEB-INF/c-1_0.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-bean.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-html.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-html.tld</taglib-location>
    
</taglib>
    
<taglib>
        
<taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri>
        
<taglib-location>/WEB-INF/struts-logic.tld</taglib-location>
    
</taglib>


今天終于先在iAS里部署完了struts,下一步把hibernate放進去,上次部署過一次,沒有成功,據說是和toplink有點沖突。 知道的兄弟分享下oc4j中部署hibernate


Alex 2007-05-08 19:11 發表評論
]]>
[zt]插入圖片到數據庫(BLOB大字段保存對象)http://www.oiklr.tw/alex/archive/2007/03/28/107018.htmlAlexAlexWed, 28 Mar 2007 08:55:00 GMThttp://www.oiklr.tw/alex/archive/2007/03/28/107018.htmlhttp://www.oiklr.tw/alex/comments/107018.htmlhttp://www.oiklr.tw/alex/archive/2007/03/28/107018.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/107018.htmlhttp://www.oiklr.tw/alex/services/trackbacks/107018.html閱讀全文

Alex 2007-03-28 16:55 發表評論
]]>
hashMap不排序啊http://www.oiklr.tw/alex/archive/2007/03/20/105020.htmlAlexAlexTue, 20 Mar 2007 08:23:00 GMThttp://www.oiklr.tw/alex/archive/2007/03/20/105020.htmlhttp://www.oiklr.tw/alex/comments/105020.htmlhttp://www.oiklr.tw/alex/archive/2007/03/20/105020.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/105020.htmlhttp://www.oiklr.tw/alex/services/trackbacks/105020.html閱讀全文

Alex 2007-03-20 16:23 發表評論
]]>
真正理解面向接口編程http://www.oiklr.tw/alex/archive/2007/03/12/103185.htmlAlexAlexSun, 11 Mar 2007 16:40:00 GMThttp://www.oiklr.tw/alex/archive/2007/03/12/103185.htmlhttp://www.oiklr.tw/alex/comments/103185.htmlhttp://www.oiklr.tw/alex/archive/2007/03/12/103185.html#Feedback7http://www.oiklr.tw/alex/comments/commentRss/103185.htmlhttp://www.oiklr.tw/alex/services/trackbacks/103185.html閱讀全文

Alex 2007-03-12 00:40 發表評論
]]>
[討論]上傳文件放在哪里比較合適?http://www.oiklr.tw/alex/archive/2007/01/31/96831.htmlAlexAlexWed, 31 Jan 2007 01:06:00 GMThttp://www.oiklr.tw/alex/archive/2007/01/31/96831.htmlhttp://www.oiklr.tw/alex/comments/96831.htmlhttp://www.oiklr.tw/alex/archive/2007/01/31/96831.html#Feedback4http://www.oiklr.tw/alex/comments/commentRss/96831.htmlhttp://www.oiklr.tw/alex/services/trackbacks/96831.html
目里面有上傳文件的需求,我想了一下不外乎下面兩種處理方法:

1. 在數據庫表中建立一個blob字段存放用戶上傳文件.
2. 在服務器上建立一個文件夾保存用戶上傳文件,數據庫表中只存放該文件的url地址.

我本人現在比較傾向于第2種方案, 主要原因是擔心方案1的效率(我用的是mysql數據庫)。 但是處理過程中除了維護數據庫中表的字段還要維護上傳的文件,稍微麻煩一點。

大家在項目里面又是怎么做呢? 給我點建議!謝謝


討論內容見: javaeye

robin更建議第二種方案,放在數據庫中主要的問題是 AppServer吃不消,開銷比較大.

上面是摘錄,不過我們這里用的是Oracle9i AS,在Oracle的協作套間里一般文檔或者上傳的文件都是保存在數據庫里,還把這個特性作為Oracle 與別的協作套件之間不同的賣點。

大家以為如何? 我直覺是Oracle的DB和oc4j的AppServer對付這個似乎沒有開銷上的擔心,但是沒有實際檢測過。

換句話說,文件的管理是放在文件夾里方便還是數據庫里方便? 有點為難

update (2007-5-13):
還有一種方案結合了數據庫和IO,我認為比較可行,就是文件存在數據庫,但是下載的時候第一次從數據庫下載,然后第一次這個文件保存在一個臨時文件夾下面,以后每次下載的時候總是先檢查此臨時文件夾,如果已經存在則直接下載,如果沒有則從數據庫重復這個動作。當然,保存在臨時文件夾下的文件的命名需要唯一,這個應該沒有問題。

Alex 2007-01-31 09:06 發表評論
]]>
2007計劃http://www.oiklr.tw/alex/archive/2007/01/03/91656.htmlAlexAlexWed, 03 Jan 2007 15:31:00 GMThttp://www.oiklr.tw/alex/archive/2007/01/03/91656.htmlhttp://www.oiklr.tw/alex/comments/91656.htmlhttp://www.oiklr.tw/alex/archive/2007/01/03/91656.html#Feedback12http://www.oiklr.tw/alex/comments/commentRss/91656.htmlhttp://www.oiklr.tw/alex/services/trackbacks/91656.html
新的一年開始了,制定一個計劃吧

說說你有什么計劃

如圖:

2007-plans.png

Alex 2007-01-03 23:31 發表評論
]]>
Unsupported major.minor version 49.0錯誤http://www.oiklr.tw/alex/archive/2006/11/08/79775.htmlAlexAlexWed, 08 Nov 2006 02:13:00 GMThttp://www.oiklr.tw/alex/archive/2006/11/08/79775.htmlhttp://www.oiklr.tw/alex/comments/79775.htmlhttp://www.oiklr.tw/alex/archive/2006/11/08/79775.html#Feedback2http://www.oiklr.tw/alex/comments/commentRss/79775.htmlhttp://www.oiklr.tw/alex/services/trackbacks/79775.html
今天用一個工作流的產品,非要用jdk1.4的版本,沒辦法,只好切換回來,但是換回來后打開頁面jsp出錯,提示Unsupported major.minor version 49.0錯誤,到網上查了一下,49.0錯誤屬于jdk1.5的錯誤,但是我的jdk1.5已經刪除了啊?怎么回事呢?

最后想起來,可能是jboss中的1.5 版本產生臨時文件class文件刪除,刪除后OK


資料:Unsupported major.minor version 49.0

Alex 2006-11-08 10:13 發表評論
]]>
[zt]RBAC 模型初探http://www.oiklr.tw/alex/archive/2006/10/26/77481.htmlAlexAlexThu, 26 Oct 2006 13:31:00 GMThttp://www.oiklr.tw/alex/archive/2006/10/26/77481.htmlhttp://www.oiklr.tw/alex/comments/77481.htmlhttp://www.oiklr.tw/alex/archive/2006/10/26/77481.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/77481.htmlhttp://www.oiklr.tw/alex/services/trackbacks/77481.html 訪問控制背景

??? 訪問控制技術是由美國國防部(Department of Defense, DoD)資助的研究和開發成果演變而來的。這一研究導致兩種基本類型訪問控制的產生:自主訪問控制(Discretionary Access Control, DAC)和強制訪問控制(Mandatory Access Control, MAC)。最初的研究和應用主要是為了防止機密信息被未經授權者訪問,近期的應用主要是把這些策略應用到為商業領域。

??? 自主訪問控制,允許把訪問控制權的授予和取消留給個體用戶來判斷。為沒有訪問控制權的個體用戶授予和廢除許可。自主訪問控制機制允許用戶被授權和
取 消訪問其控制之下的任何客體(object),換句話說,用戶就是他們控制下的客體的擁有者。然而,對于多數組織來說,最終用戶對所訪問的信息沒有擁有 權。對于這些組織,公司或代理機構是事實上的系統客體和處理他們的程序的擁有者。訪問優先權受組織控制,而且也常常基于雇員功能而不是數據所有權。

?? 強制訪問控制,在美國國防部 Trusted Computer Security Evaluation Criteria (TCSEC) 中定義如下:“一種限制訪問客體的手段,它以包含在這些客體中的信息敏感性和訪問這些敏感性信息的主體的正式授權信息(如清除)為基礎”。
??
?? 以上訪問控制策略對于處理一些無需保密但又敏感的信息的政府和行業組織的需求并不是特別的適合。在這樣的環境下,安全目標支持產生于現有法律、道德規范、 規章、或一般慣例的高端組織策略。這些環境通常需要控制個體行為的能力,而不僅僅是如何根據信息的敏感性為其設置標簽從而訪問這一信息的個人能力。
????


什么是基于角色訪問控制(Role-Based Access Control, RBAC)?NIST 有如下定義。
??
?? 訪問是一種利用計算機資源去做某件事情的的能力,訪問控制是一種手段,通過它這種能力在某些情況下被允許或者受限制(通常是通過物理上和基于系統的控 制)。基于計算機的訪問控制不僅可規定是“誰”或某個操作有權使用特定系統資源,而且也能規定被允許的訪問類型。這些控制方式可在計算機系統或者外部設備 中實現。
??
??? 就基于角色訪問控制而言,訪問決策是基于角色的,個體用戶是某個組織的一部分。用戶具有指派的角色(比如醫生、護士、出納、經理)。定義角色的過程應該基于對組織運轉的徹底分析,應該包括來自一個組織中更廣范圍用戶的輸入。
???
??? 訪問權按角色名分組,資源的使用受限于授權給假定關聯角色的個體。例如,在一個醫院系統中,醫生角色可能包括進行診斷、開據處方、指示實驗室化驗等;而研究員的角色則被限制在收集用于研究的匿名臨床信息工作上。
???
??? 控制訪問角色的運用可能是一種開發和加強企業特殊安全策略,進行安全管理過程流程化的有效手段。
?????


用戶(User)和角色(Role)

??? 用戶指訪問系統中的資源的主體,一般為人,也可為 Agent 等智能程序。角色指應用領域內一種權力和責任的語義綜合體,可以是一個抽象概念,也可以是對應于實際系統中的特定語義體,比如組織內部的職務等。針對角色 屬性的不同,某些模型中將角色進一步細分為普通角色和管理員角色(可理解為全局角色)。

?

許可(Permissions)和權限(Permission)

??? 許可描述了角色對計算機資源的訪問和操作所具有的權限,其反映的是授權的結果。比如授予某個角色對計算機資源有讀的權限,則代表了一個許可的存在,這個許 可表示:角色獲取了對計算機資源的讀許可。針對操作來說,其描述的是許可和操作之間的一種關聯關系,而這層關系則表示了某一角色對某一操作所具有的權限及 權限狀態。


?????
角色和指派(Assignment)

??? 指派包含兩個方面,用戶指派和許可指派。用戶指派表示的是,將用戶指派給特定的角色。許可指派表示的是為角色指派計算機資源的訪問和操作許可。

?

會話(session)

??? 會話表示的是用戶和角色之間的關系。用戶每次必須通過建立會話來激活角色,得到相應的訪問權限。

?

角色和角色等級(Role Hierarchies)

??? 角色本身僅僅只是一個名詞,其本身并不能代表權限的大小。比如,我們可以定一個“Director”的角色,也可以定一個“Project Leader”的角色。對于現實中我們來說,看到這樣兩個角色,就清楚 DIR 的權限要比一個 PL 的權限級別高。但是對計算機來說,這兩個角色僅僅是兩個“詞語”,是等同的。可以采用分等級角色,在角色上實現層次化來解決這些問題。也可以采用復合角色 (其表示的就是一個角色組的概念),對角色實現一定的分組和復合,以便于權限指派。在一些 OA 產品中經常出現分等級角色。
???


限制(Constraints)
???
??? 模型中的職責分離關系(Separation of Duty),用于控制沖突(Conflict)。靜態職責分離(Static SD)指定角色的互斥關系,用于用戶指派階段。避免同一用戶擁有互斥的角色。實現簡單,角色互斥語義關系清楚,便于管理不夠靈活,不能處理某些實際情況。 動態職責分離(Dynamic SD)指定角色的互斥關系,用于角色激活階段。允許同一用戶擁有某些互斥的角色,但是不允許該用戶同時激活互斥的角色。更靈活,直接與會話掛鉤,適應實際 管理需要,實現復雜,不易管理。

?????????????

?

?

參考文獻

《AN INTRODUCTION TO ROLE-BASED ACCESS CONTROL》 NIST

《工作流授權控制模型》??????? 胡長城

《基于角色的權限管理綜述》 俞詩鵬

?

?

最后,感謝宏云博士對本文翻譯提供的指導。???


請注意!引用、轉貼本文應注明原作者:Rosen Jiang 以及出處:http://www.oiklr.tw/rosen



Alex 2006-10-26 21:31 發表評論
]]>
[zt]Java 學習方法淺談 http://www.oiklr.tw/alex/archive/2006/09/20/70747.htmlAlexAlexWed, 20 Sep 2006 04:12:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/20/70747.htmlhttp://www.oiklr.tw/alex/comments/70747.htmlhttp://www.oiklr.tw/alex/archive/2006/09/20/70747.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/70747.htmlhttp://www.oiklr.tw/alex/services/trackbacks/70747.html轉自 robin

Java本身是一種設計的非常簡單,非常精巧的語言,所以Java背后的原理也很簡單,歸結起來就是兩點:

1、JVM的內存管理

理解了這一點,所有和對象相關的問題統統都能解決

2、JVM Class Loader

理解了這一點,所有和Java相關的配置問題,包括各種App Server的配置,應用的發布問題統統都能解決

就像張無忌學太極劍,本質就是一圈一圈的畫圓,你要是懂得了太極劍的本質,那么太極劍就那么一招而已,本身是很容易學的,只是難度在于你要能夠舉一 反三,化一式劍意為無窮無盡的劍招,這就需要一點悟性和不斷的實踐了;反過來說,如果學劍不學本質,光學劍招,你就是學會了1萬招,碰到了第1萬零1招, 還是不會招架,敗下陣來。

技術世界本來就是豐富多彩,企圖統一標準,實際上也做不到,但是世界本質其實并不復雜。學習技術,特別是某種具體的軟件工具的時候,應該學會迅速把 握事物的本質,不要過多攪纏細節。軟件工具應該為我所用,而不是我被工具所駕馭。當你具備了對整個J2EE架構的設計和實施的能力,你還會被具體的工具束 縛嗎?哪種工具適合你的架構,你就用什么,哪種不適合你,你就拋棄它,軟件皆臣服于你的腳下,而不是你被什么軟件牽著鼻子走,到了這種程度,你難道還害怕 學習什么新的軟件?

我自己也在一直朝著這個方向努力,在我心中,設計軟件,架構是第一位的,采用什么技術要為架構服務。如果我發現什么技術對我的架構來說很重要,那么 我會花時間去學習,去鉆研,就像我花時間去鉆研ORM一樣,如果我覺得什么技術對我的架構來說沒有用,即使技術再火爆,我也不去碰它

總之要學會抓住本質,駕馭技術,而不是被技術所駕馭。當你掌握了本質原理,其實學什么都很快,畢竟都是相通的,我先看JDO,后看 Hibernate,其實兩者就很類似,所以學得很快,以后如果有工作需要,要我學習別的ORM,那我也不會覺得有什么困難的,一樣手到拿來。

更有說服力的是Unix類的操作系統,那就更相似了,只要抓住了Unix最本質的幾點,例如shell命令和編程,文件系統結構和配置,系統啟動原 理和過程,所有的Unix都是無師自通的。我自己會用Linux,FreeBSD,SCO Unix, Solaris,HP-UX 和 AIX等6種Unix,更體會到一通百通的道理。

拿剛出了光明頂密道的張無忌來說吧,(我很喜歡張無忌這個角色),他也沒有練過什么武功,但是他已經把天下武學之本質:九陽神功 + 乾坤大挪移學會了,所以不管什么功夫,他都是看一遍就會,馬上為我所用,看了空性用了一遍龍爪手,就會用龍爪手來破對方;和昆侖派打了一架,就會用昆侖劍 法和滅絕師太過招;七傷拳更是無師自通;太極拳也是看一遍就會。

總之,學習方法還是很重要,別被五花八門的技術給搞不清學習方向了。



Alex 2006-09-20 12:12 發表評論
]]>
[zt]Effective Java讀書筆記http://www.oiklr.tw/alex/archive/2006/09/11/69002.htmlAlexAlexMon, 11 Sep 2006 10:14:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/11/69002.htmlhttp://www.oiklr.tw/alex/comments/69002.htmlhttp://www.oiklr.tw/alex/archive/2006/09/11/69002.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/69002.htmlhttp://www.oiklr.tw/alex/services/trackbacks/69002.html閱讀全文

Alex 2006-09-11 18:14 發表評論
]]>
web開發的瑞士軍刀 javawebpartshttp://www.oiklr.tw/alex/archive/2006/09/08/68600.htmlAlexAlexFri, 08 Sep 2006 13:18:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/08/68600.htmlhttp://www.oiklr.tw/alex/comments/68600.htmlhttp://www.oiklr.tw/alex/archive/2006/09/08/68600.html#Feedback6http://www.oiklr.tw/alex/comments/commentRss/68600.htmlhttp://www.oiklr.tw/alex/services/trackbacks/68600.html閱讀全文

Alex 2006-09-08 21:18 發表評論
]]>
用Digester解析xml到beanhttp://www.oiklr.tw/alex/archive/2006/09/06/68148.htmlAlexAlexWed, 06 Sep 2006 15:32:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/06/68148.htmlhttp://www.oiklr.tw/alex/comments/68148.htmlhttp://www.oiklr.tw/alex/archive/2006/09/06/68148.html#Feedback6http://www.oiklr.tw/alex/comments/commentRss/68148.htmlhttp://www.oiklr.tw/alex/services/trackbacks/68148.html
假設有下列xml文件:
<?xml?version='1.0'?encoding='utf-8'?>
<address-book>
????
<contact?myType="individual">
????????
<name>Zane?Pasolini</name>
????????
<address>999?W.?Prince?St.</address>
????????
<city>New?York</city>
????????
<province>NY</province>
????????
<postalcode>10013</postalcode>
????????
<country>USA</country>
????????
<telephone>1-212-345-6789</telephone>
????
</contact>
????
<contact?myType="business">
????????
<name>SAMOFIX?d.o.o.</name>
????????
<address>Ilica?47-2</address>
????????
<city>Zagreb</city>
????????
<province></province>
????????
<postalcode>10000</postalcode>
????????
<country?from="cn">Croatia</country>
????????
<telephone>385-1-123-4567</telephone>
????
</contact>
</address-book>

這是一份常用到的文件,現在我們需要將之映射到java bean,用Digester解析顯得非常簡單
public?class?AddressBookParser
{
????
/**
?????*?Prints?the?contact?information?to?standard?output.
?????*
?????*?
@param?contact?the?<code>Contact</code>?to?print?out
?????
*/
????
public?void?addContact(Contact?contact)
????{
????????System.out.println(
"TYPE:?"?+?contact.getType());
????????System.out.println(
"NAME:?"?+?contact.getName());
????????System.out.println(
"????ADDRESS:????"?+?contact.getAddress());
????????System.out.println(
"????CITY:???????"?+?contact.getCity());
????????System.out.println(
"????PROVINCE:???"?+?contact.getProvince());
????????System.out.println(
"????POSTALCODE:?"?+?contact.getPostalcode());
????????System.out.println(
"????COUNTRY:????"?+?contact.getCountry());
????????System.out.println(
"????COUNTRY-From:????"?+?contact.getCountryFrom());
????????System.out.println(
"????TELEPHONE:??"?+?contact.getTelephone());
????}

????
/**
?????*?Configures?Digester?rules?and?actions,?parses?the?XML?file?specified
?????*?as?the?first?argument.
?????*
?????*?
@param?args?command?line?arguments
?????
*/
????
public?static?void?main(String[]?args)?throws?IOException,?SAXException
????{
????????
//?instantiate?Digester?and?disable?XML?validation
????????Digester?digester?=?new?Digester();
????????digester.setValidating(
false);

????????
//?instantiate?AddressBookParser?class
????????digester.addObjectCreate("address-book",?AddressBookParser.class?);
????????
//?instantiate?Contact?class
????????digester.addObjectCreate("address-book/contact",?Contact.class?);

????????
//?set?type?property?of?Contact?instance?when?'type'?attribute?is?found
????????
//對有屬性的值通過setProperties方法

????????digester.addSetProperties(
"address-book/contact",?????????"myType",?"type"?);

????????
//?set?different?properties?of?Contact?instance?using?specified?methods
????????
//addCallMethod與addBeanPropertySetter等價
????????
//?參數?0代表一個參數,默認就是當前讀的數據

????????digester.addCallMethod(
"address-book/contact/name",???????"setName",?0);
????????digester.addCallMethod(
"address-book/contact/address",????"setAddress",?0);
????????digester.addCallMethod(
"address-book/contact/address",????"setAddress",0);
????????digester.addCallMethod(
"address-book/contact/city",???????"setCity",?0);
????????digester.addCallMethod(
"address-book/contact/province",???"setProvince",?0);
????????digester.addCallMethod(
"address-book/contact/postalcode",?"setPostalcode",?0);
????????digester.addCallMethod(
"address-book/contact/country",????"setCountry",?0);



????????
//增加country的屬性?:?from
????????digester.addSetProperties("address-book/contact/country","from","countryFrom");
????????digester.addCallMethod(
"address-book/contact/telephone",??"setTelephone",?0);

????????
//?call?'addContact'?method?when?the?next?'address-book/contact'?pattern?is?seen
????????digester.addSetNext("address-book/contact",???????????????"addContact"?);

????????
//?now?that?rules?and?actions?are?configured,?start?the?parsing?process
????????AddressBookParser?abp?=?(AddressBookParser)?digester.parse(new?File("c:\\addressbook.xml"));
????}

????
/**
?????*?JavaBean?class?that?holds?properties?of?each?Contact?entry.
?????*?It?is?important?that?this?class?be?public?and?static,?in?order?for
?????*?Digester?to?be?able?to?instantiate?it.
?????
*/
????
public?static?class?Contact
????{
????????
private?String?type;
????????
private?String?name;
????????
private?String?address;
????????
private?String?city;
????????
private?String?province;
????????
private?String?postalcode;
????????
private?String?country;
??????? //增加一個country的屬性:?from
????????private?String?countryFrom;
????????private?String?telephone;

????????
public?void?setType(String?newType)
????????{
????????????type?
=?newType;
????????}
????????
public?String?getType()
????????{
????????????
return?type;
????????}

????????
public?void?setName(String?newName)
????????{
????????????name?
=?newName;
????????}
????????
public?String?getName()
????????{
????????????
return?name;
????????}

????????
public?void?setAddress(String?newAddress)
????????{
????????????address?
=?newAddress;
????????}
????????
public?String?getAddress()
????????{
????????????
return?address;
????????}

????????
public?void?setCity(String?newCity)
????????{
????????????city?
=?newCity;
????????}
????????
public?String?getCity()
????????{
????????????
return?city;
????????}

????????
public?void?setProvince(String?newProvince)
????????{
????????????province?
=?newProvince;
????????}
????????
public?String?getProvince()
????????{
????????????
return?province;
????????}

????????
public?void?setPostalcode(String?newPostalcode)
????????{
????????????postalcode?
=?newPostalcode;
????????}
????????
public?String?getPostalcode()
????????{
????????????
return?postalcode;
????????}

????????
public?void?setCountry(String?newCountry)
????????{
????????????country?
=?newCountry;
????????}
????????
public?String?getCountry()
????????{
????????????
return?country;
????????}

????????
public?void?setTelephone(String?newTelephone)
????????{
????????????telephone?
=?newTelephone;
????????}
????????
public?String?getTelephone()
????????{
????????????
return?telephone;
????????}

????????
public?String?getCountryFrom()?{
????????????
return?countryFrom;
????????}

????????
public?void?setCountryFrom(String?countryFrom)?{
????????????
this.countryFrom?=?countryFrom;
????????}
????}
}


AjaxChat 中的讀取房間信息的方式顯得更簡潔
房間的xml配置文件如下:
<rooms>
??
<room?id="1"?name="General?Topics"?/>
??
<room?id="2"?name="Programming"?/>
??
<room?id="3"?name="Movies"?/>
??
<room?id="4"?name="Music"?/>
??
<room?id="5"?name="Television"?/>
</rooms>

解析代碼如下 :
public?synchronized?void?init(InputStream?isConfigFile)?{

????????log.debug(
"init()");
????????
if?(isConfigFile?!=?null)?{
????????????
//?Read?in?rooms?config?and?create?beans,?hand?off?to?DAO.
????????????Digester?digester?=?new?Digester();
????????????digester.setValidating(
false);
????????????digester.push(
this);
????????????digester.addObjectCreate(
"rooms/room",
????????????????????
"org.apache.struts.apps.ajaxchat.dto.RoomDTO");
??? ?? ?? ? //注意這里,如果xl的屬性名稱和bean的屬性名稱完全對應,則直接提供xml的位置即可
????????????digester.addSetProperties(
"rooms/room");
????????????digester.addSetNext(
"rooms/room",?"addRoom");
????????????
try?{
????????????????digester.parse(isConfigFile);
????????????????log.info(
"*****?Rooms?=?"?+?rooms);
????????????}?
catch?(IOException?ioe)?{
????????????????ioe.printStackTrace();
????????????}?
catch?(SAXException?se)?{
????????????????se.printStackTrace();
????????????}
????????}

????}?
//?End?init().

如果在xml文件中增加非attribute則更改后的配置文件如下:

<rooms>
??
<room?id="1"?name="General?Topics"?/>
??
<room?id="2"?name="Programming"?/>
??
<room?id="3"?name="Movies"?/>
??
<room?id="4"?name="Music"?/>
??
<room?id="5"?name="Television"?/>
??
<room>
????
<id>6</id>
????
<name>shit</name>
??
</room>
??
<room>
????
<id>7</id>
????
<name>haha</name>
??
</room>
</rooms>
對應的解析如下:
public?synchronized?void?init(InputStream?isConfigFile)?{

????????log.debug(
"init()");
????????
if?(isConfigFile?!=?null)?{
????????????
//?Read?in?rooms?config?and?create?beans,?hand?off?to?DAO.
????????????Digester?digester?=?new?Digester();
????????????digester.setValidating(
false);
????????????digester.push(
this);
????????????digester.addObjectCreate(
"rooms/room",
????????????????????
"org.apache.struts.apps.ajaxchat.dto.RoomDTO");
????????????digester.addSetProperties(
"rooms/room");
??? ?? ?? ? //增加addCallMethod方法
????????????digester.addCallMethod(
"rooms/room/id","setId",0);
????????????digester.addCallMethod(
"rooms/room/name","setName",0);
????????????digester.addSetNext(
"rooms/room",?"addRoom");
????????????
try?{
????????????????digester.parse(isConfigFile);
????????????????log.info(
"*****?Rooms?=?"?+?rooms);
????????????}?
catch?(IOException?ioe)?{
????????????????ioe.printStackTrace();
????????????}?
catch?(SAXException?se)?{
????????????????se.printStackTrace();
????????????}
????????}

????}?
//?End?init().



Alex 2006-09-06 23:32 發表評論
]]>
[zt]Struts國際化處理http://www.oiklr.tw/alex/archive/2006/09/05/67905.htmlAlexAlexTue, 05 Sep 2006 14:22:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/05/67905.htmlhttp://www.oiklr.tw/alex/comments/67905.htmlhttp://www.oiklr.tw/alex/archive/2006/09/05/67905.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/67905.htmlhttp://www.oiklr.tw/alex/services/trackbacks/67905.html

一、Struts的國際化
??? Struts是一種支持國際化的MVC的Web Framework。可是如何來使用struts國際化是一個問題。下面我們來探討一下,如何實現Struts的國際化。Web程式的國際化涉及到3個層面的東西。第一、jsp部分的輸入/輸出;第二、應用處理程序的國際化;第三、DB的國際化問題。這里主要探討的是jsp部分的輸入/輸出問題。

二、靜態部分的國際化
?? Struts的jsp頁面靜態內容(包括靜態文字,靜態圖片)國際化問題,是通過資源文件來實現的。要實現國際化,需要做如下幾項工作:1、定義web.xml的動ActionServlet的參數;2、定義資源文件;3、定義JSP頁面的字符集合;4、在JSP頁面獲取資源文件里面的內容。
1、定義web.xml的動ActionServlet的參數

<servlet>
??
<servlet-name>action</servlet-name>
??
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>???
??
<init-param>
????
<param-name>config</param-name>
????
<param-value>/WEB-INF/struts-config.xml</param-value>
??
</init-param>
??
<init-param>
????
<param-name>application</param-name>
????
<param-value>ApplicationResources</param-value>?<!--?默認資源文件名?-->
??
</init-param>
??
<load-on-startup>2</load-on-startup>
</servlet>

2、定義資源文件
在/WEB-INF/classes下面添加UTF-8資源束文件。每一個資源文件是“鍵-值”對的集合。在JSP頁面里面可以通過鍵來找到相應的數據值。本例子的文件名是ApplicationResources,所以相應的資源文件束是(包括e文,簡體中文,繁體中文)
ApplicationResources.properties : 默認資源文件。當在其他資源文件里面找不到某個資源的時候,就使用該資源文件里面的定義。
ApplicationResources_zh_CN.properties:簡體中文資源文件。
ApplicationResources_zh_TW.properties:繁體中文資源文件。

資源文件的格式為:默認資源文件名_國別_語言.properties。其中每個文件都是通過%JAVA_HONE%/BIN/native2ascii.exe工具轉換而來。你也可以使用其他工具來處理得到(http://java.sun.com/products/jilkit/ 有一個工具Internationalization Java Internationalization and Localization Toolkit 可以處理)。下面是一個例子,我們顯示如何使用%JAVA_HONE%/BIN/native2ascii.exe命令來定義資源束文件。
2.1 準備文件
//ApplicationResources.properties ;默認資源文件,通常里面的內容是英文的。
label.username=USERNAME :
label.password=PASSWORD :

//ApplicationResources_zh_CN.bak ;簡體中文的資源文件。里面的內容是中文的。它需要工具將其中的內容處理成UTF-8
label.username=用戶名 :
label.password=密? 碼 :

//ApplicationResources_zh_TW.bak : 繁體中文的資源文件。里面的內容是中文的。它需要工具將其中的內容處理成UTF-8,下面的內容是繁體碼。
label.username=ノめ?W :
label.password=ノめ?W :

2.2 準備完成以后,使用如下的命令創建UTF-8資源文件束
native2ascii -encoding gb2312 ApplicationResources_zh_CN.bak ApplicationResources_zh_CN.properties
native2ascii -encoding big5 Applica tionResources_zh_TW.bak ApplicationResources_zh_TW.properties

3、定義JSP頁面的字符集合
定義JSP頁面的語言為UTF-8。在每個JSP頁面,必須有如下的內容(如果使用的模板技術,則只是需要在模板頁面添加,其他使用該模板的頁面無需添加)
<%@ page contentType="text/html;charset=UTF-8"%>

4、在JSP頁面獲取資源文件里面的內容。
在JSP里面需要顯示靜態內容的地方使用<bean:message />strus的bean tag包里面的message標簽。例如下面的頁面

<table>
? <tr>
??? <td align="right"><bean:message key="label.username" /></td>???
? </tr>
? <tr>
??? <td align="right"><bean:message key="label.password" /></td>
? </tr>
</table>

好了,在這個頁面顯示的時候,如果客戶的IE的語言集合是zh_CN的話,就會顯示
用戶名:
口? 令:

如果是客戶的IE的語言是zh_TW的話,就會顯示
用戶名:
用戶名:

可以在IE的工具->Internet選項->語言的地方,來選擇,定義IE的語言。

三、表單的數據的處理。
對于表單數據的處理,我們是通過添加一個Filter來實現的。所有提交的請求,都需要做字符處理。然后在web.xml里面定義該Filter。這樣我們就不需要在程序里面做任何的字符處理。
3.1 定義Filter。下面是一個例子。
package com.webapps.commons;

import java.io.*;
import javax.servlet.*;

public class CharsetEncodingFilter implements Filter{
? private FilterConfig config = null;
? private String defaultEncode = "UTF-8";

? public void init(FilterConfig config) throws ServletException {
??? this.config = config;
??? if(config.getInitParameter("Charset")!=null){
??????? defaultEncode=config.getInitParameter("Charset");
??? }
? }

? public void destroy() {
??? this.config = null;
? }

? public void doFilter(ServletRequest request, ServletResponse response,
?????????????????????? FilterChain chain) throws IOException, ServletException {
??? ServletRequest srequest=request;
??? srequest.setCharacterEncoding(defaultEncode);
??? chain.doFilter(srequest,response);
? }
}

3.2 在web.xml里面聲明使用該Filter
<filter>
? <filter-name>Character Encoding</filter-name>
? <filter-class>com.webapps.commons.CharsetEncodingFilter</filter-class>
</filter>
<filter-mapping>
? <filter-name>Character Encoding</filter-name>
? <url-pattern>/*</url-pattern>
</filter-mapping>

四、擴展
待續的是應用程序部分的國際化問題,和DB的國際化問題。




Alex 2006-09-05 22:22 發表評論
]]>
[zt]使用 AppFuse 的七個理由http://www.oiklr.tw/alex/archive/2006/09/04/67669.htmlAlexAlexMon, 04 Sep 2006 12:34:00 GMThttp://www.oiklr.tw/alex/archive/2006/09/04/67669.htmlhttp://www.oiklr.tw/alex/comments/67669.htmlhttp://www.oiklr.tw/alex/archive/2006/09/04/67669.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/67669.htmlhttp://www.oiklr.tw/alex/services/trackbacks/67669.html

使用 AppFuse 的七個理由

學習 Java 開放源碼工具 —— 并使用這些工具提高生產效率


級別: 初級

Matt Raible (mraible@virtuas.com), 開放源碼實踐先驅, Virtuas Open Source Solutions

2006 年 8 月 31 日

開 始學習在 Java? 平臺上使用諸如 Spring、Hibernate 或 MySQL 之類的開放源碼工具時可能非常困難。再加上 Ant 或 Maven,以及與 DWR 一起的小 Ajax,還有 Web 框架 —— 即 JSF,我們必須睜大眼睛盯著如何配置應用程序。AppFuse 減少了集成開放源碼項目的痛苦。它可以把測試變成一等公民,讓我們可以從數據庫表生成整個 UI,并使用 XFire 來支持 Web 服務。另外,AppFuse 的社區也非常健全,這是不同 Web 框架用戶可以一起融洽相處的地方之一。

AppFuse 是一個開放源碼的項目和應用程序,它使用了在 Java 平臺上構建的開放源碼工具來幫助我們快速而高效地開發 Web 應用程序。我最初開發它是為了減少在為客戶構建新 Web 應用程序時所花費的那些不必要的時間。從核心上來說,AppFuse 是一個項目骨架,類似于通過向導創建新 Web 項目時 IDE 所創建的東西。當我們使用 AppFuse 創建一個項目時,它會提示我們將使用開放源碼框架,然后才創建項目。它使用 Ant 來驅動測試、代碼生成、編譯和部署。它提供了目錄和包結構,以及開發基于 Java 語言的 Web 應用程序所需要的庫。

與大部分 “new project” 向導不同,AppFuse 創建的項目從最開始就包含很多類和文件。這些文件用來實現特性,不過它們同時也會在您開發應用程序時被用作示例。通過使用 AppFuse 啟動新項目,我們通常可以減少一到兩周的開發時間。我們不用擔心如何將開放源碼框架配置在一起,因為這都已經完成了。我們的項目都已提前配置來與數據庫進 行交互,它會部署到應用服務器上,并對用戶進行認證。我們不必實現安全特性,因為這都早已集成了。

當我最初開發 AppFuse 時,它只支持 Struts 和 Hibernate。經過幾年的努力,我發現了比 Struts 更好的 Web 框架,因此我還添加了為這些 Web 框架使用的選項。現在,AppFuse 可以支持 Hibernate 或 iBATIS 作為持久性框架。對于 Web 框架來說,我們可以使用 JavaServer Faces(JSF)、Spring MVC、Struts、Tapestry 或 WebWork。

AppFuse 提供了很多應用程序需要的一些特性,包括:

  • 認證和授權
  • 用戶管理
  • Remember Me(這會保存您的登錄信息,這樣就不用每次都再進行登錄了)
  • 密碼提醒
  • 登記和注冊
  • SSL 轉換
  • E-mail
  • URL 重寫
  • 皮膚
  • 頁面修飾
  • 模板化布局
  • 文件上載

這種 “開箱即用” 的功能是 AppFuse 與其他 CRUD 代 框架的區別之一(CRUD 取自創建、檢索、更新刪除 幾個操作的英文首字母),包括 Ruby on Rails、Trails 和 Grails。上面提到的這些框架,以及 AppFuse,都讓我們可以從數據庫表或現有的模型對象中生成主頁/細節頁。

圖 1 闡述了一個典型 AppFuse 應用程序的概念設計:


圖 1. 典型的 AppFuse 應用程序
典型的 AppFuse 應用程序

清單 1 給出了我們在創建 devworks 項目時所使用的命令行交互操作,同時還給出了所生成的結果。這個項目使用了 WebWork 作為自己的 Web 框架(請參考下面 參考資料 一節給出的鏈接)。


清單 1. 使用 AppFuse 創建新項目
alotta:~/dev/appfuse mraible$ ant new
Buildfile: build.xml

clean:
[echo] Cleaning build and distribution directories

init:

new:
[echo]
[echo] +-------------------------------------------------------------+
[echo] | -- Welcome to the AppFuse New Application Wizard! -- |
[echo] | |
[echo] | To create a new application, please answer the following |
[echo] | questions. |
[echo] +-------------------------------------------------------------+

[input] What would you like to name your application [myapp]?
devworks
[input] What would you like to name your database [mydb]?
devworks
[input] What package name would you like to use [org.appfuse]?
com.ibm
[input] What web framework would you like to use [webwork,tapestry,spring,js
f,struts]?
webwork
[echo] Creating new application named 'devworks'...
[copy] Copying 359 files to /Users/mraible/Work/devworks
[copy] Copying 181 files to /Users/mraible/Work/devworks/extras
[copy] Copying 1 file to /Users/mraible/Work/devworks
[copy] Copying 1 file to /Users/mraible/Work/devworks

install:
[echo] Copying WebWork JARs to ../../lib
[copy] Copying 6 files to /Users/mraible/Work/devworks/lib
[echo] Adding WebWork entries to ../../lib.properties
[echo] Adding WebWork classpath entries
[echo] Removing Struts-specific JARs
[delete] Deleting directory /Users/mraible/Work/devworks/lib/struts-1.2.9
[delete] Deleting directory /Users/mraible/Work/devworks/lib/strutstest-2.1.3
[echo] Deleting struts_form.xdt for XDoclet
[delete] Deleting directory /Users/mraible/Work/devworks/metadata/templates
[echo] Deleting Struts merge-files in metadata/web
[delete] Deleting 7 files from /Users/mraible/Work/devworks/metadata/web
[echo] Deleting unused Tag Libraries and Utilities
[delete] Deleting 2 files from /Users/mraible/Work/devworks/src/web/org/appfu
se/webapp
[echo] Modifying appgen for WebWork
[copy] Copying 12 files to /Users/mraible/Work/devworks/extras/appgen
[echo] Replacing source and test files
[delete] Deleting directory /Users/mraible/Work/devworks/src/web/org/appfuse/
webapp/form
[delete] Deleting directory /Users/mraible/Work/devworks/src/web/org/appfuse/
webapp/action
[copy] Copying 13 files to /Users/mraible/Work/devworks/src
[delete] Deleting directory /Users/mraible/Work/devworks/test/web/org/appfuse
/webapp/form
[delete] Deleting directory /Users/mraible/Work/devworks/test/web/org/appfuse
/webapp/action
[copy] Copying 5 files to /Users/mraible/Work/devworks/test
[echo] Replacing web files (images, scripts, JSPs, etc.)
[delete] Deleting 1 files from /Users/mraible/Work/devworks/web/scripts
[copy] Copying 34 files to /Users/mraible/Work/devworks/web
[delete] Deleting: /Users/mraible/Work/devworks/web/WEB-INF/validator-rules-c
ustom.xml
[echo] Modifying Eclipse .classpath file
[echo] Refactoring build.xml
[echo] ----------------------------------------------
[echo] NOTE: It's recommended you delete extras/webwork as you shouldn't ne
ed it anymore.
[echo] ----------------------------------------------
[echo] Repackaging info written to rename.log
[echo]
[echo] +-------------------------------------------------------------+
[echo] | -- Application created successfully! -- |
[echo] | |
[echo] | Now you should be able to cd to your application and run: |
[echo] | > ant setup test-all |
[echo] +-------------------------------------------------------------+

BUILD SUCCESSFUL
Total time: 15 seconds

為什么使用 WebWork?
Struts 社區最近在熱情地擁抱 WebWork,這種結合導致為 Java 平臺提供了一個非常優秀的新 Web 框架:Struts 2。當然,Spring MVC 是一個非常優秀的基于請求的框架,但是它不能像 Struts 2 一樣支持 JSF。基于內容的框架(例如 JSF 和 Tapestry)也都很好,但是我發現 WebWork 更為直觀,更容易使用(更多有關 Structs 2 和 JSF 的內容請參看 參考資料)。

在創建一個新項目之后,我們就得到了一個類似于圖 2 所示的目錄結構。Eclipse 和 Intellij IDEA 項目文件都是作為這個過程的一部分創建的。


圖 2. 項目的目錄結構
項目的目錄結構

這個目錄結構與 Sun 為 Java 2 Platform Enterprise Edition(J2EE)Web 應用程序推薦的目錄結構非常類似。在 2.0 版本的 AppFuse 中,這個結構會變化成適合 Apache Maven 項目的標準目錄結構(有關這兩個目錄介紹的內容,請參看 參考資料 中的鏈接)。AppFuse 還會從 Ant 遷移到 Maven 2 上,從而獲得相關下載的能力和對生成 IDE 項目文件的支持。目前基于 Ant 的系統要求提交者維護項目文件,而 Maven 2 可以通過簡單地使用項目的 pom.xml 文件生成 IDEA、Eclipse 和 NetBeans 項目文件。(這個文件位于您項目的根目錄中,是使用 Maven 構建應用程序所需要的主要組件)。它與利用 Ant 所使用的 build.xml 文件非常類似。)

現在我們對 AppFuse 是什么已經有一點概念了,在本文剩下的部分中,我們將介紹使用 AppFuse 的 7 點理由。即使您選擇不使用 AppFuse 來開始自己的項目,也會看到 AppFuse 可以為您提供很多樣板代碼,這些代碼可以在基于 Java 語言的 Web 應用程序中使用。由于它是基于 Apache 許可證的,因此非常歡迎您在自己的應用程序中重用這些代碼。

理由 1:測試

測試是在軟件開發項目中很少被給予足夠信任的一個環節。注意我并不是說在軟件開發的一些刊物中沒有得到足夠的信任!很多文章和案例研究都給出了測試 優先的開發方式和足夠的測試覆蓋面以提高軟件的質量。然而,測試通常都被看作是一件只會延長項目開發時間的事情。實際上,如果我們使用測試優先的方法在編 寫代碼之前就開始撰寫測試用例,我相信我們可以發現這實際上會加速 開發速度。另外,測試優先也可以使維護和重用更加 容易。如果我們不編寫代碼來測試自己的代碼,那么就需要手工對應用程序進行測試 —— 這通常效率都不高。自動化才是關鍵。

當我們首次開始使用 AppFuse 時,我們可能需要閱讀這個項目 Web 站點上提供的快速入門指南和教程(請參看 參考資料 中的鏈接)。這些教程的編寫就是為了您可以首先編寫測試用例;它們直到編寫接口和/或實現之后才能編譯。如果您有些方面與我一樣,就會在開始編寫代碼之前 就已經編寫好測試用例了;這是真正可以加速編寫代碼的惟一方式。如果您首先編寫了代碼的實現,通過某種方式驗證它可以工作,那么您可能會對自己說,“哦, 看起來不錯 —— 誰需要測試呢?我還有更多的代碼需要編寫!”這種情況不幸的一面是您通常都會做一些事情 來測試自己的代碼;您簡單地跳過了可以自動化進行測試的地方。

AppFuse 的文檔展示了如何測試應用程序的所有 層次。它從數據庫層開始入手,使用了 DbUnit(請參看 參考資料)在運行測試之前提前使用數據來填充自己的數據庫。在數據訪問(DAO)層,它使用了 Spring 的 AbstractTransactionalDataSourceSpringContextTests 類(是的,這的確是一個類的名字!)來允許簡單地加載 Spring 上下文文件。另外,這個類對每個 testXXX() 方法封裝了一個事務,并當測試方法存在時進行回滾。這種特性使得測試 DAO 邏輯變得非常簡單,并且不會對數據庫中的數據造成影響。

在服務層,jMock (請參看 參考資料)用來編寫那些可以消除 DAO 依賴的真正 單元測試。這允許進行驗證業務邏輯正確的快速測試;我們不用擔心底層的持久性邏輯。

HtmlUnit 支持
HtmlUnit 團隊在 1.8 發行版中已經完成了相當多的工作來確保包可以與流行的 Ajax 框架(Prototype 和 Scriptaculous)很好地工作。

在 Web 層,測試會驗證操作(Struts/WebWork)、控件(Spring MVC)、頁面(Tapestry)和管理 bean(JSF)如我們所期望的一樣進行工作。Spring 的 spring-mock.jar 可以非常有用地用來測試所有這些框架,因為它包含了一個 Servlet API 的仿真實現。如果沒有這個有用的庫,那么測試 AppFuse 的 Web 框架就會變得非常困難。

UI 通常是開發 Web 應用程序過程中最為困難的一部分。它也是顧客最經常抱怨的地方 —— 這既是由于它并不是非常完美,也是由于它的工作方式與我們期望的并不一樣。另外,沒有什么會比在客戶面前作演示的過程中看到看到異常堆棧更糟糕的了!您的 應用程序可能會非常可怕,但是客戶可能會要求您做到十分完美。永遠不要讓這種事情發生。Canoo WebTest 可以對 UI 進行測試。它使用了 HtmlUnit 來遍歷測試 UI,驗證所有的元素都存在,并可以填充表單的域,甚至可以驗證一個假想的啟用 Ajax 的 UI 與我們預期的工作方式一樣。(有關 WebTest 和 HTMLUnit 的鏈接請參看 參考資料。)

為了進一步簡化 Web 的測試,Cargo(請參看 參考資料)對 Tomcat 的啟動和停止(分別在運行 WebTest 測試之前和之后)進行了自動化。





理由 2:集成

正如我在本文簡介中提到的一樣,很多開放源碼庫都已經預先集成到 AppFuse 中了。它們可以分為以下幾類:

  • 編譯、報告和代碼生成:Ant、Ant Contrib Tasks、Checkstyle、EMMA、Java2Html、PMD 和 Rename Packages
  • 測試框架:DbUnit、Dumbster、jMock、JUnit 和 Canoo WebTest
  • 數據庫驅動程序:MySQL 和 PostgreSQL
  • 持久性框架:Hibernate 和 iBATIS
  • IoC 框架:Spring
  • Web 框架:JSF、Spring MVC、Struts、Tapestry 和 WebWork
  • Web 服務:XFire
  • Web 工具:Clickstream、Display Tag、DWR、JSTL、SiteMesh、Struts Menu 和 URL Rewrite Filter
  • Security:Acegi Security
  • JavaScript 和 CSS:Scriptaculous、Prototype 和 Mike Stenhouse 的 CSS Framework

除了這些庫之外,AppFuse 還使用 Log4j 來記錄日志,使用 Velocity 來構建 e-mail 和菜單模板。Tomcat 可以支持最新的開發,我們可以使用 1.4 或 5 版本的 Java 平臺來編譯或構建程序。我們應該可以將 AppFuse 部署到任何 J2EE 1.3 兼容的應用服務器上;這已經經過了測試,我們知道它在所有主要版本的 J2EE 服務器和所有主要的 servlet 容器上都可以很好地工作。

圖 3 給出了上面創建的 devworks 項目的 lib 目錄。這個目錄中的 lib.properties 文件控制了每個依賴性的版本號,這意味著我們可以簡單地通過把這些包的新版本放到這個目錄中并執行諸如 ant test-all -Dspring.version=2.0 之類的命令來測試這些包的新版本。


圖 3. 項目依賴性
AppFuse 項目依賴性

預先集成這些開放源碼庫可以在項目之初極大地提高生產效率。盡管我們可以找到很多文檔介紹如何集成這些庫,但是定制工作示例并簡單地使用它來開發應用程序要更加簡單。

除了可以簡化 Web 應用程序的開發之外,AppFuse 讓我們還可以將 Web 服務簡單地集成到自己的項目中。盡管 XFire 也在 AppFuse 下載中一起提供了,不過如果我們希望,也可以自己集成 Apache Axis(請參看 參考資料 中有關 Axis 集成的教程)。另外,Spring 框架和 XFire 可以一起將服務層作為 Web 服務非常簡單地呈現出來,這就為我們提供了開發面向服務架構的能力。

另外,AppFuse 并不會將我們限定到任何特定的 API 上。它只是簡單地對可用的最佳開放源碼解決方案重新進行打包和預先集成。AppFuse 中的代碼可以處理這種集成,并實現了 AppFuse 的基本安全性和可用性特性。只要可能,就會減少代碼,以便向 AppFuse 的依賴框架添加一個特性。例如,AppFuse 自帶的 Remember Me 和 SSL 切換特性最近就因為類似的特性而從 Acegi Security 中刪除了。







理由 3:自動化

Ant 使得簡化了從編譯到構建再到部署的自動化過程。Ant 是 AppFuse 中的一等公民,這主要是因為我發現在命令行中執行操作比從 IDE 中更加簡單。我們可以使用 Ant 實現編譯、測試、部署和執行任何代碼生成的任務。

盡管這種能力對于有些人來說非常重要,但是它并不適用于所有的人。很多 AppFuse 用戶目前都使用 Eclipse 或 Intellij IDEA 來構建和測試自己的項目。在這些 IDE 中運行 Ant 的確可以工作,但是這樣做的效率通常都不如使用 IDE 內置的 JUnit 支持來運行測試效率高。

幸運的是,AppFuse 支持在 IDE 中運行測試,不過管理這種特性對于 AppFuse 開發人員來說就變得非常困難了。最大的痛苦在于 XDoclet 用來生成 Hibernate 映射文件和 Web 框架所使用的一些工件(例如 ActionForms 和 Struts 使用的 struts-config.xml)。IDE 并不知道需要生成的代碼,除非我們配置使用 Ant 來編譯它們,或者安裝了一些可以認識 XDoclet 的插件。

這種對知識的缺乏是 AppFuse 2.0 切換到 JDK 5 和 Maven 2 上的主要原因。JDK 5、注釋和 Struts 2 將讓我們可以擺脫 XDoclet。Maven 2 將使用這些生成的文件和動態類路徑來生成 IDE 項目文件,這樣對項目的管理就可以進行簡化。目前基于 Ant 的編譯系統已經為不同的層次生成了一些工件(包括 dao.jar、service.jar 和 webapp.war),因此切換到 Maven 的模型上應該是一個非常自然的調整。

除了 Ant 之外(它對于編譯、測試、部署和報告具有豐富的支持),對于 CruiseControl 的支持也構建到了 AppFuse 中。CruiseControl 是一個 Continuous Integration 應用程序,讓我們可以在源代碼倉庫中代碼發生變化時自動運行所有的測試。extras/cruisecontrol 目錄包含了我們為基于 AppFuse 的項目快速、簡單地設置 Continuous Integration 時所需要的文件。

設置 Continuous Integration 是軟件開發周期中我們首先要做的事情之一。它不但激發程序員去編寫測試用例,而且還通過 “You broke the build!” 游戲促進了團隊之間的合作和融合。







理由 4:安全特性和可擴展性

AppFuse 最初是作為我為 Apress 編寫的書籍 Pro JSP 中示例應用程序的一部分開發的。這個示例應用程序展示了很多安全特性和用于簡化 Struts 開發的特性。這個應用程序中的很多安全特性在 J2EE 的安全框圖中都不存在。使用容器管理認證(CMA)的認證方法非常簡單,但是 Remember Me、密碼提示、SSL 切換、登記和用戶管理等功能卻都不存在。另外,基于角色的保護方法功能在非 EJB 環境中也是不可能的。

最初,AppFuse 使用自己的代碼和用于 CMA 的解決方案完全實現了這些特性。我在 2004 年年初開始學習 Spring 時就聽說過有關 Acegi Security 的知識。我對 Acegi 所需要的 XML 的行數(175)與 web.xml 中所需要的 CMA 的行數(20)進行了比較,很快就決定丟棄 Acegi 了,因為它太過復雜了。

一年半之后 —— 在為另外一本書 Spring Live 中編寫了一章有關使用 Acegi Security 的內容之后 —— 我就改變了自己的想法。Acegi 的確(目 前仍然)需要很多 XML,但是一旦我們理解了這一點,它實際上是相當簡單的。當我們最終作出改變,使用 Acegi Security 的特性來全部取代 AppFuse 的特性之后,我們最終刪除了大量的代碼。類之上的類都已經沒有了,“Acegi handles that now” 中消失的部分現在全部進入了 CVS 的 Attic 中了。

Acegi Security 是 J2EE 安全模型中曾經出現過的最好模型。它讓我們可以實現很多有用的特性,這些特性在 Servlet API 的安全模型中都不存在:認證、授權、角色保護方法、Remember Me、密碼加密、SSL 切換、用戶切換和注銷。它讓我們還可以將用戶證書存儲到 XML 文件、數據庫、LDAP 或單點登錄系統(例如 Yale 的 Central Authentication Service (CAS) 或者 SiteMinder)中。

AppFuse 對很多與安全性相關的特性的實現從一開始都是非常優秀的。現在 AppFuse 使用了 Acegi Security,這些特性 —— 以及更多特性 —— 都非常容易實現。Acegi 有很多地方都可以進行擴充:這是它使用巨大的 XML 配置文件的原因。正如我們已經通過去年的課程對 Acegi 進行集成一樣,我們已經發現對很多 bean 的定義進行定制可以更加緊密地與 AppFuse 建立聯系。

Spring IoC 容器和 Acegi Security 所提供的簡單開發、容易測試的代碼和松耦合特性的組合是 AppFuse 是這么好的一種開發平臺的主要原因。這些框架都是不可插入的,允許生成干凈的可測試代碼。AppFuse 集成了很多開放源碼項目,依賴注入允許對應用程序層進行簡單的集成。







理由 5:使用 AppGen 生成代碼

有些人會將代碼生成稱為代碼氣味的散播(code smell)。在他們的觀點中,如果我們需要生成代碼,那么很可能就會做一些錯事。我傾向于這種確定自己代碼使用的模式和自動化生成代碼的能力應該稱為代碼香味的彌漫(code perfume)。如果我們正在編寫類似的 DAO、管理器、操作或控件,并且不想為它們生成代碼,那么這就需要根據代碼的氣味來生成代碼。當然,當語言可以為我們提供可以簡化任務的特性時,一切都是那么美好;不過代碼生成通常都是一個必需 —— 通常其生產率也非常高 —— 的任務。

AppFuse 中提供了一個基于 Ant 和 XDoclet 的代碼生成工具,名叫 AppGen。默認情況下,常見的 DAO 和管理器都可以允許我們對任何普通老式 Java 對象(POJO)進行 CRUD 操作,但是在 Web 層上這樣做有些困難。AppGen 有幾個特性可以用來執行以下任務:

  • (使用 Middlegen 和 Hibernate 工具)從數據庫表中生成 POJO
  • 從 POJO 生成 UI
  • 為 DAO、管理器、操作/控制器和 UI 生成測試

在運行 AppGen 時,您會看到提示說 AppGen 要從數據庫表或 POJO 中生成代碼。如果在命令行中執行 ant install-detailed,AppGen 就會安裝 POJO 特定的 DAO、管理器以及它們的測試。運行 ant install 會導致 Web 層的類重用通用的 DAO 和默認存在的管理器。

為了闡述 AppGen 是如何工作的,我們在 devworks MySQL 數據庫中創建了如清單 2 所示的表:


清單 2. 創建一個名為 cat 的數據庫表
    create table cat (
cat_id int(8) auto_increment,
color varchar(20) not null,
name varchar(20) not null,
created_date datetime not null,
primary key (cat_id)
) type=InnoDB;

在 extras/appgen 目錄中,運行 ant install-detailed。這個命令的輸出結果對于本文來說實在太長了,不過我們在清單 3 中給出了第一部分的內容:


清單 3. 運行 AppGen 的 install-detailed 目標
$ ant install-detailed
Buildfile: build.xml

init:
[mkdir] Created dir: /Users/mraible/Work/devworks/extras/appgen/build
[echo]
[echo] +-------------------------------------------------------+
[echo] | -- Welcome to the AppGen! -- |
[echo] | |
[echo] | Use the "install" target to use the generic DAO and |
[echo] | Manager, or use "install-detailed" to general a DAO |
[echo] | and Manager specifically for your model object. |
[echo] +-------------------------------------------------------+

[input] Would you like to generate code from a table or POJO? (table,pojo)
table
[input] What is the name of your table (i.e. person)?
cat
[input] What is the name, if any, of the module for your table (i.e. organization)?

[echo] Running Middlegen to generate POJO...

要對 cat 表使用這個新生成的代碼,我們需要修改 src/dao/com/ibm/dao/hibernate/applicationContext-hibernate.xml,來為 Hibernate 添加 Cat.hbm.xml 映射文件。清單 3 給出了我們修改后的 sessionFactory bean 的樣子:


清單 4. 將 Cat.hbm.xml 添加到 sessionFactory bean 中
    <bean id="sessionFactory" class="...">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>com/ibm/model/Role.hbm.xml</value>
<value>com/ibm/model/User.hbm.xml</value>
<value>com/ibm/model/Cat.hbm.xml</value>
</list>
</property>
...
</bean>

在運行 ant setup deploy 之后,我們就應該可以在部署的應用程序中對 cat 表執行 CRUD 操作了:


圖 4. Cat 列表
所生成的主屏幕

圖 5. Cat 表單
所生成的詳細屏幕

我們在上面的屏幕快照中看到的記錄都是作為代碼生成的一部分創建的,因此現在就有測試數據了。








理由 6:文檔

我們可以找到 AppFuse 各個風味的教程,并且它們都以 6 種不同的語言給出了:中文、德語、英語、韓語、葡萄牙語和西班牙語。使用風味(flavor) 一詞,我的意思是不同框架的組合,例如 Spring MVC 加上 iBATIS、Spring MVC 加上 Hibernate 或 JSF 加上 Hibernate。使用這 5 種 Web 框架和兩種持久框架,可以有好幾種組合。有關它們的翻譯,AppFuse 為自己的默認特性提供了 8 種翻譯。可用語言包括中文、荷蘭語、德語、英語、法語、意大利語、葡萄牙語和西班牙語。

除了核心教程之外,還添加了很多教程(請參看 參考資料) 來介紹與各種數據庫、應用服務器和其他開放源碼技術(包括 JasperReports、Lucene、Eclipse、Drools、Axis 和 DWR)的集成。





理由 7:社區

Apache 軟件基金會對于開放源碼有一個有趣的看法。它對圍繞開放源碼項目開發一個開放源碼社區最感興趣。它的成員相信如果社區非常強大,那么產生高質量的代碼就是一個自然的過程。下面的內容引自 Apache 主頁:

“我們認為自己不僅僅是一組共享服務器的項目,而且是一個開發人員和用戶的社區。”

AppFuse 社區從 2003 年作為 SourceForge 上的一個項目(是 struts.sf.net 的一部分)啟動以來,已經獲得了極大的增長。通過在 2004 年 3 月轉換到 java.net 上之后,它已經成為這里一個非常流行的項目,從 2005 年 1 月到 3 月成為訪問量最多的一個項目。目前它仍然是一個非常流行的項目(有關 java.net 項目統計信息的鏈接,請參看 參考資料),不過在這個站點上它正在讓位于 Sun 贊助的很多項目。

在 2004 年年末,Nathan Anderson 成為繼我之后第一個提交者。此后有很多人都加入了進來,包括 Ben Gill、David Carter、Mika G?ckel、Sanjiv Jivan 和 Thomas Gaudin。很多現有的提交者都已經通過各種方式作出了自己的貢獻,他們都幫助 AppFuse 社區成為一個迅速變化并且非常有趣的地方。

郵件列表非常友好,我們試圖維護這樣一條承諾 “沒有問題是沒有人理會的問題”。我們的郵件列表歸檔文件中惟一一條 “RTFM” 是從用戶那里發出的,而不是從開發者那里發出的。我們絕對信奉 Apache 開放源碼社區的哲學。引用我最好的朋友 Bruce Snyder 的一句話,“我們為代碼而來,為人們而留下”。目前,大部分開發者都是用戶,我們通常都喜歡有一段美妙的時間。另外,大部分文檔都是由社區編寫的;因此, 這個社區的知識是非常淵博的。







結束語

我們應該嘗試使用 AppFuse 進行開發,這是因為它允許我們簡單地進行測試、集成、自動化,并可以安全地生成 Web 應用程序。其文檔非常豐富,社區也非常友好。隨著其支撐框架越來越好,AppFuse 也將不斷改進。

從 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 中對這些類簡單地進行擴展,這應該會大大簡化它的升級過程,并鼓勵更多用戶將自己希望的改進提交到這個項目中。

如果沒有其他問題,使用 AppFuse 可以讓您始終處于 Java Web 開發的技術前沿上 —— 就像我們一樣!







參考資料

學習

獲得產品和技術
  • AppFuse on java.net:下載不同風味的 AppFuse。

  • WebWork:了解這個易于使用的 Web 框架。

  • DbUnit:查看更多有關 JUnit 擴展的內容。

  • jMock:創建動態仿真對象來簡化真正的單元測試。

  • Canoo WebTest:自動化 Web 應用程序的 UI 測試。

  • HtmlUnit:WebTest 的優秀 JavaScript 支持背后的基礎。

  • Cargo:自動啟動和停止容器。

  • Greenbox:一種代碼生成框架。


討論






關于作者

Matt Raible 居住在美國科羅拉多州的丹佛,他在那里是 Spring 和 Web 框架對 Virtuas Open Source Solutions 的實踐先驅。他在開放源碼領域具有豐富的經驗,是這個領域的專家。他在這個領域中既是用戶,又是一名開發人員。Matt 是 SourceBeat PublishingSpring Live 的作者。他還為 Apress 的書籍 Pro JSP Third Edition 作出了很大的貢獻。他是很多開放源碼會議的積極倡導者,包括 ApacheCon、MySQL User's Conference 和 OSCON,同時他還是 http://raibledesigns.com 上一名非常活躍的博客。Raible 的大部分生活都被計算機所包圍了,盡管他是在連電都沒有的 Montana 長大的。當不工作的時候時,他總是試圖讓妻子 Julie 成為世界上最幸福的女人,或者與他們的孩子 Abbie 和 Jack 一起玩耍。



Alex 2006-09-04 20:34 發表評論
]]>
[zt]Jive論壇系統完整分析(7)http://www.oiklr.tw/alex/archive/2006/08/31/66836.htmlAlexAlexThu, 31 Aug 2006 04:29:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66836.htmlhttp://www.oiklr.tw/alex/comments/66836.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66836.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66836.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66836.html 7? Jive 安裝調試運行

Jive 默認編碼方式是 ISO8859_1 。下面以安裝在英文 Linux 操作系統上為例:

1 )安裝數據庫。在 database 目錄中選擇對應數據庫,如果數據庫是 MySQL ,則使用 jive_mysql.sql ,然后通過數據庫的管理工具將 jive_mysql.sql 導入相應數據庫中。 Jive 所需要的數據庫都已經準備完成。

2 )由于 Jive Servlet/JSP 系統,必須在 Web 容器支持下才能運行。因此,必須安裝 Web 服務器軟件,例如 Tomcat 等。

最后需要將 Jive 部署到 Tomcat 中。有兩種辦法,其中直接復制的辦法比較簡單,修改 server.xml 辦法可以見其他章節介紹。

Jive application 目錄下所有文件復制到 Tomcat 應用目錄 webapps 的指定目錄下,如 Tomcat/webapps/jive 下。

3 )在運行設置 Jive 之前,還需要設定 Jive 的初始值,在上述應用目錄的 WEB-INF/classes/ 下,創建或編輯 jive_init.properties ,加入行:

jiveHome=C:\\javasource\\jive\\WEB-INF\\jiveHome

這是指定 jivHome 的目錄, jiveHome 主要放置 Jive 的配置文件和搜索等內部工作文件,一般是建立在 WEB-INF 目錄下,這樣, jiveHome 的內容就不會被外界通過瀏覽器直接訪問到,要注意是絕對路徑。

4 )可以安裝設置 Jive 系統。通過瀏覽輸入網址: http://localhost:8080/jive/admin/setup/ Jive 的安裝導航程序會自動進行安裝檢查。由于 Jive 編碼是 ISO8859_1 ,如果涉及需要設置 Java 編碼方式的提問,都設置為英文。

管理員密碼最好更改一下,默認用戶名和密碼是 admin admin

全部設置完成后,進入 http://localhost:8080/jive/ 可以瀏覽。

進入 http://localhost:8080/jive/admin 可以實現論壇管理,可以設置全局過濾器,一般設置如下過濾器:

·????????? TextStyle 文本格式。

·????????? Newline 新一行。

·????????? Profanity 過渡褻瀆或不恰當詞語。

·????????? URLConverter URLConverter

·????????? ImageFilter ImageFilter 支持上傳圖片。 ???????

·????????? CodeHighlighter CodeHighlighter

另外,緩存設置也很重要,可根據訪問量、緩存擊中率以及實際內存大小調整,可以提高論壇的性能。

圖片上傳路徑的設置需要通過手工修改 jiveHome 下的 jive_config.xml 。打開 jive_config.xml 會發現,所有在管理配置中配置的信息都保存在這里,找到下列配置:

<upload>

??????? <dir>/home/bqlr/jive/upload/</dir>

??????? <relurl>upload/</relurl>

</upload>

其中, dir 是上傳圖片存放的絕對路徑; relurl 是網址的相對路徑,比如 upload/ ,那就表示輸入下列網址:“ http://localhost:8080/jive/upload/xxxx.jpg ”,就可以看到上傳的圖片。因為上傳圖片有自動縮小功能,因此需要 Linux 安裝時是帶圖形 X86 的完全安裝。用戶如為中文名,將影響圖片文件名。

以上是 Jive 論壇的安裝



Alex 2006-08-31 12:29 發表評論
]]>
[zt]Jive論壇系統完整分析(8)http://www.oiklr.tw/alex/archive/2006/08/31/66837.htmlAlexAlexThu, 31 Aug 2006 04:29:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66837.htmlhttp://www.oiklr.tw/alex/comments/66837.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66837.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66837.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66837.html

Your Ad Here

8? 小結

本章主要介紹了一個基于 J2EE Web 技術進行設計開發的論壇系統,通過這個系統的剖析,能夠了解和掌握 GOF 設計模式,學會 Java 實戰中一些處理技巧和技術。

使用 GOF 設計模式的主要優點:使得復雜系統的架構變得更加清晰而且有條理,而這一點正是許多程序員在開發實用系統中所缺乏的,可能導致的結果是大大降低 Java 系統可維護性以及可拓展性,重新回到了傳統編程語言的陷阱中。

因此, GOF 設計模式對于 Java 設計編程的重要性是無論怎么強調也不過分,它能夠幫助程序員更加深入地理解 Java 完全面向對象特性,從而以真正的面向對象設計概念進行實用系統的設計和開發。

Jive 系統是一個完全的 Web 系統,整個系統的最大特點是自我定制實現,它為了提高數據庫的訪問性能,使用了自己開發的數據庫連接池;為了提高系統的數據處理系統,它使用了緩存機制;為了實現用戶安全管理機制,它使用 Proxy 模式實現了角色權限的定位和檢查等。這些模塊功能在很多系統中都是需要的,但是如果想從 Jive 系統提煉出這些模塊功能以達到重用,又是非常困難的。

因此,開發者需要一種具有一定高度的框架技術。在這個框架技術中,所有這些通用技術都能夠自動實現,無需再自行設計和開發,能夠將更多精力投入到與業務有關的特定功能開發中。 J2EE EJB 技術實際就是這種框架技術。

學習和研究 Jive 論壇系統也非常有助于程序員學習和理解 EJB J2EE 完整的框架技術,因為它們的目的都是一樣,只不過實現的途徑不一樣而已。



Alex 2006-08-31 12:29 發表評論
]]>
[zt]Jive論壇系統完整分析(6)http://www.oiklr.tw/alex/archive/2006/08/31/66835.htmlAlexAlexThu, 31 Aug 2006 04:28:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66835.htmlhttp://www.oiklr.tw/alex/comments/66835.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66835.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66835.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66835.html 6? Jive 圖形處理

Jive 提供了強大的論壇功能,但是有些功能離實際需求還是有一定的距離,例如論壇是用于信息交流討論的場所。而信息不只是文字,有時還包括圖片或一些 PDF 等類型的文件,那么如何在 Jive 中實現這樣的功能呢?

6.1? 圖片上傳處理

HTML 中,使用表單 Form 主要是用來向服務器提交數據,格式如下:

FORM ACTION="URL"

METHOD="GET|POST"

ENCTYPE="…" TARGET="..."

. . .

/FORM

enctype 指定了表單提交給服務器時的內容形式( Content-Type ),默認值是 "application/x-www-form-urlencoded" ,這時,表單信息一般采用 URL 編碼制。

但是,當向服務器傳送圖片或文件這樣包含非 ASCII 字符或二進制數的數據時,根據 RFC1867 規定,就必須使用“ multipart/form-data ”內容類型。

其實無論是默認表單信息,還是圖片文件,這些內容都是裝載在 HTTP 協議的正文內容部分,都可以看成 HTTP 協議攜帶的對象,只是兩種正文內容形式不一樣。前者是 String 字符串類型,而后者則是一個通用的數據對象類型( Object )。在以后章節中將專門討論 HTTP 協議裝載數據對象的底層細節。

使用“ multipart/form-data ”上傳文件的格式寫法如下:

FORM ACTION="URL" METHOD="GET|POST" ENCTYPE=" multipart/form-data "

? <INPUT TYPE FILE NAME file1>

/FORM

文件通過 HTTP 協議傳送到服務器端后,需要在服務器端對該文件進行專門的接受。 HttpServletRequest 沒有提供直接獲取文件數據的方法,因此需要開發專門的服務器文件處理組件。

目前有兩種上傳文件處理組件:一種是基于完全 JSP 結構的,使用 JSP 來處理上傳的文件,以 SmartUpload http://www.jspsmart.com )最常用;還有一種是完全的 JavaBeans 組件: Cos 文件上傳組件包( http://www.servlets.com/cos/index.html ), Cos 可以使用在 JSP 中,也可以使用在 Servlet Servlet Filter 中。

由于在實際應用中,文件上傳功能往往和其他正常表單參數一起混合使用,而不是獨立使用的。因此,可以設定一個 Servlet 專門用來處理這類混合表單的請求,在將文件接受處理后,自動導向到處理表單正常參數的 JSP/Servlet 去處理。

表單調用示例如下:

<form action="<%=request.getContextPath()%>/multipartformserv"

???? method="post" enctype="multipart/form-data">

?? <input type="hidden" name="FORWARDNAME" value="login.jsp" >?

?? <input type="file" name="file1" >

?? <input type="hidden" name="maxwidth" value="120" >

?? <input type="hidden" name="maxheight" value="60" >

?? <input type="text" name="username" >

?? <input type="text" name="password" >

</form>

在這個表單中,既有文件提交,也有 username 這樣正常的參數需要提交,提交的 Servlet 名為 multipartformserv 。由 multipartformserv 來處理上傳的文件,然后再自動轉交到 FORWARDNAME 的值 login.jsp 進行 username 等正常參數的處理。

在表單中,如果設定 maxwidth maxiheight ,那么表示如果上傳的圖片超過這個尺寸,服務器將縮小圖片到這個尺寸。

編制一個專門用來統一處理 Jive 系統中所有文件處理的 Servlet ,這樣有利于簡化系統。編制 MultipartFormServ 如下:

public class MultipartFormServ extends HttpServlet {

? static final private String CONTENT_TYPE = "text/html";

? // 文件上傳處理

? private static MultipartFormHandle mf = MultipartFormHandle.getInstance();

? // 文件上傳后存放的臨時目錄

? private String dirName;

? private ServletContext context;

? public void init() throws ServletException {

??? // web.xml 中讀取上傳目錄參數

??? dirName = mf.getUploaddir();

??? if (dirName == null) {

????? throw new ServletException("Please supply uploadDir parameter");

??? }

? }

?

? // 處理帶有文件內容的請求

? public void doPost(HttpServletRequest request, HttpServletResponse response)

???????? throws ServletException, IOException {

??? try {

?????? mf.init(dirName,request); // 調用文件上傳處理器處理

?????? // 得到 FORWARDNAME 參數值

?????? String forward=mf.getForwardProgram();

????? if (forward.equals(""))

?????? {

???????? errorMessage("no forward program", response);

???????? return;

????? }

????? String param=mf.getForwardProgramParam();

????? mf.clear();

?????? // 引導分流到 forward 參數值進行其他文本參數處理

????? getServletConfig().getServletContext().

?????????? getRequestDispatcher("/"+forward+"?"+param).forward(request, response);

?

??? }catch (Exception Ex) {

????????? throw new ServletException(Ex.getMessage());

??? }

? }

3-8? 上傳文件處理框架

}

MultipartFormHandler 主要調用 Cos 組件處理上傳文件,對上傳文件圖形大小進行處理,然后將圖形搬遷到指定的目錄;同時也將請求信號中的正常參數提取出來,以作為轉發使用。

這樣一個圖形或文件上傳系統已經形成了一個框架結構,可以重復使用在任何需要圖片或文件上傳處理的系統中,如圖 3-8 所示。

3-8 中上傳文件處理額 Servlet 相當于請求信號 Request 的一個過濾器,既然正常的 Request 處理機制不能從 Request 提取攜帶的文件,那么,使用一個過濾器先將文件提取出來,剩余的再通過正常 Request 處理機制去處理。

6.2? 服務器端圖形處理

Java 最初是以 Applet 等客戶端圖形處理為技術起點的,而本節討論的是如何在 Servlet/JSP 中實現圖形處理。

Jive 中,圖片可以用來顯示用戶的頭像,用戶在上傳自己頭像圖片時,該圖片的大小可能不一,但是由于版面原因,顯示的頭像圖片又有大小限制,那么就需要在用戶上傳圖片時對圖片大小做一個檢查。如果超過規定大小,就進行一定的縮放處理。

縮放處理有兩種方式:是在 HTML 顯示時,使用 image 語法的 width height 來 限制大小,但是這樣做只是解決了表面問題,無法解決大字節圖片傳送到客戶端帶來的性能影響,這個圖片因為是用戶發言的頭像,將會在每個帖子里面顯示。如果 頭像都是巨大圖片,對帖子顯示速度的影響是很大,因此必須在服務器端進行縮小后,再傳送到客戶端,這樣提高了論壇系統性能。

服務器端的圖形處理需要使用到 Java 的圖形處理技術,而且圖形處理是在服務器端的 Web 容器中進行的。和以往 Java 在客戶端進行圖形處理稍微有所不同,相同的是都要使用計算機的底層圖形支持資源。

J2SE 1.4 提供新的增強的圖形處理功能, JDK1.4 中最新的 javax.imageio.ImageIO 對圖片進行讀寫操作,而使用 java.awt.geom.AffineTransform 對圖片進行尺寸縮放處理。

import java.io.File;

import java.awt.image.BufferedImage;

import java.awt.Image;

import java.awt.image.AffineTransformOp;

import javax.imageio.ImageIO;

import java.awt.geom.AffineTransform;

?

public class UploadImg{

???? /**

??? ?* 參數設置

???? * @param fromdir 圖片的原始目錄

???? * @param todir 處理后的圖片存放目錄

???? * @param imgfile 原始圖片

???? * @param sysimgfile 處理后的圖片文件名前綴

???? */

???????? ? public void init(String fromdir,String todir,String imgfile,String sysimgfile)

???????? ? {

????????????????? this.fromdir=fromdir;

????????????????? this.todir=todir;

????????????????? this.imgfile=imgfile;

????????????????? this.sysimgfile=sysimgfile;

???????? ??? }

??? …

??? public boolean CreateThumbnail() throws Exception

??? {

??????? //ext 是圖片的格式 gif JPG png

??????? String ext=""

??????? double Ratio=0.0;

??????? File oldFile = new File(fromdir,imgfile);

??????? if (!F.isFile())? // 檢查是否存在此圖片文件

???????????? throw new Exception(F+" is not image file error in CreateThumbnail!");

?

???????? // 首先判斷上傳的圖片是 gif 還是 JPG ImageIO ,只能將 gif 轉換為 png

???????? if (isJpg(imgfile)){

??????????? ext="jpg";

?????? ?}else{

?????????? ext="png";

??????? }

??????? File newFile = new File(todir,sysimgfile+"."+ext);

?

??????? BufferedImage Bi = ImageIO.read(oldFile);? // 讀取原始圖片

??????? if ((Bi.getHeight()>120) || (Bi.getWidth()>120)){

??????????? if (Bi.getHeight()>Bi.getWidth())

????????????? Ratio = 120.0/Bi.getHeight();

??????????? else

????????????? Ratio = 120.0/Bi.getWidth();

?????? }

?????? // 進行圖片轉換

?????? AffineTransformOp op =

????????? new AffineTransformOp(AffineTransform.getScaleInstance(Ratio, Ratio), null);

?????? Image itemp = op.filter(Bi, null);

?

?????? try { // 寫入轉換后的圖片

?????????? ImageIO.write((BufferedImage) itemp, ext, newFile);

?????? }catch (Exception ex) {

??????????? throw new Exception(ex.getMessage());

?????? }

?????? return (true);

?? }

}

該類中由于使用到了 Java AWT ,雖然沒有實際顯示,但 Linux 系統下需要 X11 Windows 的支持(安裝 Linux 時需安裝 XFree86 Linux 完全安裝方式包括安裝 XFree86 )。

該縮放功能是在圖片上傳到服務器后再進行的處理,可以對 JPG 進行縮小放大;對上傳是 GIF 的圖片,縮放后變成 PNG 圖片格式文件。



Alex 2006-08-31 12:28 發表評論
]]>
[zt]Jive論壇系統完整分析(4)http://www.oiklr.tw/alex/archive/2006/08/31/66833.htmlAlexAlexThu, 31 Aug 2006 04:27:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66833.htmlhttp://www.oiklr.tw/alex/comments/66833.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66833.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66833.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66833.html 4? Jive 的緩存機制

Jive 論壇的一個主要特點就是其性能速度快,因此很多巨大訪問量的網站都采用了 Jive 論壇。這些都是由于 Jive 采取了高速緩存機制。

緩存( Cache )機制是提高系統運行性能必不可少的技術。緩存機制從原理上講比較簡單,就是在原始數據第一次讀取后保存在內存中,下次讀取時,就直接從內存中讀取。原始數據有可能保存在持久化介質或網絡上。緩存機制也是代理模式的一種實現。

4.1? 緩存原理和實現

Jive Cache 總體來說實現得不是非常精簡和有效。它是針對每個具體數據對象逐個實現緩沖,這種“窮盡”的辦法不是實踐所推薦的用法。通過使用動態代理模式,可以根據具體方法的不同來實現緩存是值得推薦的做法。 Jive 的緩存實現得比較簡單,可以用來學習和研究緩存機制。

Jive 中的 Cache 實現了緩存機制的大部分行為,它是將對象用惟一的關鍵字 Key 作標識保存在 HashMap Hashtable 中。當然,必須知道這些對象的大小,這個前提條件的設定可以保證緩存增長時不會超過規定的最大值。

如果緩存增長得太大,一些不經常被訪問的對象將首先從緩存中刪除。如果設置了對象的最大生命周期時間,即使這個對象被反復頻繁訪問,也將從緩存中刪除。這個特性可以適用于一些周期性需要刷新的數據,如來自數據庫的數據。

Cach 中除了 getObject() 方法的性能依據緩存大小,其他方法的性能都是比較快的。一個 HashMap 用來實現快速尋找,兩個 LinkedList 中一個以一定的訪問順序來保存對象,叫 accessed LinkedList ;另外一個以它們加入緩存的順序保存這些對象,這種保存對象只是保存對象的引用,叫 age LinkedList 。注意,這里的 LinkedList 不是 JDK 中的 LinkedList ,而是 Jive 自己定義的 LinkedList

當對象被加入緩存時,首先被 CacheObject 封裝。封裝有以下信息:對象大小(以字節計算),一個指向 accessed LinkedList 的引用,一個指向 age LinkedList 的引用。

當從緩存中獲取一個對象如 ObjectA 時,首先, HashMap 尋找到指向封裝 ObjectA 等信息的 CacheObject 對象。然后,這個對象將被移動到 accessed LinkedList 的前面,還有其他一些動作如緩存清理、刪除、過期失效等都是在這個動作中一起觸發實現的。

public class Cache implements Cacheable {

??? /**

???? * 因為 System.currentTimeMillis() 執行非常耗費性能,因此如果 get 操作都執行

* 這條語句將會形成性能瓶頸, 通過一個全局時間戳來實現每秒更新

* 當然,這意味著在緩存過期時間計算上有一到幾秒的誤差

???? */

??? protected static long currentTime = CacheTimer.currentTime;

??? //CacheObject 對象

??? protected HashMap cachedObjectsHash;

??? //accessed LinkedList 最經常訪問的排列在最前面

??? protected LinkedList lastAccessedList;

??? // 以緩存加入順序排列,最后加入排在最前面;越早加入的排在最后面

??? protected LinkedList ageList;

??? // 緩存最大限制 默認是 128k 可根據內存設定,越大性能越高

??? protected int maxSize =? 128 * 1024;

??? // 當前緩存的大小

??? protected int size = 0;

??? // 最大生命周期時間,默認是沒有

??? protected long maxLifetime = -1;

??? // 緩存的擊中率,用于評測緩存效率

??? protected long cacheHits, cacheMisses = 0L;

?

??? public Cache() {

??????? // 構造 HashMap. 默認 capacity 11

??????? // 如果實際大小超過 11 HashMap 將自動擴充,但是每次擴充都

// 是性能開銷,因此期初要設置大一點

??????? cachedObjectsHash = new HashMap(103);

??????? lastAccessedList = new LinkedList();

??????? ageList = new LinkedList();

??? }

??? public Cache(int maxSize) {

??????? this();

??????? this.maxSize = maxSize;

??? }

? ??public Cache(long maxLifetime) {

??????? this();

??????? this.maxLifetime = maxLifetime;

??? }

??? public Cache(int maxSize, long maxLifetime) {

??????? this();

??????? this.maxSize = maxSize;

??????? this.maxLifetime = maxLifetime;

??? }

??? public int getSize() {??????? return size;??? }

??? public int getMaxSize() {??????? return maxSize;??? }

?

??? public void setMaxSize(int maxSize) {

??????? this.maxSize = maxSize;

??????? // 有可能緩存大小超過最大值,需要激活刪除清理動作

??????? cullCache();

??? }

??? public synchronized int getNumElements() {

??????? return cachedObjectsHash.size();

??? }

?

??? /**

???? * 增加一個 Cacheable 對象

* 因為 HashMap 不是線程安全的,所以操作方法要使用同步

* 如果使用 Hashtable 就不必同步

???? */

??? public synchronized void add(Object key, Cacheable object) {

??????? // 刪除已經存在的 key

??????? remove(key);

??????? int objectSize = object.getSize();

??????? // 如果被緩存對象的大小超過最大值,就放棄

??????? if (objectSize > maxSize * .90) {??????????? return;??????? }

??????? size += objectSize;

??????? // 創建一個 CacheObject 對象

??????? CacheObject cacheObject = new CacheObject(object, objectSize);

??????? cachedObjectsHash.put(key, cacheObject);? // 保存這個 CacheObject

??????? // 加入 accessed LinkedList Jive 自己的 LinkedList 在加入時可以返回值

??????? LinkedListNode lastAccessedNode = lastAccessedList.addFirst(key);

??????? // 保存引用

??????? cacheObject.lastAccessedListNode = lastAccessedNode;

??????? // 加入到 age LinkedList

??????? LinkedListNode ageNode = ageList.addFirst(key);

??????? // 這里直接調用 System.currentTimeMillis(); 用法值得討論

??????? ageNode.timestamp = System.currentTimeMillis();

??????? // 保存引用

??????? cacheObject.ageListNode = ageNode;

??????? // 做一些清理工作

??????? cullCache();

??? }

??? /**

???? * 從緩存中獲得一個被緩存的對象,這個方法在下面兩種情況返回空

???? *??? <li> 該對象引用從來沒有被加入緩存中

???? *??? <li> 對象引用因為過期被清除 </ul>

???? */

??? public synchronized Cacheable get(Object key) {

??????? // 清除過期緩存

??????? deleteExpiredEntries();

??????? // Key 從緩存中獲取一個對象引用

??????? CacheObject cacheObject = (CacheObject)cachedObjectsHash.get(key);

??????? if (cacheObject == null) {

??????????? // 不存在,增加未命中率

??????????? cacheMisses++;

??????????? return null;

??????? }

??????? // 存在,增加命中率

??????? cacheHits++;

??????? // accessed LinkedList 中將對象從當前位置刪除

??????? // 重新插入在第一個

??????? cacheObject.lastAccessedListNode.remove();

??? ????lastAccessedList.addFirst(cacheObject.lastAccessedListNode);

??????? return cacheObject.object;

??? }

??? …

}

Cache 中,關鍵字 Key 是一個對象,為了再次提高性能,可以進一步將 Key 確定為一個 long 類型的整數。

4.2? 緩存使用

建立 LongCache 只是為了提高原來的 Cache 性能,本身無多大意義,可以將 LongCache 看成與 Cache 一樣的類。

LongCache 的關鍵字 Key Forum ForumThread 以及 ForumMessage long 類型的 ID ,值 Value Forum ForumThread 以及 ForumMessage 等的對象。這些基本是通過 DatabaseCacheManager 實現完成,在主要類 DbForumFactory 的初始化構造時,同時構造了 DatabaseCacheManager 的實例 cacheManager

前面過濾器功能分析中, Message 對象獲得方法的第一句如下:

protected ForumMessage getMessage(long messageID, long threadID, long forumID) throws

????? ForumMessageNotFoundException {

??? DbForumMessage message = cacheManager.messageCache.get(messageID);

??? …

}

其中, cacheManager DatabaseCacheManager 的實例, DatabaseCacheManager 是一個緩存 Facade 類。在其中包含了 5 種類型的緩存,都是針對 Jive 5 個主要對象, DatabaseCacheManager 主要代碼如下:

public class DatabaseCacheManager {

?? ?public UserCache userCache;??????? ????????????????? // 用戶資料緩存

??? public GroupCache groupCache;?????? ??????????????? // 組資料緩存

??? public ForumCache forumCache;????? ???????????????? //Forum 論壇緩存

??? public ForumThreadCache threadCache; ?????????????? //Thread 主題緩存

??? public ForumMessageCache messageCache;????????? //Message 緩存

??? public UserPermissionsCache userPermsCache;???? // 用戶權限緩存

?

??? public DatabaseCacheManager(DbForumFactory factory) {

??????? …

??????? forumCache =

??????????? new ForumCache(new LongCache(forumCacheSize, 6*HOUR), factory);

??????? threadCache =

??????????? new ForumThreadCache(

????????????????? new LongCache(threadCacheSize, 6*HOUR), factory);

??????? messageCache = new ForumMessageCache(

????????????????? new LongCache(messageCacheSize, 6*HOUR), factory);

??????? userCache = new UserCache(

????????????????? new LongCache(userCacheSize, 6*HOUR), factory);

??????? groupCache = new GroupCache(

????????????????? new LongCache(groupCacheSize, 6*HOUR), factory);

??????? userPermsCache = new UserPermissionsCache(

??????????????? new UserPermsCache(userPermCacheSize, 24*HOUR), factory

??????? );

??? }

??? …

}

從以上代碼看出, ForumCache 等對象生成都是以 LongCache 為基礎構建的,以 ForumCache 為例,代碼如下:

public class ForumCache extends DatabaseCache {

??? // Cache 構建 ID 緩存

??? protected Cache forumIDCache = new Cache(128*1024, 6*JiveGlobals.HOUR);

??? // LongCache 構建整個對象緩存

??? public ForumCache(LongCache cache, DbForumFactory forumFactory) {

??????? super(cache, forumFactory);

??? }

?

??? public DbForum get(long forumID) throws ForumNotFoundException {

??????? …

??????? DbForum forum = (DbForum)cache.get(forumID);

??????? if (forum == null) {??? // 如果緩存沒有從數據庫中獲取

??????????? forum = new DbForum(forumID, factory);

??????????? cache.add(forumID, forum);

??????? }

??????? return forum;

??? }

?

public Forum get(String name) throws ForumNotFoundException {

?????? ??// name key ,從 forumIDCache 中獲取 ID

?CacheableLong forumIDLong = (CacheableLong)forumIDCache.get(name);

??????? if (forumIDLong == null) { // 如果緩存沒有 從數據庫獲得

??????????? long forumID = factory.getForumID(name);

??????????? forumIDLong = new CacheableLong(forumID); // 生成一個緩存對象

??????????? forumIDCache.add(name, forumIDLong);

??????? }

??????? return get(forumIDLong.getLong());

??? }

??? …

}

由此可以看到, LongCache 封裝了 Cache 的核心功能,而 ForumCache 等類則是在 LongCache 核心外又包裝了與應用系統相關的操作,這有點類似裝飾( Decorator )模式。

從中也可以看到 Cache LongCache 兩種緩存的用法。

使用 Cache 時的關鍵字 Key 是任何字段。如上面代碼中的 String name ,如果用戶大量帖子主題查詢中, Key query + blockID ,見 DbForum 中的 getThreadBlock 方法;而值 Value 則是 Long 類型的 ID ,如 ForumID ThreadID 等。

LongCache 的關鍵字 Key Long 類型的 ID ,如 ForumID ThreadID 等;而值 Value 則是 Forum ForumThread ForumMessage 等主要具體對象。

在實際使用中,大多數是根據 ID 獲得對象。但有時并不是這樣,因此根據應用區分了兩種 Cache ,這其實類似數據庫的數據表,除了主關鍵字外還有其他關鍵字。

4.3? 小結

緩存中對象是原對象的映射,如何確保緩存中對象和原對象的一致性?即當原對象發生變化時,緩存中的對象也必須立即更新。這是緩存機制需要解決的另外一個基本技術問題。

Jive 中是在原對象發生變化時,立即進行清除緩存中對象,如 ForumMessage 對象的創建。在 DbForumThread AddMessage 方法中有下列語句:

factory.cacheManager.threadCache.remove(this.id);

factory.cacheManager.forumCache.remove(this.forumID);

即當有新的帖子加入時,將 ForumThreadCache ForumCache 相關緩沖全部清除。這樣,當有相關對象讀取時,將直接從數據庫中讀取,這是一種非常簡單的緩存更新方式。

在復雜的系統,例如有一臺以上的服務器運行著 Jive 系統。如果一個用戶登陸一臺服務器后,通過這臺服務器增加新帖。那么按照上述原理,只能更新本服務器 JVM 中的緩存數據,而其他服務器則無從得知這種改變,這就需要一種分布式的緩存機制。

3-7? Jive 主要對象的訪問

到目前可以發現 整個 Jive 系統其實是圍繞 Forum ForumThread ForumMessage 等這些主要對象展開的讀取、修改或創建等操作。由于這些對象原先持久化保存在數據庫中,為了提高性能和加強安全性, Jive 在這些對象外面分別實現兩層包裝,如圖 3-7 所示。

客戶端如果需要訪問這些對象,首先要經過它們的代理對象。進行訪問權限的檢查,然后再從緩存中獲取該對象。只有緩存不存在時,才會從數據庫中獲取。

這套機制是大多數應用系統都面臨的必須解決的基本功能,因此完全可以做成一個通用的可重復使用的框架。這樣在具體應用時,不必每個應用系統都架設開發這樣的機制。其實 EJB 就是這樣一套框架,實體 Bean 都由緩存機制支持,而通過設定 ejb-jar.xml 可以實現訪問權限控制,這些工作都直接由 EJB 容器實現了,不必在代碼中自己來實現。剩余的工作是調整 EJB 容器的參數,使之適合應用系統的具體要求,這些將在以后章節中討論。

Jive 中,圖 3-7 的機制是通過不同方式實現的。基本上是一配二模式:一個對象有一個緩沖對象和一個代理對象,這樣做的一個缺點是導致對象太多,系統變得復雜。這點在閱讀 Jive 源碼時可能已經發現。

如果建立一個對象工廠,工廠內部封裝了圖 3-7 機制實現過程,客戶端可以根據不同的工廠輸入參數獲得具體不同的對象。這樣也許代碼結構要更加抽象和緊湊, Java 的動態代理 API 也許是實現這個工廠的主要技術基礎。有興趣者可以進一步研究提煉。



Alex 2006-08-31 12:27 發表評論
]]>
[zt]Jive論壇系統完整分析(5)http://www.oiklr.tw/alex/archive/2006/08/31/66834.htmlAlexAlexThu, 31 Aug 2006 04:27:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66834.htmlhttp://www.oiklr.tw/alex/comments/66834.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66834.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66834.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66834.html閱讀全文

Alex 2006-08-31 12:27 發表評論
]]>
[zt]Jive論壇系統完整分析(2)http://www.oiklr.tw/alex/archive/2006/08/31/66831.htmlAlexAlexThu, 31 Aug 2006 04:26:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66831.htmlhttp://www.oiklr.tw/alex/comments/66831.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66831.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66831.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66831.html閱讀全文

Alex 2006-08-31 12:26 發表評論
]]>
[zt]Jive論壇系統完整分析(3)http://www.oiklr.tw/alex/archive/2006/08/31/66832.htmlAlexAlexThu, 31 Aug 2006 04:26:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66832.htmlhttp://www.oiklr.tw/alex/comments/66832.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66832.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/66832.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66832.html 3? Jive 安全管理機制

Jive 中除了前面介紹的有關設計模式實現組件外,還有其他有一定特點的組件功能,分析研究這些組件功能可以更加完整透徹地理解 Jive 論壇系統。

Jive 安全管理機制基本是由下列部分組成:

·????????? 安全驗證機制。主要是驗證用戶名和密碼組合是否與數據庫中注冊時的數據一致,以確認該用戶身份為注冊用戶。這是對所有的 JSP 訪問都進行攔截訪問。

·????????? 訪問權限控制( ACL )。對不同的數據不同用戶擁有不同的訪問權限,例如,一個帖子普通用戶可以瀏覽,但是不能更該;但是管理員卻可以編輯刪除。這部分功能是通過代理模式實現,為每個關鍵數據都建立一個代理類用來實現訪問權限檢查,這在前面討論過。

·????????? 用戶資料管理系統。主要是管理用戶的資料數據,進行用戶組和用戶關系的建立等。

1? 安全驗證機制

Jive 的安全驗證機制是按照比較通用的思路設計的。類似前面“簡單的用戶注冊管理系統”中的介紹, Jive 也是在所有的 JSP 頁面中 include 一個安全檢驗功能的 global.jsp 。由于 global.jsp 是在每個 JSP 一開始必須執行的功能,因此通過攔截 global.jsp 攔截發往各個 JSP 頁面的請求( request )。如果這個請求是合法的,將被允許通過;如果不是,將注明請求者身份是 Anonymous (匿名者)。

global.jsp 代碼如下:

boolean isGuest = false;

Authorization authToken = SkinUtils.getUserAuthorization(request, response);

if (authToken == null) {// 未被驗證通過

??? authToken = AuthorizationFactory.getAnonymousAuthorization();

??? isGuest=true;

}

Jive 中,以 Authorization 對象作為驗證通過的標志,它的接口代碼如下:

public interface Authorization {

??? public long getUserID();???

??? public boolean isAnonymous();

}

具體實現是 DbAuthorization ,代碼如下:

public final class DbAuthorization implements Authorization, Serializable {

??? private long userID;

??? protected DbAuthorization(long userID) {

??????? this.userID = userID;

??? }

??? public long getUserID() {

??????? return userID;

??? }

??? public boolean isAnonymous() {

??????? return userID == -1;

??? }

}

此類只是一個 userID ,因此只是一個象征性的標志。

SkinUtils 是一個為 JSP 服務的類,它的 getUserAuthorization 代碼如下:

public static Authorization getUserAuthorization

??????? (HttpServletRequest request, HttpServletResponse response)

? {

??? HttpSession session = request.getSession();

??? // HttpSession 中獲取 Authorization 實例

??? Authorization authToken =

(Authorization)session.getAttribute(JIVE_AUTH_TOKEN);

??? if (authToken != null) {???? return authToken;? }

?

??? // 如果 HttpSession 中沒有,檢查用戶瀏覽器 cookie

??? Cookie cookie = getCookie(request, JIVE_AUTOLOGIN_COOKIE);

??? if (cookie != null) {

??????? try {

?????????? String[] values = decodePasswordCookie(cookie.getValue());

?????????? String username = values[0];

?????????? String password = values[1];

?????????? // cookie 中獲得用戶名和密碼后,進行安全驗證

?????????? authToken = AuthorizationFactory.getAuthorization(username,password);

??????? }catch (Exception e) {}

??????? // put that token in the user's session:

??????? if (authToken != null) {// 如果通過驗證,保存 authToken http Session

?????????? session.setAttribute(JIVE_AUTH_TOKEN, authToken);

??????? }

?????? // return the authorization token

??????? return authToken;

??? }

? ??return null;

}

用戶驗證預先通過兩個步驟。首先檢查 HttpSession 中是否保存了該用戶的驗證信息,如果用戶第一次驗證通過,反復訪問,這道關口檢查就可以通過。

如果 HttpSession 中沒有驗證信息,那么從該用戶的瀏覽器 cookie 中尋找用戶名和密碼。如果該用戶激活了 cookie 保存這些登錄信息,那么應該可以找到用戶名和密碼,這樣就省卻了用戶再次從鍵盤輸入用戶名和密碼,將用戶名和密碼通過下列語句進行數據庫驗證:

authToken = AuthorizationFactory.getAuthorization(username,password);

這一舉是驗證關鍵。 AuthorizationFactory 是一個抽象類,定義了 Jive 安全驗證機制所需的所有方法, AuthorizationFactory 的實現類似前面討論的 ForumFactory 實現,是使用工廠模式加動態類反射機制完成的,代碼如下:

public abstract class AuthorizationFactory {

?? // 定義一個數據庫具體實現

??? private static String className =

??????? " com.Yasna.forum.database.DbAuthorizationFactory";

?

??? private static AuthorizationFactory factory = null;

??? // 驗證方法 如果沒有 UnauthorizedException 拋出,表示驗證通過

??? public static Authorization getAuthorization(String username,

??????????? String password) throws UnauthorizedException

??? {

??????? loadAuthorizationFactory();

??????? return factory.createAuthorization(username, password);

??? }

??? // 匿名者處理方法

??? public static Authorization getAnonymousAuthorization() {

??????? loadAuthorizationFactory();

??????? return factory.createAnonymousAuthorization();

??? }

??? // 需要具體實現的抽象方法

??? protected abstract Authorization createAuthorization(String username,

??????????? String password) throws UnauthorizedException;

??? protected abstract Authorization createAnonymousAuthorization();

??? // 動態配置 AuthorizationFactory 的具體實現,可以在配置文件中定義一個

??? // 基于 LDAP 的實現。類似 ForumFactory getInstance 方法

??? private static void loadAuthorizationFactory() {

??????? …

??? }

}

AuthorizationFactory 看上去很復雜,實際只有一個核心方法 getAuthorization 。實現用戶名和密碼的驗證。如果無法通過驗證,有兩個信息實現顯示:一個是拋出 UnauthorizedException ,另外一個是返回空的 Authorization 對象。

那么,子類 DbAuthorizationFactory 毫無疑問就是查詢數據庫,將輸入的用戶名和密碼與數據庫保存的用戶名和密碼進行校驗。

Jive 的安全驗證機制比較簡單易懂,值得在實踐中學習借鑒。但是注意到這套安全驗證機制只是 Web 層的“手工”驗證,資源訪問權限( ACL )也是自己“手工”來實現的。如果使用 EJB 技術,因為 EJB 容器本身有一定的資源訪問控制體系,因此在 Web 層驗證通過后,需要將這些登錄信息傳遞到 EJB 層。當然如果直接使用 Web 容器的安全驗證機制,那么 Web 層與 EJB 層之間的登錄信息傳遞將由容器實現,這樣就更加簡單方便。

Jive 這種的安全驗證并不是使用 Web 容器的安全驗證機制,如何使用 Web 容器的安全驗證機制將在以后章節介紹。盡管如此, Jive 這套安全驗證機制對付小型系統的應用也是足夠的。


2? 用戶資料管理

Jive 中,用戶 User 對象的操作訪問類似于論壇 Forum 對象的訪問,與 User 對象有關的操作都封裝在一個類中操作,這是外觀( Facade )模式的應用。

Jive 中,用戶資料管理屬于大系統中的一個子系統,在這個子系統中,用戶子系統和其他系統又有一定的關系,涉及的類不少,通過建立一個 UserManager 類來統一對外接口,使得整個子系統條目結構清晰。

UserManager 中無外乎用戶數據的管理,如用戶的創建、修改、查詢和刪除。 DbUserManager UserManager 的一個數據庫實現,可是看看 DbUserManager 中除了刪除功能是直接通過 SQL 語句進行數據庫刪除操作外,其他都委托給 User 的具體實現 DbUser 實現的。這種實現非常類似于 EJB Session Bean 和實體 Bean 之間的關系。以創建用戶資料為例,代碼如下:

public User createUser(String username, String password, String email)

??????????? throws UserAlreadyExistsException

?{

??????? User newUser = null;

??????? try {

??????????? // username 查詢改用戶是否存在

??????????? User existingUser = getUser(username);

??????????? // 如果沒有拋出 UserNotFoundException 異常,表示該用戶存在

??????????? //The user already exists since now exception, so:

??????????? throw new UserAlreadyExistsException();

??????? } catch (UserNotFoundException unfe) {

??????????? // 該用戶不存在,創建一個新用戶

??????????? newUser = new DbUser(username, password, email, factory);

??????? }

??????? return newUser;

}

DbUser 的構造方法實際是用戶資料的新增創建:

protected DbUser(String username, String password, String email,

??????????? DbForumFactory factory)

{

??????? this.id = SequenceManager.nextID(JiveGlobals.USER);? // 獲得自增 ID

??????? this.username = username;

??????? // Compute hash of password.

??? ????this.passwordHash = StringUtils.hash(password);? // 獲得加密的密碼

??????? this.email = email;

??????? this.factory = factory;

??????? long now = System.currentTimeMillis();

??????? creationDate = new java.util.Date(now);

??????? modifiedDate = new java.util.Date(now);

??????? properties = new Hashtable();

??????? insertIntoDb();????????????? // 數據庫插入數據

}

Jive 中,數據修改的保存是由 DbUser saveToDb 方法實現的,而 saveToDb 方法調用是在每個 setXXXX 方法中。即每當外界調用 DbUser setXXXX ,則表示需要改變某些字段屬性值,在這個方法中直接進行數據庫存儲,這也類似 EJB CMP 實體 Bean 的數據字段修改保存。

Jive 中組 Group 與用戶 User 處理幾乎差不多,只是在 Group 中整合了權限方面的信息,這種做法是有一定的局限性,不是很值得借鑒,要想設計一個動態擴展靈活的權限系統,必須在用戶或組與權限之間引入角色概念,也就是比較先進的基于角色的權限系統( RBAC Roled-Based Access Control ,相關網址: http://csrc.nist.gov/rbac/ )。

RBAC 中,用戶組只是用戶的一個集合,應該是通過角色和權限發生聯系。所以 RBAC 認為,如果給用戶組賦予權限,那么用戶組也接近角色的概念。



Alex 2006-08-31 12:26 發表評論
]]>
[zt]Jive論壇系統完整分析(1)http://www.oiklr.tw/alex/archive/2006/08/31/66830.htmlAlexAlexThu, 31 Aug 2006 04:25:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/31/66830.htmlhttp://www.oiklr.tw/alex/comments/66830.htmlhttp://www.oiklr.tw/alex/archive/2006/08/31/66830.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/66830.htmlhttp://www.oiklr.tw/alex/services/trackbacks/66830.html 1? Jive 功能需求

Jive 功能需求分析類似于一個新系統的需求分析。只有了解 Jive 系統實現了哪些論壇功能,才能進一步研究和學習它是怎樣巧妙、優雅地實現這些功能的。

論壇系統是網絡交流的一種主要互動功能系統,如圖 3-1 所示。通過論壇系統,用戶可以共同就某個話題不斷進行討論,通過發貼功能發布新的話題,通過回貼功能回復別人的話題。 Jive 論壇系統可以允許管理員動態地創建新的論壇、編輯論壇的內容、設置論壇過濾信息以及管理注冊用戶等。

3-1? Jive 用例圖

Jive 論壇系統中,用戶角色和權限是緊密聯系在一起的。主要分兩大角色:普通用戶和管理員,具體的表現形式是通過權限組合來體現的。管理方面的權限有:

·????????? SYSTEM_ADMIN ,系統管理員,可以管理整個系統。

·????????? FORUM_ADMIN ,論壇管理員,可以管理某個特定的論壇。

·????????? USER_ADMIN GROUP_ADMIN ,用戶和組管理員,可以管理一些特定用戶和用戶 組。

論壇的讀寫權限包括:讀權限,創建一個新主題,創建一個新的帖子等。

Jive 中沒有明確定義普通用戶和管理員角色,而是直接通過以上權限組合和具體用戶直接建立聯系,并將這種直接聯系保存到數據庫中。

在權限不是很復雜的情況下,這種沒有引入角 色的做法比較簡單直接。但由于用戶和權限直接掛鉤,而用戶和權限都可能在不斷地動態變化,那么它們之間由于聯系太直接和緊密,對各自變化形成了限制。所 以,對于復雜的權限系統,引入了基于角色的權限系統,這將在以后章節中進一步討論。

Jive 論壇業務對象主要分為 Forum ForumThread ForumMessage ,它們之間的關系如圖 3-2 所示。

每個論壇 Forum 包含一系列 ForumThread (主題),而每個主題都是由很多內容帖子 ForumMessage 組成的,這是一個聚集關系。這 3 種對象中每一個對象都涉及到對象數據的創建、編輯、查詢和刪除,這些對象數據分別保存在數據庫中。這 3 個對象對于不同的角色可操作訪問權限是不一樣的,只有系統管理員和論壇管理員可以對 Forum 相關數據實行操作,普通用戶可以創建或編輯 ForumThread ForumMessage

Jive 論壇為了實現不同用戶對不同基本對象的不同操作權限,通過設定一個統一的入口,在這個入口將檢查客戶端每次對數據的操作權限,如圖 3-3 所示。

??

3-2? 基本對象關系圖 ??????????????????????????? 3-3? 入口示意圖

客戶端每次對數據庫的操作,都要經過 ForumFactory 入口進入。在 ForumFactory 中會動態生成一個訪問控制代理 ForumFactoryProxy ,通過 ForumFactoryProxy 檢查客戶端訪問方法是否符合整體權限訪問控制要求。

下面將從 ForumFactory 作為 Jive 論壇系統分析入手,結合設計模式逐步分解論壇功能的具體實現。



Alex 2006-08-31 12:25 發表評論
]]>
關于java與javaScript的互相訪問http://www.oiklr.tw/alex/archive/2006/08/21/64850.htmlAlexAlexMon, 21 Aug 2006 10:02:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/21/64850.htmlhttp://www.oiklr.tw/alex/comments/64850.htmlhttp://www.oiklr.tw/alex/archive/2006/08/21/64850.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/64850.htmlhttp://www.oiklr.tw/alex/services/trackbacks/64850.html在jsp中,通過js訪問java代碼比較容易(不過,也有缺陷,比如java代碼的聲明必須先于js),反過來則不方便,網上看到有通過其他組件的方式來做,感覺也不是很好,其實平時用的更多的是在js中有中文編碼,而需要到下一個jsp頁面中得到這個對應的值。

js中有函數escape和unescape,可惜的是java.net.*中的編碼和解碼與js的不一致,所以他們不能協同工作,有一個方法就是在java中重新實現一遍js里對應的方法,代碼如下:
/**
?*?java版本的escape和?unescape[對應javaScript里的函數]
?
*/
public?class?EscapeUnescape?{
????
/**
?????*?escape?==>?escape
?????*?
@param?src
?????*?
@return?String
?????
*/
????
public?static?String?escape(String?src)?{
????????
int?i;
????????
char?j;
????????StringBuffer?tmp?
=?new?StringBuffer();
????????tmp.ensureCapacity(src.length()?
*?6);
????????
for?(i?=?0;?i?<?src.length();?i++)?{
????????????j?
=?src.charAt(i);
????????????
if?(Character.isDigit(j)?||?Character.isLowerCase(j)
????????????????????
||?Character.isUpperCase(j))
????????????????tmp.append(j);
????????????
else?if?(j?<?256)?{
????????????????tmp.append(
"%");
????????????????
if?(j?<?16)
????????????????????tmp.append(
"0");
????????????????tmp.append(Integer.toString(j,?
16));
????????????}?
else?{
????????????????tmp.append(
"%u");
????????????????tmp.append(Integer.toString(j,?
16));
????????????}
????????}
????????
return?tmp.toString();
????}

????
/**
?????*?unescape?===>js
?????*?
@param?src
?????*?
@return?String
?????
*/
????
public?static?String?unescape(String?src)?{
????????StringBuffer?tmp?
=?new?StringBuffer();
????????tmp.ensureCapacity(src.length());
????????
int?lastPos?=?0,?pos?=?0;
????????
char?ch;
????????
while?(lastPos?<?src.length())?{
????????????pos?
=?src.indexOf("%",?lastPos);
????????????
if?(pos?==?lastPos)?{
????????????????
if?(src.charAt(pos?+?1)?==?'u')?{
????????????????????ch?
=?(char)?Integer.parseInt(src.substring(pos?+?2,?pos?+?6),?16);
????????????????????tmp.append(ch);
????????????????????lastPos?
=?pos?+?6;
????????????????}?
else?{
????????????????????ch?
=?(char)?Integer.parseInt(src.substring(pos?+?1,?pos?+?3),?16);
????????????????????tmp.append(ch);
????????????????????lastPos?
=?pos?+?3;
????????????????}
????????????}?
else?{
????????????????
if?(pos?==?-1)?{
????????????????????tmp.append(src.substring(lastPos));
????????????????????lastPos?
=?src.length();
????????????????}?
else?{
????????????????????tmp.append(src.substring(lastPos,?pos));
????????????????????lastPos?
=?pos;
????????????????}
????????????}
????????}
????????
return?tmp.toString();
????}
}




Alex 2006-08-21 18:02 發表評論
]]>
[ZT]與Java相關的四十個名字http://www.oiklr.tw/alex/archive/2006/08/13/63361.htmlAlexAlexSun, 13 Aug 2006 13:35:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/13/63361.htmlhttp://www.oiklr.tw/alex/comments/63361.htmlhttp://www.oiklr.tw/alex/archive/2006/08/13/63361.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/63361.htmlhttp://www.oiklr.tw/alex/services/trackbacks/63361.html十大事件

1990-1994:Java緣起
文/孟巖

Larry Wall說,優秀程序員應有的三個特點:懶惰、急躁和傲慢。Java就是誕生在一群懶惰、急躁而傲慢的程序天才之中。
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。
到了1992年9月,Oak語言連同Green OS和一些應用程序一起發布在稱做Start 7的小設備上,從而使之有了第一次精彩的亮相。隨后,Sun開了一家名為FirstPerson的公司,整個團隊被轉移到這家公司里研發機頂盒,以投標時 代華納公司的一個項目。這幫天才被技術狂熱所鼓舞,開發出了一個高交互性的設備,結果沒想到時代華納公司和有線電視服務商并不愿意用戶擁有那么大的控制 權,從而在競標之戰中敗給了SGI。Oak的鋒芒之銳,竟然把客戶都給嚇懵了。Sun沮喪地關閉了FirstPerson,召回了整個團隊。事實證明,傳 統行業中那些腦滿肥腸的保守主義者是腐朽沒落的。回去!回到激情澎湃的IT產業,抓住互聯網的大潮,這才是出路!1994年,Oak被命名為Java,針 對互聯網的新一輪開發如火如荼,一切已經就緒,熔巖在地下奔流,火山即將噴發。


1995: Java香濃世界
文/馬偉

1995年,Sun正式對外公布了Java,并且發布了JDK 1.0。這種外形酷似C++,卻包含一顆Smalltalk般純潔的面向對象之心的全新程序設計語言及其平臺,幾乎在一夜之間就成為軟件產業的新寵兒。 Java當時僅僅被用來為網站制作一些動態應用,諸如動畫圖片之類,但這仍然引起了很多Web開發者們的注意,他們非常渴望有一種安全的語言,可以在靜態 的HTML網頁上制作動畫圖片。Sun最終把Java集成到NetScape瀏覽器。同時因為它具有“只寫一次,隨處運行”的特性,而引起了很多開發者的 注意,他們可以再也不用為了使程序能夠在不同型號的硬件上運行而耗費大量的時間來編譯代碼了。
當時的Web瀏覽器的出現也為Java的出現起到了很好的推動作用,通過Java和Web瀏覽器的結合,人們似乎看到了什么,有人甚至預言PC 將在一兩年內退出歷史的舞臺,取而代之的是基于Java的瀏覽器應用程序,通過網絡計算設備來進行應用。Java的出現為當時的軟件產業帶來了無限的遐 想。


1996:Java大躍進,盟主地位就此定
文/馬偉

SUN在1996年一開始首先成立了JavaSoft組織,并在1月23日正式發布自己的Java 1.0,作為20世紀業界出現的最重要的技術之一,Java引起了編程世界的革命。直到現在,Java仍然是互聯網上最流行的語言。
在Sun正式發布Java 1.0之后,Java這門新生的語言就擁有了自己的會議——JavaOne,這次會議初試啼音就吸引了600多名參與者。除了擁有這么多的積極參與者來進 行Java的開發之外,各大知名公司也紛紛向Sun申請Java的許可。一時間,NetScape、惠普、IBM、Oralce、Sybase甚至當時剛 推出Windows 95的微軟都是Java的追隨者。
Java的應用就像是世界上的頂級玩家們組成的一個公開聯盟,告訴全世界我們大家就是都在用著Java。也正是因為如此,Java也找到了自己的歸宿。現在的J2EE已經成為中大型企業級應用的標準,成為承接數據庫和Web之間的一個重要橋梁。
當年Java的機會實在太多了,以至于很難知道到底該做什么。最終Java在應用服務器市場獲得了難以取代的地位,也確定了J2EE的發展方向,并且仍將延續下去。


1997-2001: 微軟與Sun的Java官司
文/孟巖

Java誕生的1995年,正是微軟在軟件產業地位達到巔峰的時代,Windows 95發布時的風光場面給人們留下的深刻印象至今難忘。盡管如此,作為最卓越的技術領袖,比爾?蓋茨仍然敏銳地注意到Java。當他了解了Java的一些細 節之后,給予了這樣的評價:“Java是很長時間以來最優秀的程序設計語言。”基于此,微軟于1996年3月申請并獲得了Java許可證。微軟對于 Java的這一熱情態度在當時大大提高了人們對Java的興趣和信心,但也有不少人擔心微軟會依靠自己強大的影響力在標準之外另立標準,從而破壞Java 的純潔性。
果然,從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分庭抗禮。
現在回過頭去看,當時的這一場官司對Java世界產生了深遠的影響。如果沒有這一場官司,也許很多Java程序員都在使用Visual J++,基于WFC開發Windows客戶端程序,同時不得不面對被兩個不同的事實標準所分裂的Java世界。


1998:Java 2平臺發布
文/陶文

1998年,Java 2平臺正式發布。經過了三年時間的發展、熱熱鬧鬧的攻關宣傳、紅紅火火的眾廠商的熱情參與,Sun終于知道Java適合干什么了。對比Java剛發明時的 技術定位,與Java的戲劇性觸“網”的那段歷史,Java 2平臺的發布可真算得上是有的放矢了。根據官方的文檔,Java 2是Sun意識到“one size doesn’t fit all”之后,把最初的Java技術打包成三個版本的產物,也就是著名的J2ME、J2SE、J2EE。
之所以說Java自從Java 2平臺發布之后,進入了現代。那是因為之前的歷史怎么看來都和現在程序員日常開發使用的技術無什么關系,比如Applet,已經很少有人使用了。Java 2之后的歷史就不一樣了,至少人們在推崇輕量級開發,猛批EJB時還不時會引用J2EE這個詞是如何誕生的。而Java 2的三大版本中,除了J2EE得到了長足發展和廣泛使用之外,J2ME也在手機市場上取得了遍地開花的結果。相較之下,J2SE難免落寞,只剩SWT這個 血統不純的家伙在Rich Client回歸的時代吸引著人們的眼球了。無論今天看來當時的Java 2有多么的不成熟,至少經過市場和時間的檢驗,Java 2規劃出來的三大方向把Java技術指向了光明的方向是勿庸置疑的。


1998:JCP成立并正式運作,
Java開源社群開始蓬勃發展
文/黃海波

1998年,JCP組織成立,并且開始把握Java的發展方向。JCP組織的開放性,不但使得所有對Java感興趣的商業公司可以參與Java的 發展,更重要的是JCP允許個人、非盈利組織、學校等加入,這就給Java帶來了巨大的活力。隨之興起的Java開源運動的最大貢獻是實現和鼓勵了知識共 享,在眾多熱情的開源程序員們的努力和分享下,很多原先只被商業公司掌握的技術、思想和產品可以被所有需要的開發人員免費或者以較低的價格獲得使用權, 并通過開放源代碼更容易的獲得反饋和改進意見從而進一步演化發展。我們知道,所謂知識不是孤立發展認知,而是人們的經驗,認識是思考交流和積累的產物。而 開源運動所帶來的開放、反饋、交流的風氣正是符合人類社會知識形成和發展的規律。
開源運動起源于西方的發達國家,有其現實背景和文化根源。1990年代可以說是IT產業的一個黃金時代。信息時代的興起對IT人員,特別是軟件 人員有著巨大的需求。而軟件開發又是一種類似藝術創作的腦力活動,和所有的藝術家、作家們一樣,在作品打上自己的印記并流傳在世界上是每一個創作人員的夢 想。互聯網時代下的高收入的舒適生活,早九晚五的編寫公司的代碼并不能滿足很多有激情的軟件開發人員的夢想,再加上西方傳統的基督教文化中十分推崇的分享 和交流,開源的出現和興起也就水到渠成了。今天,開源運動已經不僅僅是一些個人天才程序員們的游樂園地,而是發展成為一項開源軟件產業。


1998:WebLogic打開J2EE的魔匣
文/霍泰穩

Java語言的出現使得互聯網絡有了良好的交互性能,但這些很“酷”的技術僅被人們認為是一些小花招,它還無法消除企業級用戶對它的懷疑。 1998年,BEA公司宣布收購WebLogic公司,并接著推出由Sun公司第一個授權使用J2EE許可證的WebLogic Server應用服務器,這個Java版的AppServer一推出就引起業界極大的興趣。WebLoigc Server以其對標準的支持、強悍的運算能力和安全的架構設計等特性也很快征服了那些懷疑J2EE應用的人們。推出市場后不到一年,WebLogic Server就成為業內第一Java應用服務器。
這里我們援引一些當時著名咨詢公司的調查數據來說明問題,“在IDC的報告中,BEA在應用服務器和交易服務器領域市場份額第一;在 Gartner的報告中,BEA WebLogic Server擁有業內最廣泛的EJB應用安裝基礎;在Giga Group的報告中,BEA WebLogic Server市場份額占32%”。
因為應用服務器市場極大的發展潛力,在WebLogic Server之后,其它的很多公司也推出了自己的AppServer,如IBM的WebSphere、Sun公司的iPlanet等,逐漸地應用服務器取 代了傳統意義上的各類中間件,成為企業應用的基礎平臺。應用服務器的出現使得Java有了真正意義上的發展。


2002-2004: Sun與微軟的法律碰撞最終以喜劇收場
文/惡魔

2003年4月2 日,Sun與微軟達成16億美元的法律和解。如果不是晚了一天,許多人會以為這是一個在4月1日愚人節開的玩笑。盡管當時所有人都像是看到“太陽從西邊出來了”那樣張大了嘴巴,但這的確是事實。
根據兩家公司達成的版權協議,雙方會為采用對方的技術而支付專利費用,微軟向Sun提前支付3.5億美元使用費,Sun則承諾,如果Sun集成微軟的某些技術,也會向微軟付款。
毫無疑問,“私下了結”的方式對雙方而言都是最好的結果。就在協議簽署的當天,在美國舊金山由Sun和微軟為“拋棄十年恩怨、攜手合作“舉行的新 聞發布會上,盡管比爾?蓋茨沒有到場,但這并沒有防礙現場看起來異常輕松的氣氛。麥克尼利和鮑爾默各自穿了一件密歇根州底特律“Red Wings”曲棍球隊的運動服,并談及了一起在哈佛大學讀書的經歷,麥克尼利還說:“當時我們兩人是非常要好的朋友,當然我們也有吵架的時候。”人與人當 然可能成為終生的知己,但是公司與公司之間有的只能是利益上的分分合合。


2000-2004: JBoss和Eclipse
——Java開源軟件的王者
文/莫映

Java和開源幾乎就是天生的一對,這可以從無比興盛繁榮的Java開源軟件社區得到佐證。目前最有影響力的Java開源軟件項目,要數 JBoss和Eclipse。可以說,幾乎所有的Java開發人員都獲多或少的聽到過或接觸和使用過它們。前者是目前最優秀、應用最為廣泛的企業級開源 J2EE應用服務器,后者是功能完全可以替代商業產品的Java IDE。二者的覆蓋功能之全、支持工具之廣、子項目之多,幾乎可以僅憑借它倆來完成企業應用的開發構建到部署實施的全過程,而軟件開發者和客戶也都可以最 大程度上享受高質量,高可靠Java開源軟件所帶來的低成本優勢。
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的這種模式是否能獲得成功還要我們拭目 以待。
不管JBoss和Eclipse的未來發展如何,JBoss和Eclipse的成功已經讓我們看到了Java開源軟件的威力,祝愿它們一路走好。


2004:Java 5.0
文/莫映

2004年9月30日,代號為“Tiger”,研發歷時近三年的J2SE 5.0發布正式版本,這是Java平臺歷來發布版本中改動面波及最大的一次。
縱觀Tiger,“Ease of development”是其核心主題,這一點著重體現于語言特性上的改進,這在很大程度上,簡化了開發人員日常的編程任務,以往一些瑣碎的手工勞動都代 之以輕松自然,而又安全可靠的自動化實現。其中的注解功能,以及隨之而來的聲明式編程,還對構筑于J2SE 5.0之上的J2EE 5.0產生了巨大影響。盡管Tiger在語言特性上做了很大的動作,但作為Java技術的基礎支撐,這些改動都是深思熟慮的結果。
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機制,它將使由多個包組成的大 型項目變得易于管理。

----------------------------------------------------------------------------------------


十大人物

James Gosling : Java之父
文/陶文

作為Java之父,James Gosling的名字可謂是耳熟能詳。當人們評論一種編程語言時,總喜歡捎帶著把下蛋的母雞一起帶上。Java做為中國的編程語言學習者餐桌上有限的那么 幾樣餐點中的流行款式,自然是讓James Gosling風光不已。雖然James Gosling現在已經不是領導Java發展潮流的領軍人物了,做為Sun的開發者產品組的CTO,怎么算來也是身居高位了,俗事纏身吧,但是這并不妨礙 其對于Java一如既往的愛護,表達著各式各樣鮮明的觀點,引發一場又一場的爭論。
James Gosling是很愛Java的——是啊,哪有當父母的不愛自己的孩子的呢。James Gosling也是很愛Sun的——是啊,哪有當領導的不愛自己的公司的呢。于是我們在批評.NET的安全性的隊伍前頭,在褒揚Java性能的隊伍前頭, 在抨擊SWT開倒車的隊伍前頭,在給NetBeans大唱贊歌的隊伍前頭,我們都看到了James Gosling的身影。無論對錯、偏見或者固執,至少說明了Gosling的鮮明個性絲毫沒有受到年齡的影響。也許也只有這種天才而偏執的人物才能創造出 Java這般偉大的語言來吧。


Bill Joy : 軟件業的愛迪生
文/徐昊

Joy生于1954年,1982年與Vinod Khosla, Scott McNealy和Andy Bechtolsheim一起創建了Sun Microsystems,并從那時起擔任首席科學家,直到2003年離開。他是一位令人崇敬的軟件天才,他在軟件和硬件的歷史上留下了無數令人仰止的傳 奇。
在上個世紀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編譯器的作者。
關于Bill Joy驚人的軟件才能流傳最廣的一個傳奇是,據說他在上研究生的時候,想看看自己能不能寫一個操作系統出來,于是就在三天里寫了一個非常簡陋,但是可以使 用的Unix系統, 傳說就是BSD的前身。雖然如此夸張的才情令人難以置信,但是考慮到主角是Bill Joy,還是有一定的可信度的。Bill Joy碩士畢業之后,決定到工業界發展,于是就到了當時只有一間辦公室的Sun, 他作為主要設計者參與了SPARC微處理器的設計,負責設計最為關鍵的一部分電路。這樣兼精軟硬件的天才實在是讓人不得不佩服啊。1995年,Sun發布 了轟動世界的Java語言。當然,Bill Joy對Java也作出了不少的貢獻,首先是JINI——一種針對分布式服務的基礎連接技術。任何可以內嵌JVM的電子設備都可以通過JINI相互連接; JXTA是基于Java的P2P協議,允許互聯網上的軟件進行點對點交流和協作。
這個其貌不揚的瘦高個,有著凌亂的亞麻色頭發,被《財富》雜志譽為“網絡時代的愛迪生”的技術狂人,在短短的二十年間,創造了無數令人心動的軟 件。在MIT的BBS上曾有一個帖子,說微軟電話面試有一道題,問“Who do you think is the best coder, and why?”雖然回復的帖子中大家都聲明列舉的best coder排名不分先后,然而大多數人仍把Bill Joy列在第一位,或許可以從一個側面驗證Bill Joy在廣大Programmer心目中的地位吧。


Joshua Bloch : Java 2 元勛
文/莫映

早在1996年,適逢Java剛剛嶄露頭角,年內好事連連。先是1月份發布JDK 1.0,然后是5月底在舊金山召開首屆JavaOne大會,年末又是JDK 1.1緊跟其后。正是在Java技術如火如荼、大展拳腳的背景之下,Joshua Bloch來到了Sun,開始了他帶領Java社區步入“迦南美地”的漫長歷程。
很快,他被從安全組調入核心平臺組,從事底層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最大的語法改進。
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為數不多的幾個執行委員會成員之一。
Joshua Bloch給人的印象是謙遜平和,行事低調而不喜拋頭露面,一個典型的技術人員和實干家。不過即便如此,也絲毫不會減弱他對Java技術的卓越貢獻和對 Java社區的絕對影響力。有人說,如果他能更彰顯一些,就很有可能成為Java開發者中的領軍人物,就有如Don Box之于微軟社群。
2004年7月初,就在Tiger發布在即之時,就在Jusha Bloch剛剛榮獲Sun“杰出工程師(Distinguished Engineer)”的稱號之時,他突然離開Sun而去了正值發展態勢迅猛的Google。當他離開Sun的消息在TSS發布之后,眾多擁躉表達了懷念與 不舍之情。一年過去了,我們還沒有獲知Joshua的任何近聞,似乎又是他行事低調的一貫作風所致,不知他在Google狀況如何。希望Joshua依然 能繼續“摩西未盡的事業”,以他的影響力推動Java社群繼續前行。據稱,《Effective Java》的下一版會加入Java 5.0的部分,讓我們翹首以待吧。


Bruce Eckel : 功勛卓著的機會主義分子
文/孟巖

Bruce Eckel原本是一位普通的匯編程序員。不知道是什么因緣際會,他轉行去寫計算機技術圖書,卻在此大紅大紫。他成功的秘訣不外乎兩點:超人的表達能力和捕 捉機會的能力。他最早的一本書是1990年代初期的《C++ Inside & 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?總之,是什么我都不奇怪。


Rickard Oberg :J2EE奇才
文/熊節

Oberg的作品很多,流行的代碼生成工具XDoclet和MVC框架WebWork都出自他的手筆。這兩個框架有一個共同的特點,即它們的功能 雖然簡單,但設計都非常優雅靈活,能夠很方便地擴展新功能甚至移植到新環境下使用。優雅的設計源自Oberg的過人才華,簡單的功能則折射出他玩世不恭的 人生態度。正是這兩種特質的融合,才造就了這個不世出的奇才。
1999年,JDK 1.3發布,其中帶來了一個重要的新特性:動態代理(Dynamic Proxy)。當所有人都還在對這項新技術的用途感到迷惑時,Oberg發現用它便可以輕松攻克EJB容器實現中的一些難關。這一發現的產物就是一本 《Mastering RMI》,以及大名鼎鼎的JBoss應用服務器。但Oberg很快又讓世人見識了他的玩世不恭。由于和總經理Marc Fleury在經營理念上不合,Oberg抱怨“法國的天空總讓我感到壓抑”,甩手離開了自己一手打造的JBoss。此后的幾年里,他和老友Hani Suleiman不斷地對JBoss的“專業開源”模式和Marc Fleury的商人味道冷嘲熱諷,讓眾人為他的孩子氣扼腕嘆息。
2002年10月,微軟推出Petstore示例應用的.NET版本,并宣稱其性能比Java Petstore高出數倍。正是Oberg深入分析這個示例應用的源代碼,在第一時間指出它大量運用了SQL Server專有的特性,性能對比根本不具參考價值。后來Oberg又先后關注了AOP和IoC容器,兩者都成為了J2EE架構的新寵。


Doug Lea : 世界上對Java影響力最大的個人
文/KIT

如果IT的歷史,是以人為主體串接起來的話,那么肯定少不了Doug Lea。這個鼻梁掛著眼鏡,留著德王威廉二世的胡子,臉上永遠掛著謙遜靦腆笑容,服務于紐約州立大學Oswego分校計算器科學系的老大爺。
說他是這個世界上對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包。
值得一提的是: Doug Lea也是JCP (Java小區項目)中的一員。
Doug是一個無私的人,他深知分享知識和分享蘋果是不一樣的,蘋果會越分越少,而自己的知識并不會因為給了別人就減少了,知識的分享更能激蕩出 不一樣的火花。《Effective JAVA》這本Java經典之作的作者Joshua Blosh便在書中特別感謝Doug是此書中許多構想的共鳴板,感謝Doug大方分享豐富而又寶貴的知識。這位并發編程的大師級人物的下一步,將會帶給 Java怎樣的沖擊,不禁令人屏息以待。


Scott McNealy :SUN十年來的掌舵者
文/KIT

McNealy,Sun的CEO、總裁兼董事長。他曾經狂傲的說:“摧毀微軟是我們每個人的任務。”這位英勇的硅谷英雄,似乎帶頭起義,試圖組織 一個反微軟陣線聯盟,以對抗微軟這股龐大的托拉斯惡勢力。他時常口出驚人之語,在公開場合大肆的批評微軟,并曾經說微軟的.NET是.NOT。
Scott McNealy先后畢業于哈佛大學及史丹佛大學,分別持有經濟學學士學位及企管碩士。1982年MBA畢業的他和三個同學共同合伙創建了Sun,并于 1984年成為Sun的執行官。“要么吞了別人,不然就被別人吞了”是Scott McNealy的名言錄之一。他擅長以信念帶動員工,鼓舞士氣。極富自信的他,對于認定的事,總是堅持自己的想法,因此有人形容他是一個剛愎自用的決策 者。
身為Sun這艘船的掌舵者,Scott McNealy能夠看多遠,Sun就能走多遠。Scott McNealy認為將來軟件界是一個只有服務,沒有產品的世代。他希望打造出Sun不是一個純靠硬件賺錢的公司。從Open Source到Open Solaris,Sun希望可以成為提供整合性解決方案的服務廠商。Solaris 10 + UltraSPARC是否可以像Scott McNealy希望的是下一匹世紀黑馬呢?Sun是否能以股價來證明華爾街分析師及普羅大眾的誹短流長?Scott McNealy是否能帶領著Sun成為繼微軟之后的下一個巨人,一場場IT界的爭霸戰值得我們拭目以待。


Rod Johnson : 用一本書改變了Java世界的人
文/ 劉鐵鋒

Rod在悉尼大學不僅獲得了計算機學位,同時還獲得了音樂學位。更令人吃驚的是在回到軟件開發領域之前,他還獲得了音樂學的博士學位。有著相當豐 富的C/C++技術背景的Rod早在1996年就開始了對Java服務器端技術的研究。他是一個在保險、電子商務和金融行業有著豐富經驗的技術顧問,同時 也是JSR-154(Servlet 2.4)和JDO 2.0的規范專家、JCP的積極成員。
真正引起了人們的注意的,是在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架構也逐漸得到人們的認可,甚至在大型的項目架構中也逐漸開始應用。
Rod Johnson的新作《Expert One-on-one J2EE Development without JEB》則更讓人吃驚,單單“Without EJB”一詞就會讓大多數J2EE架構師大跌眼鏡了。不過Rod Johnson可能僅僅是想通過“Without EJB”一詞表明應該放開門戶之見。這也是Rod Johnson一貫的作風,。也許正是這種思想,促使得Rod Johnson創建了Spring,真正改變了Java世界。



Alan Kay :Java的精神先鋒
文/徐昊

Sun的官方Java教材中有一句話,說Java是“C++的語法與Smalltalk語義的結合”。而Smalltalk的創造者就是Alan Kay。
Alan Kay于1970年加入Xerox公司的Palo Alto研究中心。早在70年代初期,Alan Kay等人開發了世界上第二個面向對象語言Smalltalk,因此,Alan Kay被譽為Smalltalk之父。2003年,Alan Key因為在面向對象程序設計上的杰出貢獻,獲得了有計算機界的諾貝爾獎之稱的ACM Turing Award。
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一廂情愿的單戀吧。



Kent Beck : 領導的敏捷潮
文:劉鐵鋒

Beck全家似乎都彌漫著技術的味道。生長在硅谷, 有著一個對無線電癡迷的祖父,以及一個電器工程師父親。從小就引導Kent Beck成為了業余無線電愛好者。
在俄勒岡州大學讀本科期間,Kent Beck就開始研究起模式。然而在他最終拿到計算機學位之前,他卻是在計算機和音樂中交替學習。似乎Java大師都能夠有這樣的能耐,另一Java大牛Rod Johnson同樣也擁有音樂學的博士學位。
Kent Beck一直倡導軟件開發的模式定義。早在1993年,他就和Grady Booch(UML之父)發起了一個團隊進行這個方面的研究。雖然著有了《Smalltalk Best Practice Patterns》一書,但這可能并不是Kent Beck最大的貢獻。他于1996年在DaimlerChrysler啟動的關于軟件開發的項目,才真正地影響后來的軟件開發。這次的杰作就是XP(極限 編程)的方法學。
和軟件開發大師Martin Fowler合著的《Planning Extreme Programming》可謂是關于XP的奠基之作。從此,一系列的作品如《Test Driven Development: By Example》,《Extreme Programming Explained: Embrace Change》讓更多的人領略到了極限編程的精髓,也逐步導致了極限編程的流行。
Kent Beck的貢獻遠不僅如此。對于眾多的Java程序員來說,他和Erich Gamma共同打造的JUnit,意義更加重大。也許正式這個簡單而又強大的工具,讓眾多的程序員更加認可和信賴極限編程,從而引起了Java敏捷開發的狂潮吧。

------------------------------------------------------------------------------------------

十大產品

Sun JDK :Java的基石
文/莫映

眾所周知,流傳于市的JDK不單Sun一家,比如IBM的JDK、BEA的JRocket、GNU的GCJ,以及如Kaffe這樣的開源實現,不一而足。但是,根正苗紅的Sun官方JDK一直以來都是備受矚目的主流,它對Java社區的影響也是舉足輕重。
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。
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)已經步入了一個新的高度。



Eclipse :以架構贏天下
文/惡魔

IBM是在2001年以4000萬美元種子基金成立Eclipse聯盟,并且捐贈了不少程序代碼。如今,該組織有91個會員,包含許多全球最大的軟件商。根據Evans Data公司的資料,Eclipse是目前最受歡迎的Java開發工具。
Java廠商若要共同對抗微軟,彼此之間就要有共同的開發工具才行。
在Eclipse平臺上,程序員可使用好幾種不同的語言。在前端方面,用戶可整合多種工具來撰寫Plug-in程序或Unit Test。Eclipse最大的特色就在于其完全開放的體系結構,這代表任何人都可下載并修改程序代碼,給Eclipse寫插件,讓它做任何你能想到的事 情,即所謂“Design for everything but nothing in particular”。
Eclipse基金會的架構比較特別,反映出企業現今對于開放原始碼計劃也越來越積極主動。Eclipse不像一般開放源碼軟件容許個人的捐獻程序,該基金會是由廠商主導。不論是董事會成員或者是程序贊助者幾乎都來自于獨立軟件開發商(ISVs)的員工。
Eclipse首席執行官Mike Milinkovich說,這種廠商會員制是特意設計的;他說Eclispe軟件開發快速就是因為會員制的關系,同時又加上開放源碼開發模式的臨門一腳。 這與一般透過標準組織的做法全然不同。 這其實正好驗證了一句老話:“開放即標準”。


JUnit/Ant : 讓Java自動化的絕代雙驕
文/劉鐵鋒

在Java程序員必備的工具中,共 同擁有且交口稱贊的恐怕就非JUnit、Ant莫屬了。一個是單元測試的神兵利器,一個是編譯部署的不二之選,它們讓Java的開發更簡單。
JUnit由XP和TDD的創始人、軟件大師Kent Back以及Eclipse架構師之一、設計模式之父Erich Gamma共同打造。名家的手筆和理念使得JUnit簡單而強大,它將Java程序員代入了測試驅動開發的時代。JUnit連任了2001、2002年 “Java World編輯選擇獎”以及2003年“Java World最佳測試工具”和2003年“Java Pro最佳Java測試工具”等眾多獎項,深受Java程序員好評。
Ant是開源項目的典范,它讓IDE的功能更加強大,從Sun的NetBeans到JBuilder,主流的IDE中處處都有它的身影。 “Another Neat Tool”原是它的本名,但這已經漸漸不為人知。它徹底地讓部署自動化,而程序員需要做的僅僅是幾條簡單的配置命令。和JUnit一樣,Ant也榮獲了眾 多的殊榮:2003年JavaWorld“最有用的Java社區開發的技術編輯選擇獎”, 2003年Java Pro“最有價值的Java部署技術讀者選擇獎”,2003年“JDJ編輯選擇獎”,也讓Ant受到的多方的認可。
Ant對JUnit的全面集成,則使得一切都變得更加完美。只需簡單地配置,從自動測試到報告生成,從編譯到打包部署均可自動完成。強大的功能,簡單的配置,讓Java程序員高枕無憂。實可謂讓Java自動化的絕代雙驕。

Websphere : 活吞市場的大鯨
文/jini

1999年, IBM與Novell簽訂合作協議,成功地提供電子商務的解決方案給予原先使用NetWare的用戶。同年更是推出了WebSphere Application Server 3.0,并且推出WebSphere Studio與VisualAge for Java讓工程師可以快速開發相關的程序。2001年,IBM更是宣布將應用服務器、開發工具整合在一起,與DB2、 Tivoli及Lotus結合成為一套共通解決方案,如今、IBM更是并入了Rational Rose ( UML tools )讓開發流程更是完整化。
Sun在Web Services的策略方面遠遠落后于微軟與IBM, 當他們手拉手在研訂Web Services規范, 加上IBM買硬件送軟件或是買WebSphere送DB2的策略讓企業大佬們紛紛轉向IBM的陣營, Sun才驚覺大勢已去。WebSphere復雜的安裝,深奧的設定,難以理解的出錯訊息不斷地挑戰開發者的耐心與毅力。
IBM如今已經不是將WebSphere定義為單一產品,它已經是一個平臺的代名詞。它里面的產品目前包含了應用服務器、商業整合、電子商務、 數據訊息管理、網絡串流、軟件開發流程、系統管理、無線語音等等。非常多樣化,也讓企業界愿意相信WebSphere可以帶給他們一套完整的解決方案。同 時, IBM也在推廣SOA的概念, 簡單來說, 利用Web Service的耦合性與工作流程的整合, 為企業內部打造以服務為導向的架構。
IBM捐獻出Eclipse帶給Java開發人員對IDE的重新掌握。未來是否會捐獻出WebSphere的哪一個部分成為OpenSources, 或許, 又是改寫Java世界的時刻了。



WebLogic : 技術人的最愛
文/jini

1995年, BEA成立了, 初期以Tuxedo數據轉換的產品為基礎, 成長之迅速是歷年來最強的企業。 1998年, BEA推出以Java為基礎的網絡解決方案, 提供了完整的中間層架構, 更同時支持EJB 1.0 及微軟的COM組件, 方便的管理接口擄掠了工程師的心。 在IBM和Oracle尚未準備好迎擊的時候, BEA已經席卷企業應用平臺的市場。 WebLogic無論在市場領先度與技術領導性與策略遠觀性都優于當年的所有應用服務器廠商。
如今WebLogic不僅僅是應用平臺服務器的名稱, 而是BEA對于整個企業解決方案的總稱, 無論是WebLogic Portal或是WebLogic Integration配合著Workshop開發環境, 來自微軟的UI開發團隊讓Workshop幾乎達到所見即所得。 接著, 在下一個版本之中, BEA的BeeHive開放源代碼計劃將釋出中間層控件的開發模塊, 并且與Eclipse合作共同打造新一代的開發環境。 如此強而有力的技術支持, 更是讓顧客愿意使用WebLogic平臺的最大原因。
代號為“Diablo”的 WebLogic Server 9.0小惡魔已經出現了, 目前雖然僅僅是BETA版, 以Portlet 方式打造的管理接口與完整且美妙的WebServices支持, 實在很難找到可以挑剔的地方, 雖然去年被IBM的技術性推銷超越了市場占有率, 不過接下來SOA的平臺競爭現在才開始, BEA的LOGO也加入“Think liquid”并且推出新的AquaLogic平臺做為數據服務平臺, 可見, Java的應用服務器的戰爭, 還會繼續進行著。



JBuilder : Java開發工具的王者
文/劉鐵鋒

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開發工具的王者。
Borland以每半年左右推出一個新版本的速度,讓眾多的對手倒在了沙場。而Microsoft因為與Sun的官司,也使得一個強大的對手退 出了戰爭。2001年,加入了對企業協作支持的JBuilder 5以及強化了團隊開發工具的JBuilder 6打敗了最后一個對手Visual Age For Java。2002年JBuilder 7推出之后,再也沒有其他廠商與JBuilder競爭。
孤獨的王者并沒有停下腳步,在2003年到2005年間,JBuilder也仍然延續了其半年一個版本的速度,推出了8、9、10、2005四 個版本。強大的功能以及持續的改進,也讓Java程序員多了一分對能夠在開發工具市場上與Microsoft血拼十數年的Borland的敬仰。



Oracle : Java人永遠的情結
文/熊節

在林林總總的數據庫之中,有一種尤其令人又愛又恨、印象深刻,那就是關系型數據庫市場的“大佬”——Oracle。
從公司的角度,Oracle和Sun有著諸多相似之處,例如:兩家公司都擁有一位個性鮮明的CEO。早在Java誕生之初的1995年, Oracle就緊隨NetScape從而第二個獲得了Java許可證。從那以后,Oracle對Java的鼎力支持是Java能夠在企業應用領域大獲成功 的重要原因之一。
所有J2EE程序員都知道,Oracle的JDBC驅動雖然與Oracle數據庫配合良好,但在不少地方使用了專有特性。其中最為著名的就是 “CLOB/BLOB問題”,諸如此類的問題給開發者帶來了很多麻煩。為了同時兼顧不同的數據庫,他們不得不經常把自己的一個DAO(數據訪問對象)寫成 兩份版本:針對Oracle的版本和針對其他數據庫的版本。有不少人為了開發便利,舍棄了數據庫之間的可移植性,將自己的產品綁定在Oracle的專有特 性上。
Oracle提供的Java開發工具也與此大同小異。不管是數據庫內置的Java支持還是JDeveloper IDE, Oracle的Java工具都和Oracle數據庫有著千絲萬縷的聯系。看起來,只要Oracle還是數據庫市場上的“頭牌”,了解、學習Oracle的 專有特性,周旋于Oracle特有的問題和解決方案之中,就將仍舊是J2EE程序員在數據庫基礎和SQL之外的必修功課。對Oracle的愛與恨,也將仍 舊是Java人心頭一個難解的情結。



Struts、Hibernate : 讓官方框架相形失色的產品
文/劉鐵鋒

好的框架能夠讓項目的開發和維護更加便捷和順利。相比Sun官方標準的遲鈍以及固執,開源框架也更得到Java程序員的共鳴。Struts以及Hibernate就是這樣一類產品,它們簡單、優雅,更讓官方的產品相形失色。
談起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應用框架的首位。
Hibernate則在某種程度上改變了人們對構建J2EE的思路。相比其EJB的Entity Bean的映射技術,Hibernate則顯得更加簡潔和強大。五分鐘就能把Hibernate跑起來,讓更多的Java程序員享受到了開發的樂趣。第 15屆Jolt大獎中,最優秀數據庫、框架以及組件的獎項中,Hibernate當仁不讓獲得頭籌;不僅如此, Hibernate甚至還影響了官方的標準。在眾多Java程序員翹首以待的EJB 3.0的規范中,Hibernate得到了支持。
Java開源的繁榮不僅讓眾多Java的開發者享受到了更多的便利,甚至影響了官方的標準。恐怕這也是作為Java人獨有的樂趣之一吧。



PetStore : J2EE人的必修課
文/陶文

很少有一個例子項目如PetStore這 般廣為人知,而這很大程度上要歸功于Sun很“英明”地把PetStore做成一個只展示架構而在性能調優上留下了大大余地的例子。圍繞著性能話題,產生 了頗為有趣的廠商之間以及平臺之間的Pet Wars。除去這些關于性能的流言蜚語乃至中傷,PetStore在展示J2EE1.3平臺的架構、演示什么叫分層方面還是有著很大的功勞的。而且 PetStore在架構方面的豐富性使得其成為J2EE的那些輕量級小兄弟們展示自身的一個必選科目。
不談那些圍繞PetStore的口水,那些數不盡的盜版,PetStore給開發新手帶來的最重大的影響,我想應該是架構的觀念而不是性能,也 不是業務。做為一種技術的Demo,這無可非議。但是如果你是一個新手,跟著PetStore亦步亦趨地學習J2EE開發,難免會陷入過度設計、華而不實 之類的困境。圍繞著.NET的PetStore的克隆PetShop展開的架構與性能的大討論,是不是也在促使我們學習新技術時應該以解決問題為導向呢? 特別是當你想把一個如PetStore這般的Sample Project的技術照搬到你的現實世界的Real Project來時。
------------------------------------------------------------------------------------------

十大組織

Sun : 因為Java而永被榮光
文/孟巖

Sun是1980年代初期由斯坦福大學三位年輕學生創立的公司。與一般人的印象不同,“SUN”的本意并不是企圖剽竊天上那顆溫暖的恒星的威名,而是“斯 坦福大學網絡”的意思。Sun在“前Java”時代就因為SPARC芯片、Solaris操作系統和“網絡就是計算機”的口號而為人所知。1990年12 月,Sun啟動了一個看上去沒什么意思的嵌入式軟件項目。然而,基于C++的開發很快遇到了麻煩。一個創新型技術公司的特色立刻顯示出來,一群天才不是去 深入C++,而是另辟蹊徑,發明了Java。這個傳奇故事已經盡人皆知,但是其中所包含的精神卻始終令人望空凝思。
Java的發明,使得Sun真正有機會在軟件的歷史天空中放射出太陽的光芒。Sun發明了Java,并且在長達十年的時間里始終走在Java大 潮的最前端。Sun是Java的老家,是Java慈愛的母親,這一切任何人都改變不了。雖然Sun似乎沒能夠從Java中獲得應有的金錢回報,但這絲毫沒 有挫傷Sun對于Java的母愛,還有對于Java大潮的舍我其誰的領導氣概。
所有人都迷戀富有的感覺,但是也遲早會意識到錢不是世上最寶貴的東西。這個世界并不缺少會賺錢的公司,但是能夠靠著創新型技術推動整個世界進步的公司卻是鳳毛麟角。Sun應該感到驕傲,他們將因為Java而在歷史的天空里發射出太陽的光芒。



IBM : Java經濟的最大受益人
文/惡魔

Sun公司是Java的發明人,但IBM卻是Java最大的受益者。是IBM搶占了利潤豐厚的應用服務器市場的頭把交椅,是IBM在Java技術 上投入最多的金錢,擁有最大的影響力和最好的開發者社區。可以毫不夸張地說,Java使IBM的軟件體系得到復興,在某種意義上,甚至可以說,是Java 創造了這種復興。Java之后又來了Linux,這種建造在不屬于自己的平臺上以獲得成功的理念更是變得非常有影響力。正是這種理念鑄就了今天IBM “按需計算,服務為王”的王者風范。
2004年三月,IBM以Java的解放者的姿態借機向Sun發難。IBM公司負責新興技術的副總裁史密斯在一封公開信中表示,IBM愿意與Sun合作成立一個項目,意在通過開放源代碼開發模式管理Java的開發工作。
墻內開花,墻外香。面對IBM的成功,到底是誰妒嫉呢?或許去程序的社區中逛逛聊聊,明眼人是不難發現事實真相的。也許Sun應該好好向IBM學 習經營之道。盡管利潤額不如硬件及服務部門,但IBM軟件部門的利潤率是最高的——高達85%的利潤率足以令人驚嘆。在最近的一個季度里,IBM軟件部的 利潤率上升了8%,其中WebSphere產品組的利潤率上升了14%。
正是IBM在開源和Java上的全身心地投入又秉承開放性的原則,今日的Java才能以日進千里的速度將許多競爭對手遠遠拋在后面。Java 10年,IBM功不可沒。



BEA : 用AppServer影響Java陣營
文/霍泰穩

十年前誕生的Java并不是一開始 就那么引人注目的,雖然用Applet也曾為互聯網絡帶來一抹亮色,但畢竟只是Toy。在企業級應用市場上,Java一直沒有什么起色,雖然Java的支 持者一直在鼓吹它有著大型企業級應用的強悍功能。過高的期望與低能的產品,一時間頗讓人懷疑Java的路是否已經走到了盡頭?可以說是WebLogic Server的出現逐漸打消了人們的顧慮,BEA公司慧眼獨具在2001年收購的這個產品將人們的目光吸引到電信、金融、政府等Java企業級應用方面, WebLogic Server以其優良的性能讓人們看到Java應用廣闊的未來。雖然隨后在Java應用服務器方面出現了像IBM公司的WebSpere、開源軟件 JBoss等Java應用服務器,但WebLogic Server幾乎占領世界前500強所有企業的應用服務器市場地位依然無法撼動。
Java現在已經不單純是一個語言,從另一方面它也代表著開放與創新。很多以Java產品為基礎的公司或者從事Java開發的程序員骨子里都有 著開放與創新的烙印,BEA公司的發展深深地印證了這一點。與合作伙伴的密切合作向Java社區貢獻產品基礎源代碼、加入權威開源組織參與Java標準的 制定等證實著BEA的開放,而其產品從WebLogic Server一種拓展到WebLogic Platform、WebLogic Portal、WebLogic Workshop等其它領域又證實著它的創新能力。



Oracle : 早起的鳥兒有蟲吃
文/孟巖
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開發工具世界里也自成一派。這一切不能不歸功于當初的眼光遠大。


Apache : 開源軟件的品牌保證
文/陶文

Java程序員的日常工具箱中,我們可以發現Ant、Tomcat、Log4、Lucene這些鼎鼎大名的開源產品。而它們的共同點在于,都是由 Apache Software Foundation社群中杰出的開發者開發的開源項目。Apache這個名字在Java的世界中實在太出名了,以至于“Apache”這六個字母成為開 源項目品質保證的代名詞。Apache是自由開源的一面旗幟,其Apache License更是成為商業友好的License的首選,只SourceForge上就有1000多個以Apache License授權的項目,其流行程度可見一斑。
但是,如我們所知,Apache最早聞名IT界是靠高性能的Web服務器,其歷史甚至和Java一樣長。Apache對于Java的偏愛,以及 其發展的速度也映射出了Java繁榮的一角。現在去它的主頁上看看,滿目望去全部都是Java的開源項目,早就不光是其C服務器的老本行了。Apache 對Java最大的貢獻就是提供了這么一個精品的開放舞臺,讓杰出的開發者和成熟的開源項目走到一起,共同給Java語言提供一個豐富的工具倉庫。對于一種 語言、一個平臺來說,其庫的豐富程度對于開發者來說的重要性再怎么強調也不為過。勿庸置疑,Aapache上會出現越來越多的Java開源項目,而我們開 發者也將更多地得益于這令人目不暇接的繁榮。



TheServerSide : 論壇的專業精神
文/劉天北

成立于2000年5月,TSS最初以一本書而廣為人知。它的創始人Ed Roman同時也是J2EE名著《Mastering EJB》的作者;Roman運營著一個J2EE咨詢/培訓公司TheMiddlewareCompany(簡稱TMC),TSS當時是TMC的下屬部門; 為了擴大企業的影響,Roman在TSS網站上免費發布了那本書的電子版。J2EE程序員要吃下這個香餌,就得在論壇中注冊;注冊的同時,多半也會看一眼 論壇的內容;一看之下,大部分人都被吸引住,成了社區的忠實成員。
TSS究竟有什么吸引人的秘訣?首先,它有一支能力過人的運營團隊,除了Roman本人之外,其中還有好幾人都是J2EE領域的頂尖專家;第 二,TSS和TMC定期會推出專家研討會/視頻訪談、技術白皮書、評測報告,通讀TSS提供的這些內容,基本上就可以把握技術的當前趨勢。但這還不是全 部。最可貴的還是TSS的社區風格:他們深諳技術,但不盛氣凌人;思想敏銳,但不因此缺乏審慎和大局感。其中大多數人都已在自己的開發領域頗有建樹,在 TSS上的活動既給他們提供了與同行進行深度交流的機會。一個新成員進入社區,就像參加了一個起點很高的專業俱樂部,這不是一個求解“怎樣設置 JAVA_HOME環境變量”之類問題的地方。事實上,在J2EE技術發展的若干轉折點上,TSS都起到了關鍵的推動作用。
幾經易主之后,J2EE咨詢培訓公司TMC在2004年關閉;TSS則被IT媒體集團TechTarget收購。我們期待著它更加繁榮的未來。

JBoss : 職業開源軟件組織
文/劉天北

J2EE的嬰兒期,“應用服務器”原本是“昂貴”的代名詞。但從1999年起,Marc Fleury和Rickard Oberg等人就已經著手改變這種狀況。他們開發的開源EJB容器當時叫做“EJBoss”,在Sun公司的干預下(注意,“EJB”是注冊商標), JBoss獲得了今天的名字。雖然從問世起就一直受到關注,但JBoss第一個達到產品化標準的版本可能是它的2.2版。它的易用讓人一見難忘:除了標準 部署描述符,無需編寫專用的xml配置文件。Oberg自豪地說,“我們的架構并不是按照EJB規范指定的路線設計的,因此也沒有走大多數應用服務器走過 的彎路。”
Jboss 3.x版本保持了一貫的創新精神,在用戶中間獲得了更廣泛的認可。但是,文檔要收費下載、在郵件列表上提問常常會遭到Fleury等人的斥責。無疑, JBoss的創始者也意識到了自己的幼稚:開源軟件只能靠服務盈利,賣文檔賺錢有限、罵用戶當然更損害企業形象。
雖然以Oberg為首的許多程序員退出了開發隊伍(其中很多人成了JBoss的死敵),在開源軟件領域也面臨JOnAS Geronimo等新老對手的競爭,但JBoss還是以不斷推出的新版本站穩了腳跟。在技術上,它是策動J2EE演進的重要力量:擬議中的EJB 3也要追隨Jboss 4倡導的開發范式,以至于二者的代碼樣本之間的差別幾乎難以分辨;在商業上,JBoss與Sun公司言和修好,甚至還獲得了數量可觀的風險投資。 JBoss已經像擁護者預期的那樣,成為了應用服務器領域的Linux。



Borland : 深度介入Java
文/左輕候


除了Sun以外,也許沒有一家公司 像Borland這樣深層地介入Java。Borland開發了最早的Java編譯器之一,Borland的工程師參與了早期JDK的設計, Borland的JBCL(JavaBeans Component Library) 技術也成為后來Java Bean規范的基礎。但是Borland對Java世界最大的影響還是JBuilder。
1997年11月,Borland JBuilder 1.0發布。雖然第一個版本相對于競爭對手并沒有表現出明顯的優勢,但是Borland憑借深厚的技術實力和正確的市場策略,不斷地超越了對手。 JBuilder 3.5成為業界第一個100%基于Java架構的開發工具,并且市場份額很快超過了50%。在隨后的版本中,JBuilder持續改進對團隊開發、 J2EE架構、Mobile技術等方面的支持,最終成為了Java開發工具市場,特別是大型企業級Java開發市場中的霸主。JBuilder的成功,很 大一個原因來自于Borland堅持的平臺中立性,即對不同廠商的解決方案提供一視同仁的支持。
2005年初,隨著Eclipse社區的迅速崛起,Borland進入了Eclipse的董事會,成為戰略開發者(Strategy Developer) ,并宣布將推動Borland的其它產品與Eclipse的集成。在隨后發布的一份文件中,Borland宣稱JBuilder的未來版本將放棄原有的 PrimeTime架構,而基于Eclipse架構。這個代號為“Peloton”的版本預計于2006年下半年發布。
Borland對Java的另外兩個主要貢獻來自Together和BES(Borland Enterprise Server)。Together是著名的建模工具,能夠與包括JBuilder在內的許多開發工具進行集成,全球市場份額占有率排名第二。BES AppServer是一種J2EE服務器,在全球市場份額占有率上次于WebLogic和WebSphere,排名第三。



JCP : Java世界的聯合國
文/黃海波


當聯合國正在為安理會改革問題 吵得如火如荼時,Java世界的“聯合國安理會”已經成功地運作了七個年頭。JCP(Java Community Process)在1998年由Sun發起成立,目標是通過一個開放、合作和鼓勵參與的非盈利組織來發展和推進Java和相關的技術。正是由于JCP計劃 的推出可以讓所有對Java感興趣的軟硬件廠商,個人和組織都能參與到技術規范的制定和發展過程中,協調各方的興趣和利益、集思廣益,才可以讓Java在 短短的幾年內異軍突起,成為可以和微軟開發平臺抗衡的一個主流開發語言。JCP計劃既然是一個組織,自然也有一定的架構。JCP組織架構主要包括PMO (Program Management Office)、JCP成員、EC、EG。事實上,JCP的架構就好像一個Java世界的聯合國。雖然也有不少人批評JCP成為各派利益的角力場,因而效 率低下;但是,它畢竟為Java的順利發展很好地掌握了方向。



微軟與Java : 不得不說的故事
文/孟巖


微軟跟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發揮的作用。



Alex 2006-08-13 21:35 發表評論
]]>
[轉]關于技術發展路線和當前形勢http://www.oiklr.tw/alex/archive/2006/08/13/63354.htmlAlexAlexSun, 13 Aug 2006 11:24:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/13/63354.htmlhttp://www.oiklr.tw/alex/comments/63354.htmlhttp://www.oiklr.tw/alex/archive/2006/08/13/63354.html#Feedback0http://www.oiklr.tw/alex/comments/commentRss/63354.htmlhttp://www.oiklr.tw/alex/services/trackbacks/63354.html一、軟件開發技術

1)服務器端

在最近5年內,Java還是主流,不光是因為當前的普及程度和遺留系統問題,而且除Microsoft幾乎所有大公司都投資到Java上面的原因,此外開 源也是一股無法忽略的力量:除了Java方面的開源框架在推動Java,也有Linux在帶動java企業應用在普及(別忘記dotnet只能在 Windows Server上面運行)

dotnet有自己的優勢,但是在五年內無法和Java取得均勢,不光是因為Java普及帶來的優勢,也不光因為開源界對java的推動,也不光 因為其他大公司在java上面的投資,而是很多公司的行業性質決定了dotnet的出局,例如電信行業,金融行業,電子政務行業等等,是根本沒有可能采用 dotnet的。

Python和Ruby算不上后起,但是很有競爭實力,不過基于上面的原因,仍然不能成為主流。

在Java服務器端技術中,清晰的分為兩條路線:高端的商業路線,這條路線是EJB3,J2EE5.0;低端的開源路線,這條路線是 Hibernate, Spring。這兩條路線也有重疊的地方,例如開源的Struts幾乎成為J2EE Web層的標準,開源的Hibernate奠定了EJB3的基礎。但是劃分路線不是基于技術上的區別,而是基于商業運作上的區別。注重技術支持和商業服務 的公司會選擇前者,注重成本控制和選擇自由的公司會選擇后者。

商業路線的技術方案是:EJB3+Struts;
開源路線的技術方案是:Spring+Hibernate+Struts/Webwork

Struts是一個很成功的開源框架,它的地位短期內還無法動搖,JavaEye有一項使命,就是動搖Struts在Java Web領域的地位,把它趕下王座,把Webwork扶上位!

商業的Web層技術,JSTL算是一個不錯的東西,但是和靈活的模板語言如FreeMarker相比,卻有很大的差距。JSF基本上是一個沒有前途的東西。商業Web層技術因為一直沒有出現好的應用,這樣也導致了Struts的上位。

服務器端業務層和持久層框架,我非常看好EJB3,原因也不用多談了,從商業上來說,需要這樣一個東西,跨國公司們也需要這樣一個產品來賣,來取 代糟糕的 EJB2。開源的方案里面,Spring+Hibenrate是一個很好的商業方案的開源替代,他們不存在很直接的競爭,而是一個互補的關系。這里比較尷 尬的反而是JDO:JDO是商業產品(目前沒有好的開源實現),造成開源應用不會對它感興趣,JDO沒有一個像EJB容器那樣的脫管環境,造成商業方案對 它不感興趣。不過有了JDO,我覺得是對EJB3,對Hibernate形成一個良好的競爭環境,這一點是非常有利的。

2)客戶端技術

準確的說是RIA應用。雖然我前面對XAML進行了正面的評價,但是我認為我前面有些結論給錯了。經過這段時間,我覺得,XAML即時在多年之后,也未必能夠成為一個非常成功的解決方案。道理很二:

1、XAML會帶來比ActiveX更嚴重的安全性問題。
XAML本質上就是一個本地應用程序,雖然號稱可以在IE瀏覽器里面運行,但IE就是一個皮而已,XAML應用具備對本地資源完全的訪問能力(就 算IE限制也沒有用,IE限制就喪失功能,那樣的話,功能并不會比Javascript來得更多;不限制的話,就為所欲為了),因此只要IE具備了運行 XAML的能力,黑客將可以非常輕易的通過IE進行入侵,這僅僅需要引導用戶在不知不覺中訪問一個惡意的網頁就搞定了!用戶必須面臨選擇:要么禁止IE對 XAML的運行能力,要么接受隨時被攻擊的危險。

2、XAML應用本質上也是RIA應用,因此必須進行大量的RPC調用
當前XAML采用XML Web Services進行通訊,這是一種低效的RPC。當前的XAML案例中并沒有注意到RPC領域,實際上根據我現在做RIA的體驗來說,RPC絕對不是一個簡單的事情,要考慮的問題非常多。

從當前的階段來說,最實際可用的方案有兩個:

1、AJAX
實際上就是基于XMLHTTP的JS異步交互,這個東西已經出現很多年了,最近隨著Google應用和Sun Blueprint的推出開始火熱。我原來對這個東西持否定態度,但是后來轉變了。我原來否定態度的一個前提就是:XMLHTTP缺乏成熟的組件庫!但是 沒有想到的是,現在XMLHTTP從去年下半年開始,如雨后春筍般冒出來。AJAX應用最大的好處就是充分利用現有資源,我認為應成為RIA應用的首選。

2、Flash
Flash的優勢也很明顯,強大的AS支持,強大的組件可視化設計,強大的交互能力和很炫的用戶體驗,并且Flash Remoting也已經非常成熟了。Flash的缺點就是Flash雖然嵌入網頁,但是和網頁沒有數據交互能力,Flash另一個缺點就是不適合處理大量 文本內容(HTML最適合)。現在有些人開始濫用Flash了。

因此比較好的方式可能是兩種混用,一般不過度復雜的交互交給AJAX,非常復雜,甚至需要托拽操作的,交給Flash。

總結一下:

軟件開發領域服務器端技術Java是主流,兩個技術路線,一個是EJB3,一個是Spring+Hibernate,此外iBATIS也有一席之地;客戶端技術就是AJAX和Flash。

二、數據庫技術

基本上格局不會發生多大變化,Oracle還是高高在上,SQL Server進一步蠶食NT平臺其他數據庫的領地。開源方面,MySQL將一枝獨秀,但是開源數據庫在很多方面還是和商業數據庫有無法拉近的巨大差距。這 也使得商業數據庫的地位不可替代。我會比較關注Oracle,MySQL這兩個數據庫。面向對象數據庫仍然不會有什么起色。

三、桌面編程技術

我還是相信一點,對于桌面應用來說,本地代碼的位置永遠無法被取代,所以我總覺得XAML那樣的東西效率實在很成問題。Longhorn要像成 熟,也不是第一個版本就可以達到的。當前桌面應用開發技術,還是首推Delphi,不過我覺得Python是后起之秀,非常有可能在未來取代Delphi

初探在下一代 Windows 中編寫和部署應用程序
http://www.microsoft.com/china/MSDN/library/windev/longhorn/DevelopAppLonghorn.mspx

首先,以Microsoft公司的實力和Windows操作系統的占有率來說,Longhorn遲早會被普及,而XAML的開發方式也有可能普及的。記得 當初WindowsXP剛出來的時候,因為資源占用率和新的激活制度招致一片罵聲,但是慢慢的,現在也都接受了下來。由此可以推斷,Longhorn以其 更加豐富的桌面功能和誘人的外觀,會在將來成為主流。

但是Longhorn什么時候才會全面普及,這是很值得琢磨的問題。WindowsXP是2001年推出的,在隨后的幾年,Microsoft采 用了一些商業手段來迫使用戶升級,例如企圖取消Windows98的技術支持,不再提供WindowsNT技術支持,不再銷售 WindowsNT/Windows98,將Windows2000保持在一個比較高的售價的同時,對WindowsXP推出優惠價格,讓 WindowsXP的售價低于Windows2000等等手段。但是直到現在,Windows2000仍然占據了非常高的份額,據我個人的觀察是比 WindowsXP略高。按照這種情況來推斷,Longhorn要普及,恐怕難度更大,非常多的用戶現在仍然是Windows2000的死忠派, WindowsXP推廣了四年還未能超過Windows2000,那么Longhorn究竟要幾年才能超過WindowsXP呢?我估計四年以上是起碼 的。

XAML應用程序不同以往,它只能跑在Longhorn上面,甚至比Java和dotnet要求更嚴格,后者僅僅下載安裝一個運行環境就可以了, 但是前者要求你必須更新操作系統。XAML在IE瀏覽器中運行雖然肯定是下一代RIA的主流,但是不可忽視的問題是,只要Longhorn沒有徹底淘汰 Windows2000/XP,軟件開發商和網站開發商就不敢大面積采用XAML。而根據我的觀察,現在企業中,Windows98仍有少部分市場份額。 因此Longhorn必須要等待到徹底的,毫不殘留的淘汰Windows98,Windows2000,WindowsXP之后,才會全面普及,而在此之 前,不得不經歷一個漫長的過渡期。

就好像現在,假設你開發桌面應用程序,你敢只針對WindowsXP開發嗎?而徹底不支持98和2000嗎?我想,沒有哪個軟件開發商敢這樣做。 除非 Windows2000幾乎被徹底淘汰了,你才敢這樣做,但是WindowsXP已經推出四年了,還沒有Windows2000占用率高,哪全面淘汰究竟 要幾年呢?再看看現在dotnet winforms應用,推出也已經五年時間了,但是到現在仍然沒有普及開來,根本的原因就是Windows2000/WindowsXP沒有預裝 dotnet framework。僅僅是需要打包安裝一個運行環境就使得winforms五年都推廣不了,更何況要求你升級操作系統呢?

我個人的估計是,假設2006年Longhorn如期上市,那么將需要7-9年時間來徹底淘汰Windows2000/WindowsXP。 Longhorm上面XAML應用的初步普及也至少需要4-5年時間以后才會有軟件開發商大量去做(想向dotnet是2000年開始宣傳和推廣的,到 2004年開始普及,今年和明年才會全面普及)。因此,基于XAML應用的普及可能是在2010年以后!上面的估計中還沒有包括MacOS 和Linux在桌面會否有什么表現。

先說說服務器端吧:

從可預見的未來來看,服務器和客戶端TCP通訊的主流方式一定是HTTP協議(即時通訊軟件走UDP端口,不在討論范圍)。在基于HTTP協議之 上,又分為兩類:一類是SOAP協議,異構系統支持良好,但是性能很差,目前Microsoft很喜歡用這種方式;一類是輕量級二進制協議,例如 Flash的 AMF協議,Resin的Hessian協議。值得一提的是,不管哪種方式,他們都支持異構的系統,所以完全可用在客戶端采用dotnet,在服務器端采 用Java或者Python。因此,XAML的流行不會對服務器端技術產生致命的影響(肯定會提高dotnet的服務器的市場份額)。所以我們可用拋開客 戶端影響,單獨來看服務器端技術:

1、Java
Java是當前服務器端技術當之無愧的王者,在未來五年內,也不會有任何動搖(受到dotnet和python的影響,市場份額會下降一些)。 Java特別有利的一點是,現在有太多的現存系統基于Java,這些系統都不會輕易遷移到其他平臺上。另外還有一個決定因素是除了Microsoft之外 的幾乎全部 IT大公司都在Java方面的投資巨大,放棄Java對他們來說也意味著沉重的打擊,甚至毀滅性的打擊。這些公司可以列很長很長,IBM,HP, Oracle,SAP,Sun,BEA,Macromedia等等。

2、dotnet
由于Microsoft的影響力,dotnet會成為為僅次于Java的第二大服務器端技術,但是Microsoft有一個隱憂,就是Linux 操作系統在服務器端的高速成長。雖然現在Linux在整個服務器端市場的出貨量只有13%左右,但是成長率驚人,根據我看到的資料顯示,到2008年,將 占據 25%以上的市場份額。考慮到很多公司是自己安裝Linux,因此不會被硬件服務器廠商統計進來,因此Linux的服務器端的市場份額應該比25%高一 些。并且現在主要的服務器廠商都對Linux有非常巨大的投入和支持,這些公司包括IBM,HP,Dell(只有Sun不支持),因此Linux在未來會 對Windows在服務器端的市場構成最嚴重的威脅。

不要忘記dotnet只能在Windows平臺上面跑,雖然有mono,但是你不可能移植MTS,COM+,SQL Server etc。所以只要Linux在服務器市場對Windows構成持續的威脅,dotnet就不可能超過Java,Java的地位還是穩穩的老大。從某種程度 上來說,Java的命運是和Linux聯系在一起的,只要Linux在服務器端不輸于Windows,Java就穩穩壓制dotnet。

BTW:從未來來看,Linux和Windows會在低端和中端服務器市場成為主要競爭對手,由于各自都有其不可替代性,所以雙方都不可能徹底消滅對方,最大的可能性是Linux和Windows平分市場,或者Windows市場份額略高一點。

3、Python
我個人認為Python會成長為第三大服務器端技術,Python成長于開源,但是又有商業公司來商業運作,并且背后還有大公司的支持,在歐洲普 及的非常好。當然最重要的原因是我覺得Python在技術上非常先進,并且技術發展方向上比較統一,不會出現Java那種吵架的事情。

4、PHP
PHP這東西是不錯,Yahoo也在用,IBM現在也對他感興趣,但是我還是要說PHP沒有太廣闊的前途,原因很簡單,PHP沒有服務端中間件, 例如 Java有App Server,dotnet有IIS/MTS,Python有Zope,但是PHP他就是一個腳本,沒有自己的中間件就是致命問題。Yahoo用PHP有 其特定的原因,主要是從原先自己的技術遷移到PHP很方便,而IBM支持PHP,顯然醉翁之意不在酒,IBM意不在推廣PHP,而在于爭取到那些使用 PHP的商業大客戶們,向他們賣服務。

BTW:感覺歐洲用Python/PHP的很多,似乎開源在歐洲非常深入人心。

從服務器端技術來說,Java還是我們最需要下功夫去學習和掌握的,此外,我會比較傾向于鉆研和應用Python,而不是dotnet。原因也很 簡單,跟隨Micorsoft的技術會很辛苦,Microsoft產生的新概念多,他總是會猛的推出n多種技術,然后讓他們在市場上自己生存,最后根據市 場反饋,無情的拋棄某些東西,大力推進有市場前景的東西,這樣的例子太多了,舉不勝舉了。我的感覺就是這種方式會讓Microsft經過市場嘗試在技術競 爭中篩選最優秀的技術,但是對于Microsoft技術的跟隨者來說,未免有點太不公平,整天吭哧吭哧被Microsoft拿來當免費的試驗品來用。我特 別不理解的是MSDN宇宙版,Microsoft總是把無窮無盡的文檔灌給你,讓你永遠學不完,但實際上我真的不需要那么多概念,我只需要能夠很好的完成 我工作的技術,并且這個技術可以持續的完善就好了。而不是今天給我這樣一個東西,明天灌給我無窮的文檔,后天當我用順手以后,又告訴我這東西作廢了,你給 我重新學習新東西,然后又是無窮的文檔,總之很惱火。

所以就是:重點學習Java,有時間去學習Python,保持對dotnet的關注即可。


客戶端:

前面說了那么多XAML的東西,都是和這有關,七年以后肯定是XAML的天下,但是五到七年之內還不是:

1、Java
Java在客戶端真的是扶不起的阿斗,這都怪Sun。Sun造就了Java的成功,又一手毀了Java在客戶端的市場。那些個Swing和SWT 的死忠團也不要和我爭什么,我也懶得和你們爭,你們覺得好就好吧,道不同不相與謀,你覺得好你就用你的,我覺得不好我就用別的。用不著纏著我非逼我說 Java做客戶端好,沒必要,況且就算你逼我承認又怎樣?我就是玉皇大帝金口玉言了?得到我的承認,Java就有前途了?我好像還沒有那么大本領吧?就是 IBM, Sun也沒有那么大本領,所以好不好也不是我說了算,用不著逼我。

2、dotnet winforms
由于Windows2000/WindowsXP不帶dotnet CLR,所以winforms一直沒有能夠普及得很好,等Longhorn一出來,又變成了XAML了,winforms又被淘汰了,所以 winforms的地位特別尷尬,但是在這5-7年中,你想開發既能夠在Windows2000/WindowsXP,又能夠在Longhorn上面跑的 桌面程序,winforms好像又是Microsoft技術中最好的選擇。所以只好一直尷尬下去。

3、VC,VB
dotnet出來以后就開始尷尬了,說用吧,好像很落伍了,都dotnet時代了,說不用吧,又沒有好的替代品,現階段開發桌面程序,還真得不得不用,而且還挺好用的。所以VC6SP5,VB6的死忠團也比較多。

4、Delphi
dotnet出來以后Borland就開始跟風了,這一跟風,連老本都跟沒有了。未來的XAML時代,我也不知道Borland怎樣找自己的定 位,但不管怎么說,從歷史來看,本地代碼的應用程序永遠有它一席之地!就算XAML又如何如何做得漂亮了,關鍵的地方,和特定資源處理相關的部分,還是本 地代碼的程序管用。你看VB出來多少年了,用VB開發的都是一些上層的項目級別的應用軟件,一旦涉及產品領域,還是VC和Delphi管用。所以現在大家 還是不得不用Delphi7阿。

BTW:XAML應用致力于快速開發項目級別的應用,特別是可以跑在IE瀏覽器里面的,因此是RIA的首選。但是畢竟也有很多不適合用RIA的場 所,特別是例如我要備份某些文件,你用XAML?那性能就不用提了。所以Delphi如果好好發展VCL,封裝Windows32 API,我覺得也是一條路,未必比現在跟隨dotnet差。

5、Flash RIA
其實我覺得Flash不適合做RIA的,但是Flash普及率太高,XAML又離普及太遙遠,而Flash現在就可以用了,所以是當前RIA的首 選。不過我對Macromedia公司比較失望,如果Macromedia能夠公布Flash實現細節,作為一個公開的標準向ISO提交,同時免費開源 Flex,我敢說,Flash RIA會迅速普及的。等5-7年XAML的時代,由于Flash的市場占有率,XAML就未必能拼得過Flash。可惜的是Macromedia公司目光 過于短淺,只知道賺眼前的小錢。

6、Python
這5-7年內,RIA應用和RCP應用不會統一,XAML才具備將RIA和RCP統一的實力。從這5-7年來看,Flash是RIA的首選,而RCP的首選,我要推薦Python。原因前面已經提過,簡單總結一下:
1)wxWidgets是一個比MFC優雅的庫,TortoiseCVS用wxWidges而不用MFC,就是因為wxWidgets好用,而不是為了可以移植。
2)Python的面向對象腳本語言編程適合快速界面開發
3)Python在服務器端和客戶端都非常有前途,可以形成一個統一的解決方案,這一點明顯比Java有優勢
4)Python桌面應用程序可以完全編譯為本地代碼,脫離Python運行環境,這一點比dotnet winforms都有優勢
5)Python可以不受限制的任意調用Windows32 API,所以凡是VC6可以做的事情,Python就可以做

試想一下,現在我們開發桌面應用程序有什么要求?
一、不要附帶一個JRE或者CLR的累贅
二、可以快速開發
三、性能要有保證
四、方便的遠程方法調用支持
此外如果能夠跨平臺就最好了

Java前三點都不符合;dotnet winforms不符合一;VC6不符合二和四,VB6不符合三和四;Delphi7符合前四點;Flash RIA不符合三;Python全部都符合!并且請記住Python是一個完全開源免費的方案!

客戶端技術在這5-7年中,在RIA領域我會學習一下Flash,在RCP領域我會重點學習Python,此外會觀望一下XAML。



Alex 2006-08-13 19:24 發表評論
]]>
POI的一個bug問題http://www.oiklr.tw/alex/archive/2006/08/10/62823.htmlAlexAlexThu, 10 Aug 2006 09:09:00 GMThttp://www.oiklr.tw/alex/archive/2006/08/10/62823.htmlhttp://www.oiklr.tw/alex/comments/62823.htmlhttp://www.oiklr.tw/alex/archive/2006/08/10/62823.html#Feedback1http://www.oiklr.tw/alex/comments/commentRss/62823.htmlhttp://www.oiklr.tw/alex/services/trackbacks/62823.htmljava.io.IOException Unable to read entire block

版本:2.5.1final
錯誤提示:
java.io.IOException Unable to read entire block

出這個問題具有隨機性,有時候沒問題,有時候將Excel里的CellType改一下好像就沒問題,但也不總是這樣,真是莫名其妙.

Google了一下是一個bug,重新下載src文件,將RawDataBlock.java文件的RawDataBlock(final InputStream stream)constructor覆蓋:

public?RawDataBlock(final?InputStream?stream)?throws?IOException
????{
????????_data?
=?new?byte[?POIFSConstants.BIG_BLOCK_SIZE?];
????????
int?count?=?0;
????????
int?totalBytesRead?=?0;
????????
while?((totalBytesRead?<?POIFSConstants.BIG_BLOCK_SIZE)?&&
(count?
!=?-1))?{
????????????????count?
=?stream.read(_data,?totalBytesRead,
POIFSConstants.BIG_BLOCK_SIZE?
-?totalBytesRead);
????????????????
if?(count?!=?-1)?{
????????????????????????totalBytesRead?
+=?count;
????????????????}
????????}
??????????
if?(count?==?-1)?{
????????????????_eof?
=?true;
??????????}?
else?{
????????????_eof?
=?false;
????????}?
??????????
if?((totalBytesRead?!=?POIFSConstants.BIG_BLOCK_SIZE)?&&?(totalBytesRead?!=?0))?{
????????????String?type?
=?"?byte"?+?((totalBytesRead?==?1)???(""):?("s"));
????????????
throw?new?IOException("Unable?to?read?entire?block;?"?+
totalBytesRead?
+?type?+?"?read;?expected?"?+?POIFSConstants.BIG_BLOCK_SIZE?+?"bytes");
????????}
????}


打包:
ant?jar

重啟app,OK!

說明:
主要問題出在 InputStream的read上,原來的實現用ReadFully方法:
public?static?int?readFully(InputStream?in,?byte[]?b,?int?off,?int?len)
????
throws?IOException
????{
????????
int?total?=?0;
????????
for?(;;)?{
????????????
int?got?=?in.read(b,?off?+?total,?len?-?total);
????????????
if?(got?<?0)?{
????????????????
return?(total?==?0)???-1?:?total;
????????????}?
else?{
????????????????total?
+=?got;
????????????????
if?(total?==?len)
????????????????????
return?total;
????????????}
????????}
????}

InputStream的read不能確保返回的是最大字節數,但是另一個實現卻可以:
ByteInputStream
所以,下面的方法也可以修改這個問題:
?//?read?entire?stream?into?byte?array:
????ByteArrayOutputStream?byteOS?=?new?ByteArrayOutputStream();
????
byte[]?buffer?=?new?byte[1024];
????
int?count;
????
while?(count?=?inputStream.read(buffer))?!=?-1)
????????byteOS.append(buffer,?
0,?count);
????byteOS.close();
????
byte[]?allBytes?=?byteOS.betByteArray();

//?create?workbook?from?array:
InputStream?byteIS?=?new?ByteArrayInputStream(allBytes);
HSSFWorkbook?wb?
=?new?HSSFWorkbook(byteIS);



Alex 2006-08-10 17:09 發表評論
]]>
2013火热网络捕鱼游戏 12057七星彩走势图 学生炒股 中国排球女将 0投入网上赚钱日赚200 开心棋牌是赌博 足球彩票任选9场胜负 老k棋牌游戏下载安装 江苏快三下载 七乐彩走势图模式 新疆时时彩玩法大全 众益彩票苹果 海南彩票七星彩开奖结果今天 3d17301期推荐号码 人人彩票网 蓝洞棋牌官方网 大小单双中特