soufan

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            22 隨筆 :: 0 文章 :: 0 評(píng)論 :: 0 Trackbacks

          2006年8月21日 #

               摘要: 轉(zhuǎn)載摘要:本文介紹了 Web Services 的起源和基本原理,分析了在企業(yè)應(yīng)用中 Web Services 帶來(lái)的沖擊和變革,指出了 Web Services ...  閱讀全文
          posted @ 2007-03-04 14:12 soufan 閱讀(222) | 評(píng)論 (0)編輯 收藏

          (原)Java 專業(yè)人士必備的書(shū)籍和網(wǎng)站列表

          您必備的參考資料

          文檔選項(xiàng)
          ?

          ?

          未顯示需要 JavaScript 的文檔選項(xiàng)


          拓展 Tomcat 應(yīng)用

          下載 IBM 開(kāi)源 J2EE 應(yīng)用服務(wù)器 WAS CE 新版本 V1.1


          級(jí)別: 初級(jí)

          Roy Miller (roy@roywmiller.com), 創(chuàng)始人兼總裁, The Other Road, LLC

          2007 年 1 月 15 日

          對(duì)于 Java? 語(yǔ)言開(kāi)發(fā)人員來(lái)說(shuō),信息過(guò)量是一個(gè)真正的問(wèn)題。每個(gè)新入行的程序員都要面臨一個(gè)令人畏縮的挑戰(zhàn):要進(jìn)入的行業(yè)是一個(gè)具有海量知識(shí)的行業(yè)。要了解的東西簡(jiǎn)直太多了。對(duì)于有經(jīng)驗(yàn)的老手來(lái)說(shuō),情況只有些微好轉(zhuǎn)。知識(shí)量總在增大,僅僅跟上進(jìn)度就是一個(gè)挑戰(zhàn)。如果有一份專業(yè)人士必備的書(shū)籍和網(wǎng)站列表該有多好!本文就是這個(gè)列表。它包含了每個(gè)專業(yè)的 Java 語(yǔ)言程序員在書(shū)架或?yàn)g覽器書(shū)簽中必備的最重要的書(shū)籍和網(wǎng)站。

          這些都是您書(shū)架上必備的書(shū)和應(yīng)該經(jīng)常使用的 Web 鏈接。時(shí)間是一項(xiàng)重要的資源,本文幫您回避那些分心的事情,把時(shí)間專注于最有益于您作為Java 語(yǔ)言程序員職業(yè)生涯的信息源。盡管有多少程序員就有多少他們最喜歡的參考資料,但本文收集的這些都是優(yōu)中選優(yōu),來(lái)源于我書(shū)架上的私家珍藏和許多 Java 專家的推薦。

          我考慮了兩種組織這份參考資料列表的方法。我本可以通過(guò)主題領(lǐng)域來(lái)組織,這也許很有幫助,但主題列表很快就會(huì)變得不實(shí)用。相反,我選擇了另一種方法:通過(guò)類型來(lái)組織,即書(shū)籍和 Web 站點(diǎn)。

          總的來(lái)講,有經(jīng)驗(yàn)的老手們用 Web 站點(diǎn)來(lái)跟蹤行業(yè)的走勢(shì)。書(shū)籍、文章和論文有助于跟上潮流,但它們總體上更適合于基礎(chǔ)學(xué)習(xí)。極富創(chuàng)造性的書(shū)籍偶爾會(huì)撼動(dòng)一兩個(gè)基礎(chǔ)性的東西。這樣的書(shū)也在本列表之列。

          需要提出的一點(diǎn)警告是,專注于 Java 語(yǔ)言的書(shū)籍和 Web 站點(diǎn)數(shù)量巨大。您鐘愛(ài)的未必在這份列表里。那并不意味著它們不好。它們只是不在這份列表里而已。可能是因?yàn)槲疫€不知道它們。也可能是因?yàn)槲也徽J(rèn)為它們能夠算得上是重要資源。不包含一些參考資料是一個(gè)評(píng)判問(wèn)題,但如果不這樣的話,您也許就要花幾小時(shí)來(lái)拖動(dòng)滾動(dòng)條,還要花上成千上萬(wàn)美元來(lái)買書(shū)。如果您作為一個(gè)專業(yè)的 Java 程序員,有一些常用的優(yōu)秀參考資料,一定要讓我知道這些資料。這份列表一直都在更新中,您提出的那些也許就會(huì)被收錄進(jìn)去。

          書(shū)籍

          每個(gè)程序員都會(huì)有一些由于經(jīng)常被當(dāng)作專業(yè)資料參閱而磨壞的書(shū)。下列書(shū)籍應(yīng)該是 Java 語(yǔ)言程序員的書(shū)架上必備的。書(shū)很貴,所以我有意將這份列表弄得很短,僅限于重要書(shū)籍。

          Thinking in Java (Bruce Eckel)

          Thinking in Java, 3rd edition (Bruce Eckel; Prentice Hall PTR,2002 年)
          Java 編程思想:第3版 (陳昊鵬 等譯; 機(jī)械工業(yè)出版社,2005 年)
          Eckel 的書(shū)對(duì)于學(xué)習(xí)如何在 Java 語(yǔ)言環(huán)境中使用好面向?qū)ο蠹夹g(shù)極其實(shí)用。書(shū)中大量的代碼樣例解釋了他所介紹的概念。文字出自一個(gè)并不認(rèn)為 Java 技術(shù)總是正確答案的人,所以相當(dāng)?shù)貙?shí)用。Eckel 具有多種語(yǔ)言的大量經(jīng)驗(yàn),還有用面向?qū)ο蠓绞竭M(jìn)行思考的扎實(shí)技能。本書(shū)將這些技能放到實(shí)用的 Java 語(yǔ)言環(huán)境中。他還在寫(xiě)一本新書(shū),名為 Thinking in Enterprise Java

          Effective Java (Joshua Bloch)

          Effective Java: Programming Language Guide (Joshua Bloch; Addison-Wesley,2001 年)
          Effective Java 中文版 (潘愛(ài)民 譯; 機(jī)械工業(yè)出版社,2003 年)
          本書(shū)是理解優(yōu)秀 Java 程序設(shè)計(jì)原則的最佳書(shū)籍。大多數(shù)材料從其他的 “學(xué)習(xí) Java ” 的書(shū)中根本找不到。例如,Bloch 書(shū)中關(guān)于覆蓋 equals() 這一章是我讀過(guò)的最好的參考資料之一。他也在書(shū)中包括了很實(shí)用的建議:用接口替代抽象類和靈活使用異常。Bloch 是 Sun 公司 Java 平臺(tái)庫(kù)的架構(gòu)師,所以他透徹地了解這門(mén)語(yǔ)言。事實(shí)上,他編寫(xiě)了該語(yǔ)言中大量有用的庫(kù)。本書(shū)必讀!

          The Java Programming Language (Ken Arnold, James Gosling, David Holmes)

          The Java Programming Language (Ken Arnold,James Gosling,David Holmes; Addison-Wesley,2000 年)
          Java 編程語(yǔ)言(第 3 版) (虞萬(wàn)榮 等譯,中國(guó)電力出版社,2003 年)
          這也許是能弄到的最好的 Java 入門(mén)讀物。它并不是一個(gè)標(biāo)準(zhǔn)規(guī)范,而是一本介紹每門(mén)語(yǔ)言特性的可讀書(shū)籍。這本書(shū)在嚴(yán)謹(jǐn)性和教育性方面權(quán)衡得很好,能夠讓懂編程的人迅速被 Java 語(yǔ)言(和其豐富的類庫(kù))所吸引。

          Concurrent Programming in Java: Design Principles and Patterns (Doug Lea)

          Concurrent Programming in Java: Design Principles and Patterns, 2nd edition (Doug Lea; Addison-Wesley,1999 年)
          Java 并發(fā)編程—設(shè)計(jì)原則與模式(第二版) (趙涌 等譯,中國(guó)電力出版社,2004 年)
          不是每個(gè)開(kāi)發(fā)人員都需要如此細(xì)致地了解并發(fā)性,也不是每個(gè)工程師都能達(dá)到本書(shū)的水準(zhǔn),但卻沒(méi)有比本書(shū)更好的關(guān)于并發(fā)性編程的概述了。如果您對(duì)此感興趣,請(qǐng)從這里開(kāi)始。Lea 是 SUNY 的一名專業(yè)程序員,他的和并發(fā)性有關(guān)的作品和想法都包含在了 JDK 5.0 規(guī)范(引自 JSR166)中,所以您大可放心,他所說(shuō)的關(guān)于有效使用 Java 語(yǔ)言的建議是值得一聽(tīng)的。他是一個(gè)很善于溝通的人。

          Expert One-On-One J2EE Design and Development (Rod Johnson)

          Expert One-On-One J2EE Design and Development (Rod Johnson)
          WROX: J2EE 設(shè)計(jì)開(kāi)發(fā)編程指南 (魏海萍 譯,電子工業(yè)出版社,2003 年)
          對(duì)于剛接觸 J2EE 的人來(lái)說(shuō),這是唯一的一本如實(shí)反映這項(xiàng)技術(shù)的書(shū)。本書(shū)收錄了多年的成功經(jīng)驗(yàn)和失敗經(jīng)驗(yàn),不同于其他許多作者,Johnson 樂(lè)于將失敗的經(jīng)驗(yàn)公諸于眾。J2EE 常常都被過(guò)度使用。Johnson 的書(shū)能幫您避免這一點(diǎn)。

          Refactoring (Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts)

          Refactoring: Improving the Design of Existing Code (Martin Fowler,Kent Beck,John Brant,William Opdyke,Don Roberts; Addison-Wesley,1999 年)
          重構(gòu):改善既有代碼的設(shè)計(jì)(中文版) (侯捷 等譯,中國(guó)電力出版社 ,2003 年)
          Fowler 寫(xiě)了幾本現(xiàn)已出版的最流行的編程書(shū),包括 Analysis Patterns。他的關(guān)于重構(gòu) 的書(shū)是這一主題的基本書(shū)籍。重構(gòu)代碼是被程序員忽略的訓(xùn)練,但卻是程序員最直觀的想法。重構(gòu)是在不改變代碼結(jié)果的前提下改進(jìn)現(xiàn)有代碼的設(shè)計(jì)。這是保持代碼整潔的最佳方式,用這種方法設(shè)計(jì)的代碼總是很容易修改。什么時(shí)候進(jìn)行重構(gòu)呢?當(dāng)代碼“散發(fā)出味道”時(shí)。Fowler 的書(shū)里滿是 Java 語(yǔ)言代碼的例子。許多 Java 語(yǔ)言集成開(kāi)發(fā)環(huán)境(IDE)(包括了 IBM 的 Eclipse)都將 Fowler 的重構(gòu)包含了進(jìn)去,每一個(gè)都使用他的重構(gòu)名命名,所以熟悉如extract method 等重構(gòu)方法還是很值得的。

          Design Patterns (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides)

          Design Patterns: Elements of Reusable Object Oriented Software (Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides; Addison-Wesley,1997 年)
          設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ) (李英軍 等譯,機(jī)械工業(yè)出版社 ,2005 年)
          這是一本在專業(yè)程序員圈子里更為有名的書(shū),基于作者共同的綽號(hào),這本書(shū)被認(rèn)為是 “四人幫(GOF)之書(shū)”。模式是思考和解決普通編程問(wèn)題時(shí)可以重用的方式。學(xué)習(xí)模式是一門(mén)學(xué)科。使用好模式(或知道什么時(shí)候 使用模式)是一項(xiàng)技能。忽略模式則是錯(cuò)誤的。書(shū)中所有的例子都以 C++ 表示,但 Java 語(yǔ)言是從那里誕生的,讓 Java 語(yǔ)言程序員由此聯(lián)系到如何在 Java 語(yǔ)言中實(shí)現(xiàn)這些模式相對(duì)簡(jiǎn)單一些。熟悉模式并了解如何使用好模式使編程更加簡(jiǎn)單。這使得和其他程序員交流也更簡(jiǎn)單,因?yàn)樵卺槍?duì)通用問(wèn)題的通用解決方案中,模式是描述解決方案中彼此協(xié)作的大量相關(guān)編程概念的快捷方式。一些更為通用的方式,如工廠方法 則是普便存在的,甚至存在于 Java 語(yǔ)言本身。關(guān)于明智使用模式的這個(gè)主題,也可以閱讀 Joshua Kerievsky 的 Refactoring to Patterns,該書(shū)稱可以讓代碼來(lái)告訴您何時(shí)實(shí)現(xiàn)模式。

          Patterns of Enterprise Application Architecture (Martin Fowler)

          Patterns of Enterprise Application Architecture (Martin Fowler; Addison-Wesley,2002 年)
          企業(yè)應(yīng)用架構(gòu)模式 (王懷民 等譯,機(jī)械工業(yè)出版社 ,2004 年)
          比起小型、一次性項(xiàng)目來(lái)說(shuō),企業(yè)開(kāi)發(fā)當(dāng)然代表了更大的挑戰(zhàn)。那并不意味著企業(yè)開(kāi)發(fā)帶來(lái)的所有挑戰(zhàn)都是新挑戰(zhàn)。事實(shí)上有些時(shí)候,這項(xiàng)開(kāi)發(fā)已經(jīng) 是以前完成過(guò)的了。Fowler 做了很多個(gè)這樣的項(xiàng)目。他的書(shū)提到了一些通用解決方案,并提供了關(guān)于使用、折中和可選方案的指導(dǎo)。Fowler 在書(shū)中包含了一些熟悉的模式,如模型視圖控制器(MVC),他也提供了一些您也許不了解的模式,如處理 Web 站點(diǎn)上特定頁(yè)面請(qǐng)求或行為請(qǐng)求的 Page Controller 模式。正如您對(duì)待大多數(shù)模式一樣,一旦您讀過(guò)許多模式,您就會(huì)認(rèn)為 “我已經(jīng)知道那個(gè)模式了” 。也許是這樣,但有一個(gè)用來(lái)引用模式的通用表達(dá)方式還是很有幫助的。在有多個(gè)組件(由不同人開(kāi)發(fā))的大型項(xiàng)目中,該類引用是一項(xiàng)很好的幫助。

          UML Distilled (Martin Fowler)

          UML Distilled: A Brief Guide to the Standard Object Modeling Language (Martin Fowler; Addison-Wesley 2003 年)
          UML精粹:標(biāo)準(zhǔn)對(duì)象語(yǔ)言簡(jiǎn)明指南(第3版) (徐家福 譯,清華大學(xué)出版社 ,2005 年)
          對(duì)于專業(yè)的程序員來(lái)說(shuō),UML 是一門(mén)很重要的通用可視化溝通語(yǔ)言,但是它被過(guò)度使用和草率地濫用了。您無(wú)需對(duì)使用 UML 溝通了解太多。Martin 對(duì) UML 的提煉為您提供了最核心的東西。事實(shí)上,前后的封頁(yè)提供了常規(guī)基礎(chǔ)上可能使用到的所有東西。該書(shū)中 UML 例子的代碼都是 Java 代碼。

          Test-Driven Development: By Example (Kent Beck)

          Test-Driven Development: By Example (Kent Beck; Addison-Wesley 2002 年)
          測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(中文版) (崔凱 譯,中國(guó)電力出版社 ,2004 年)
          測(cè)試優(yōu)先編程將使編程發(fā)生革命性變化,能助您成為更好的程序員。在寫(xiě)代碼之前編寫(xiě)測(cè)試開(kāi)始很難,但卻是一項(xiàng)威力強(qiáng)大的技能。通過(guò)優(yōu)先編寫(xiě)測(cè)試,可使代碼更加簡(jiǎn)單,并確保從一開(kāi)始它就能工作(Beck 實(shí)踐著他提倡的測(cè)試優(yōu)先,與人合寫(xiě)了 JUnit,這是 Java 語(yǔ)言最流行的測(cè)試框架)。Beck 的書(shū)是權(quán)威的參考資料,擴(kuò)展了的 Money 例子也用 Java 語(yǔ)言寫(xiě)成。Beck 詳述了如何用測(cè)試優(yōu)先進(jìn)行 思考(這也許是許多程序員首先遇到的障礙)。

          The Pragmatic Programmer: From Journeyman to Master (Andy Hunt and Dave Thomas)

          The Pragmatic Programmer: From Journeyman to Master (Andrew Hunt 和 David Thomas; Addison-Wesley 1999 年)
          程序員修煉之道——從小工到專家 (馬維達(dá) 譯,電子工業(yè)出版社 ,2004 年)
          做一個(gè)純粹的面向?qū)ο箝_(kāi)發(fā)人員有其優(yōu)勢(shì)所在。在當(dāng)今復(fù)雜的社會(huì)中,作為 Java 語(yǔ)言開(kāi)發(fā)人員,為完成任務(wù)常要妥協(xié)。Hunt 和 Thomas 探討了如何不將真正重要的東西妥協(xié)掉而完成任務(wù)。這不是一本關(guān)于 Java 語(yǔ)言的書(shū),而是 Java 語(yǔ)言開(kāi)發(fā)人員重要的思想讀物。例如,我認(rèn)為沒(méi)從“要解決問(wèn)題,而不是推卸責(zé)任”這句忠言中受益的程序員,不能像個(gè)自豪的藝術(shù)家一樣在他的杰作上簽上大名。

          Peopleware: Productive Projects and Teams (Tom DeMarco and Timothy Lister)

          Peopleware: Productive Projects and Teams (Tom DeMarco,Timothy Lister; Dorset House,1999 年)
          人件(第2版) (UMLChina 翻譯組 譯,清華大學(xué)出版社 ,2003 年)
          這份列表中的其他所有書(shū)籍都至少和技術(shù)有些相關(guān)。這本書(shū)卻不是。在所有技術(shù)行話和首字母縮略詞的海洋中,有時(shí)軟件開(kāi)發(fā)人員和經(jīng)理們會(huì)忘記:是 制造了軟件。DeMarco 和 Lister 向我們提醒了這一事實(shí),也向我們提醒了形成這一區(qū)別的原因。這不是一本關(guān)于一門(mén)特定編程語(yǔ)言的書(shū)籍,但卻是每個(gè) Java 語(yǔ)言程序員都應(yīng)該讀的書(shū)。關(guān)于 “累死程序員如何讓經(jīng)理們適得其反” 還有許多其他的好書(shū),但這是最好的一本。





          回頁(yè)首


          Web 站點(diǎn)

          Web 站點(diǎn)的數(shù)目浩如煙海,如果您想要消化其中的內(nèi)容,窮畢生之力也難以全部訪問(wèn)。包含 Java 語(yǔ)言某方面內(nèi)容的詳盡的網(wǎng)站列表會(huì)大得離譜。下列站點(diǎn)都是可靠、真實(shí)的。

          Sun 的 Java 技術(shù)站點(diǎn)

          Sun 的 Java 語(yǔ)言站點(diǎn)
          這是 Sun 的 Java 語(yǔ)言主站。作為 Java 語(yǔ)言開(kāi)發(fā)人員,您會(huì)發(fā)現(xiàn)自己頻繁地訪問(wèn)此站點(diǎn)。下列鏈接特別重要,特別是對(duì)新入行的 Java 語(yǔ)言開(kāi)發(fā)人員:

          • New to Java Center
            New to Java Center
            New to Java Center 存放了許多循序漸進(jìn)的 Java 技術(shù)資源鏈接。如果您剛接觸這門(mén)語(yǔ)言,這是一個(gè)好的起點(diǎn)。
          • 教程和代碼庫(kù)
            Java Tutorial
            這里有大名鼎鼎的 Java Tutorial,以及關(guān)于 Java 語(yǔ)言各個(gè)方面(例如 Collection)的其他教程。

          IBM developerWorks

          IBM 的 developerWorks
          推銷自己也許有些厚臉皮,但 developerWorks 是一項(xiàng)巨大的資源,收錄了大量 Java 語(yǔ)言工具和技術(shù)的教程和文章。其內(nèi)容從初學(xué)者指南到學(xué)習(xí)這門(mén)語(yǔ)言到高級(jí)并發(fā)性技術(shù)。可以根據(jù)主題搜索內(nèi)容,然后根據(jù)類型瀏覽。

          Apache Software Foundation

          Apache Software Foundation
          Apache 站點(diǎn)是許多可重用庫(kù)(通用領(lǐng)域)和工具的主頁(yè),這些庫(kù)和工具幫助 Java 開(kāi)發(fā)人員進(jìn)行開(kāi)發(fā)。這里的內(nèi)容全都是開(kāi)放源碼,所以盡管下載想要的吧!許多極其流行的 Java 語(yǔ)言庫(kù)和工具(如 Struts、Ant 和 Tomcat)都始于 Apache 項(xiàng)目。Jakarta 專區(qū)匯聚了大多數(shù)新興的 Java 語(yǔ)言材料。

          Eclipse.org

          Eclipse
          有幾個(gè)好的 Java 語(yǔ)言集成開(kāi)發(fā)環(huán)境(IDE)。Eclipse(來(lái)自 IBM)是最新的 IDE 之一,它很快成為 Java 語(yǔ)言開(kāi)發(fā)的首要 IDE。它完全是開(kāi)源的,這意味著它是免費(fèi)的。該站包含了學(xué)習(xí)如何有效使用 Eclipse 的各種參考資料。這里還有關(guān)于 Standard Widget Toolkit(SWT)的信息,SWT 是相對(duì)于 Swing 來(lái)說(shuō)更加輕量級(jí)的選擇。

          Eclipse 插件中心和 Eclipse 插件

          Eclipse 插件中心 Eclipse 插件
          Eclipse 基于插件架構(gòu)。事實(shí)上,插件是 Eclipse 的 Java 語(yǔ)言開(kāi)發(fā)組件。但有差不多上千個(gè)插件,從 Web 開(kāi)發(fā)的插件到在 Eclipse 環(huán)境中玩游戲的插件。這兩個(gè)站點(diǎn)分類列出了大多數(shù)插件,可以進(jìn)行搜索。它們是很棒的資源。如果您想在 Eclipse 開(kāi)發(fā)環(huán)境中弄點(diǎn)新東西,幸運(yùn)的話有某個(gè)插件可能已經(jīng)實(shí)現(xiàn),從這兩個(gè)站點(diǎn)能找到想要的插件。這兩個(gè)站點(diǎn)都允許評(píng)論插件,這樣您就可以知道哪些插件好,哪些值得一試。

          JUnit.org

          JUnit.org
          Junit 是 Java 語(yǔ)言中一個(gè)基本的單元測(cè)試框架。該站點(diǎn)包含了 Junit 最新最棒的版本,外加大量有關(guān)測(cè)試(Java 語(yǔ)言或者其他語(yǔ)言的)各個(gè)層面上(針對(duì)桌面應(yīng)用程序、Web 應(yīng)用程序、J2EE 應(yīng)用程序等)的其他資源。如果您想找測(cè)試資源,這里就是最佳起點(diǎn)。

          TheServerSide.com

          TheServerSide.com
          如果您要(或?qū)⒁?從事服務(wù)器端 Java 語(yǔ)言的開(kāi)發(fā),此站點(diǎn)是一處舉足輕重的資源。您可以到這里找到有關(guān) JBoss、J2EE、LDAP、Struts 和大量其他主題的文章,并且都是完全可檢索的。這些文章不僅僅是簡(jiǎn)單描述 Java 語(yǔ)言的特征或者支持的庫(kù)。它們更進(jìn)一步地描述了庫(kù)的新奇用法(如使用 Jakarta Velocity 作為規(guī)則引擎,而不是模板引擎)。它們也提供了有關(guān) Java 語(yǔ)言現(xiàn)狀的連續(xù)評(píng)論(當(dāng)前的一篇文章是由 Tim Bray 所寫(xiě)的 Java is boring )。該站點(diǎn)更好的通用功能之一是對(duì) Java 語(yǔ)言工具和產(chǎn)品(應(yīng)用服務(wù)器等)的矩陣式比較。

          Bruce Eckel's MindView, Inc.

          Bruce Eckel's MindView, Inc.
          Eckel 寫(xiě)了幾本 “用 …… 進(jìn)行思考” 的書(shū),內(nèi)容關(guān)于 Java 語(yǔ)言、Python 和 C++ ,當(dāng)我學(xué)習(xí) Java 語(yǔ)言時(shí),他的 Thinking in Java 對(duì)我尤其有幫助。它很實(shí)用并切中要害,在“在 Java 語(yǔ)言環(huán)境中如何面向?qū)ο笏伎肌狈矫婢哂凶孔R(shí)。您可以從此站點(diǎn)免費(fèi)下載他所有書(shū)籍的電子版。他也寫(xiě)了許多好文章,并且他把這些文章的鏈接都放到了這里(包括關(guān)于 Jython、Java 和 .NET 比較等內(nèi)容的文章)。

          ONJava.com

          ONJava.com
          O'Reilley 歷年來(lái)出版了一些有關(guān)編程語(yǔ)言和工具的優(yōu)秀書(shū)籍。他們的專注于 Java 語(yǔ)言的網(wǎng)站也不錯(cuò)。它有些有關(guān)各種 Java 語(yǔ)言工具(如 JDOM 和 Hibernate)、Java 平臺(tái)(如 J2SE 和 J2EE)不同領(lǐng)域不同部分的文章。全部都可以被檢索到。他們有優(yōu)秀的文章和教程。該站點(diǎn)按主題排列。例如有 Java 和 XML、Java Security、Wireless Java 和 Java SysAdmin。該站點(diǎn)也有到 O'Reilley Learning Lab 的鏈接,在那里您能獲得在線參考資料(Java 語(yǔ)言相關(guān)和其他的)。那些不是免費(fèi)的,但是許多都面向大學(xué)認(rèn)證。因此您可以以一種很方便的方式來(lái)學(xué)習(xí)技能,并得到一些認(rèn)證。

          java.net

          java.net 社區(qū)
          java.net 社區(qū)有多個(gè)“社區(qū)”,有特定于主題的論壇和文章。例如 Java Desktop 社區(qū)有各類與 Java 語(yǔ)言桌面開(kāi)發(fā)相關(guān)的資料。Java Patterns 社區(qū)作為一個(gè)門(mén)戶,也許對(duì)提供 Java 語(yǔ)言的模式資源相當(dāng)感興趣。還有一個(gè) Java User Groups (JUG) 社區(qū),在那里能找到有關(guān)創(chuàng)建、加入和管理一個(gè) JUG 的信息。





          回頁(yè)首


          結(jié)束語(yǔ)

          任何 “好的”、“關(guān)鍵性的” 或者 “重要的” 參考資料列表都注定是不完整的,本文的列表也未能例外。 Java 語(yǔ)言的書(shū)籍?dāng)?shù)目眾多,當(dāng)然,萬(wàn)維網(wǎng)也很龐大。除本文所列的參考資料之外,還有很多用于學(xué)習(xí) Java 語(yǔ)言的參考資料。但如果您擁有了這里所提到的所有書(shū)籍、網(wǎng)站、文章或者教程,您應(yīng)當(dāng)已經(jīng)擁有了一個(gè)使您良好開(kāi)端并助您登堂入室的實(shí)用寶庫(kù)。

          最后,要成為一個(gè)能力日增和高效的 Java 語(yǔ)言開(kāi)發(fā)人員,方法就是用它工作,動(dòng)手來(lái)嘗試。如果有一個(gè)教程詳細(xì)介紹了所需創(chuàng)建的軟件的每一部分,您很可能并沒(méi)得到多少好處。有時(shí),您可能得走自己的路。在成功地嘗試了一些新的東西之后,您可能想要寫(xiě)一篇文章、教程或者一本書(shū)來(lái)分享您所學(xué)到的。



          參考資料



          關(guān)于作者

          Roy Miller 是一名獨(dú)立軟件開(kāi)發(fā)培訓(xùn)師、程序員兼作家,他在充滿挑戰(zhàn)、快節(jié)奏的咨詢公司里從事了十多年軟件開(kāi)發(fā)和項(xiàng)目管理工作。他最初在 Andersen Consulting(現(xiàn)在是 Accenture)公司工作,在那里,他管理團(tuán)隊(duì)實(shí)現(xiàn)了許多系統(tǒng),從主機(jī)記帳系統(tǒng)到星形模式數(shù)據(jù)集市。最近三年來(lái),他在北卡羅來(lái)納州 Holly Springs 的 RoleModel Software, Inc. 公司工作,在那里他專業(yè)地運(yùn)用著 Java 技術(shù),并擔(dān)任開(kāi)發(fā)人員兼 Extreme Programming (XP) 培訓(xùn)師。他與人合著了 Addison-Wesley XP 系列的 Extreme Programming Applied: Playing to Win 一書(shū),最近他寫(xiě)了 Managing Software for Growth: Without Fear, Control and the Manufacturing Mindset 一書(shū),來(lái)幫助經(jīng)理和管理層理解:像 XP 這樣的敏捷構(gòu)建方法為什么比傳統(tǒng)的方法更有效。2003 年,他創(chuàng)辦了自己的公司:The Other Road,該公司幫助其他公司了解如何向 XP 和被他稱為 Extreme Business (XB) 的方法轉(zhuǎn)換。

          posted @ 2007-01-18 13:39 soufan 閱讀(240) | 評(píng)論 (0)編輯 收藏

          1. 簡(jiǎn)介


          JasperReport是一個(gè)強(qiáng)大的開(kāi)源報(bào)表工具,它可以傳送豐富的報(bào)表內(nèi)容到顯示器、打印機(jī)或者PDF、HTML、XLS、CSV、XML文件。它完全使用Java編寫(xiě),可以在各種Java應(yīng)用中用來(lái)創(chuàng)建動(dòng)態(tài)報(bào)表內(nèi)容。它的主要目標(biāo)是用簡(jiǎn)單靈活的方法幫助創(chuàng)建便于打印的分頁(yè)文檔。

          JasperReport根據(jù)一個(gè)xml報(bào)表設(shè)計(jì)文件來(lái)組織從JDBC獲得的關(guān)系數(shù)據(jù)庫(kù)數(shù)據(jù)。要用數(shù)據(jù)填充報(bào)表,首先必須編譯報(bào)表。編譯xml的報(bào)表設(shè)計(jì)文件是用JasperManager類的compileReport()方法完成的。

          通過(guò)編譯,報(bào)表設(shè)計(jì)被加載到一個(gè)報(bào)表設(shè)計(jì)對(duì)象(net.sf.jasperreports.engine.JasperReport類的實(shí)例)中并被序列化然后保存。在應(yīng)用程序用數(shù)據(jù)填充報(bào)表時(shí)使用該序列化文件。實(shí)際上,報(bào)表編譯完成了報(bào)表設(shè)計(jì)中所有的java表達(dá)式的編譯。很多檢查工作在編譯期間進(jìn)行以確保報(bào)表設(shè)計(jì)的完整性,編譯后的文件是待填充的報(bào)表,以方便應(yīng)用程序用各種數(shù)據(jù)集來(lái)產(chǎn)生不同的報(bào)表文檔。

          要填充報(bào)表,可以使用JasperManager類的fillReportXXX()方法。這些方法接受一個(gè)參數(shù)代表報(bào)表設(shè)計(jì)——可以是一個(gè)JasperDesign對(duì)象,也可以是一個(gè)存放該類對(duì)象的文件名——還有一個(gè)獲得填充報(bào)表數(shù)據(jù)的JDBC連接。報(bào)表填充的結(jié)果是一個(gè)表示待打印文檔的對(duì)象(net.sf.jasperreports.engine.JasperPrint類的實(shí)例),可以被序列化保存以后繼續(xù)使用,或者傳送給打印機(jī)、顯示器,或者導(dǎo)出成PDF、HTML、XLS、CSV或者XML文件。

          2. 報(bào)表設(shè)計(jì)

          一個(gè)報(bào)表設(shè)計(jì)表示一個(gè)模版用來(lái)被JasperReport引擎填充數(shù)據(jù)并傳送到屏幕、打印機(jī)或者Web。數(shù)據(jù)庫(kù)的數(shù)據(jù)根據(jù)報(bào)表設(shè)計(jì)被組織來(lái)填充報(bào)表以得到待打印的分頁(yè)文檔。報(bào)表設(shè)計(jì)都保存到一個(gè)特定結(jié)構(gòu)的一個(gè)XML文件中,文件結(jié)構(gòu)定義在一個(gè)JasperReport引擎可以識(shí)別的DTD文件中。然后這些xml文件會(huì)被編譯以準(zhǔn)備報(bào)表填充操作。

          創(chuàng)建一個(gè)報(bào)表設(shè)計(jì)(模版),必須按照如下結(jié)構(gòu)編輯一個(gè)xml文件:

          <?xml version="1.0"?>
          <!DOCTYPE jasperReport
          PUBLIC "-//JasperReports//DTD Report Design//EN"
          "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

          <jasperReport name="name_of_the_report" ... >
          ...
          </jasperReport>

          3. 報(bào)表參數(shù)

          報(bào)表參數(shù)是傳遞給報(bào)表填充操作的對(duì)象的引用,為報(bào)表引擎?zhèn)鬟f它無(wú)法在數(shù)據(jù)源中找到的數(shù)據(jù)是非常有用的。例如,我們可以將登陸執(zhí)行報(bào)表填充操作的用戶名傳給引擎,這樣我們可以在報(bào)表上顯示制表人或者動(dòng)態(tài)改變報(bào)表的標(biāo)題。

          一個(gè)使用報(bào)表參數(shù)的重要作用是完成報(bào)表的動(dòng)態(tài)查詢語(yǔ)句,以使報(bào)表獲得的數(shù)據(jù)更加符合要求,這些參數(shù)就像報(bào)表數(shù)據(jù)的過(guò)濾器。

          在報(bào)表中聲明參數(shù)非常簡(jiǎn)單,只需要指定名稱和類型(java類):

          <parameter name="ReportTitle" class="java.lang.String"/>

          <parameter name="MaxOrderID" class="java.lang.Integer"/>

          <parameter name="SummaryImage" class="java.awt.Image"/>

          可以用兩種方法在查詢語(yǔ)句中使用報(bào)表參數(shù):

          1. 就像通常在java.sql.PreparedStatement中使用參數(shù)一樣:

          SELECT * FROM Orders WHERE OrderID <= $P{MaxOrderID} ORDER BY ShipCountry

          2. 有時(shí)需要用參數(shù)來(lái)動(dòng)態(tài)改變SQL查詢的部分語(yǔ)句或者將整個(gè)SQL語(yǔ)句作為參數(shù)傳給報(bào)表,在這種情況下,語(yǔ)法有一點(diǎn)不同,如下:

          SELECT * FROM Orders ORDER BY $P!{OrderByClause}

          還有一些報(bào)表內(nèi)建的系統(tǒng)參數(shù)可以直接在表達(dá)式中使用:

          REPORT_PARAMETERS_MAP

          REPORT_CONNECTION

          REPORT_DATA_SOURCE

          REPORT_SCRIPTLET

          4. 數(shù)據(jù)源

          JasperReport只是各種類型的數(shù)據(jù)源,并提供一個(gè)JRDataSource的接口。該有一個(gè)缺省的實(shí)現(xiàn)類(JRResultSetDataSource class)包裝了ResultSet對(duì)象,允許使用任何通過(guò)JDBC連接的數(shù)據(jù)庫(kù)。使用JDBC數(shù)據(jù)源時(shí),即可以通過(guò)將數(shù)據(jù)庫(kù)連接傳給報(bào)表填充引擎并在報(bào)表定義中指定一個(gè)SQL查詢語(yǔ)句(參考dtd定義中的<queryString>元素)來(lái)提供數(shù)據(jù),也可以直接用ResultSet作參數(shù)生成JRResultSetDataSource對(duì)象來(lái)提供數(shù)據(jù)。

          對(duì)于其他的數(shù)據(jù)源,也不會(huì)太麻煩,只需要實(shí)現(xiàn)JRDataSource接口來(lái)創(chuàng)建自己的數(shù)據(jù)源類。

          5. 字段

          報(bào)表字段提供了唯一映射數(shù)據(jù)源中數(shù)據(jù)到報(bào)表數(shù)據(jù)的方式。如果數(shù)據(jù)源是ResultSet對(duì)象,報(bào)表字段必須對(duì)應(yīng)ResultSet對(duì)象中的列,就是說(shuō)報(bào)表字段必須和對(duì)應(yīng)的列有相同的名字和匹配的類型。

          例如,我們要?jiǎng)?chuàng)建的報(bào)表需要用Employees表的數(shù)據(jù),該表結(jié)構(gòu)如下:

          Column Name Datatype Length
          --------------------------------------
          EmployeeID int 4
          LastName varchar 20
          FirstName varchar 10
          HireDate datetime 8
          我們可以在報(bào)表設(shè)計(jì)文件中定義如下的字段:

          <field name="EmployeeID" class="java.lang.Integer"/>
          <field name="LastName" class="java.lang.String"/>
          <field name="FirstName" class="java.lang.String"/>
          <field name="HireDate" class="java.util.Date"/>
          如果我們生命一個(gè)報(bào)表字段在ResultSet中沒(méi)有對(duì)應(yīng)的列,則會(huì)在運(yùn)行時(shí)拋出異常。當(dāng)然ResultSet中的列沒(méi)有被聲明為報(bào)表字段不會(huì)影響報(bào)表的數(shù)據(jù)填充,但是他們?nèi)匀皇强梢栽L問(wèn)的。

          6. 表達(dá)式

          表達(dá)式是JasperReport的一個(gè)很強(qiáng)大有用的特性。用表達(dá)式可以:聲明報(bào)表變量來(lái)完成各種計(jì)算,為數(shù)據(jù)分組,指定報(bào)表文本字段內(nèi)容或?qū)ζ渌麍?bào)表對(duì)象的顯示進(jìn)行更靈活的定制。基本上,所有的報(bào)表表達(dá)式都是Java表達(dá)式,并且可以引用報(bào)表字段和報(bào)表變量。

          在報(bào)表設(shè)計(jì)的xml文件中有諸多定義表達(dá)式的元素:<variableExpression>, <initialValueExpression>, <groupExpression>, <printWhenExpression>, <imageExpression> 和<textFieldExpression>。

          要在在表達(dá)式中引用報(bào)表字段,字段名必須寫(xiě)在$F{和}符號(hào)之間。例如,如果我們要在一個(gè)文本域中連接兩個(gè)字段,我們可以像下面定義表達(dá)式:

          <textFieldExpression>
          $F{FirstName} + " " + $F{LastName}
          </textFieldExpression>
          表達(dá)式可以更復(fù)雜:

          <textFieldExpression>
          $F{FirstName} + " " + $F{LastName} + " was hired on " +
          (new SimpleDateFormat("MM/dd/yyyy")).format($F{HireDate}) + "."
          </textFieldExpression>
          要在表達(dá)式中引用一個(gè)變量,必須將變量名寫(xiě)在$V{和}符號(hào)之間,如下:

          <textFieldExpression>
          "Total quantity : " + $V{QuantitySum} + " kg."
          </textFieldExpression>
          對(duì)于報(bào)表參數(shù)也是同樣的語(yǔ)法,只不過(guò)參數(shù)名必須寫(xiě)在$P{和}符號(hào)之間:

          <textFieldExpression>
          "Max Order ID is : " + $P{MaxOrderID}
          </textFieldExpression>

          7. 變量

          報(bào)表變量是在表達(dá)式之前構(gòu)建的專用對(duì)象。變量只聲明一次,而可以在整個(gè)報(bào)表設(shè)計(jì)中重復(fù)使用,并在對(duì)應(yīng)的表達(dá)式中完成大量的計(jì)算,從而簡(jiǎn)化了報(bào)表設(shè)計(jì)。在表達(dá)式中,一個(gè)變量可以引用其它變量,但是被引用變量必須在引用變量之前聲明。所以變量的聲明順序?qū)?bào)表設(shè)計(jì)也是很重要的。

          變量還可以聲明來(lái)完成引擎內(nèi)建計(jì)算的求值,如:count、sum、average、lowest、highest、variance等等。一個(gè)完成Quantity字段sum計(jì)算的變量定義如下:

          <variable name="QuantitySum"

          class="java.lang.Double" calculation="Sum">

          <variableExpression>$F{Quantity}</variableExpression>

          </variable>

          我們還可以通過(guò)制定初始化級(jí)別來(lái)改變計(jì)算過(guò)程,默認(rèn)的級(jí)別是Report就是變量?jī)H在報(bào)表開(kāi)始處初始化一次,一直到報(bào)表結(jié)束完成計(jì)算。我們可以選擇更低的級(jí)別讓變量在每個(gè)Page、Column或者Group級(jí)別重新初始化。假如我們想計(jì)算計(jì)算每頁(yè)的總數(shù),變量聲明如下:

          <variable name="QuantitySum" class="java.lang.Double"
          resetType="Page" calculation="Sum">
          <variableExpression>$F{Quantity}</variableExpression>
          <initialValueExpression>new Double(0) </initialValueExpression>
          </variable>
          變量將在每一頁(yè)的開(kāi)始處被初始化為0。

          引擎還提供了如下的內(nèi)建變量可以在表達(dá)式中直接使用:

          PAGE_NUMBER
          COLUMN_NUMBER
          REPORT_COUNT
          PAGE_COUNT
          COLUMN_COUNT
          GroupName_COUNT

          8. 報(bào)表區(qū)域

          在創(chuàng)建報(bào)表模板時(shí),我們需要定義報(bào)表區(qū)域的內(nèi)容和風(fēng)格。一個(gè)完全的報(bào)表模板包括如下幾個(gè)區(qū)域:<title>, <pageHeader>, <columnHeader>, <groupHeader>, <detail>, <groupFooter>, <columnFoter>, <pageFooter>, <summary>。區(qū)域是報(bào)表的重要組成部分,它有指定的高度和寬度,并且可以容納直線、矩形、圖片或者文本域等報(bào)表對(duì)象。我們用<band>標(biāo)簽在報(bào)表模板xml文件中定義報(bào)表區(qū)域的內(nèi)容和風(fēng)格。下面是一個(gè)PageHeader區(qū)域的定義,它僅僅包含一條直線和一個(gè)靜態(tài)文本:

          <pageHeader>
          <band height="30">
          <rectangle>
          <reportElement x="0" y="0" width="555" height="25"/>
          <graphicElement/>
          </rectangle>
          <staticText>
          <reportElement x="0" y="0" width="555" height="25"/>
          <textElement textAlignment="Center">
          <font fontName="Helvetica" size="18"/>
          </textElement>
          <text>Northwind Order List</text>
          </staticText>
          </band>
          </pageHeader>

          9. 分組

          組表示一種分組組織數(shù)據(jù)的方式。填充報(bào)表數(shù)據(jù)時(shí),JasperReport引擎計(jì)算所有定義的分組表達(dá)式檢查是否出現(xiàn)組邊界(表達(dá)式的值改變),如果遇到組邊界則將<groupFooter>和<groupHeader>報(bào)表區(qū)域加入報(bào)表。

          報(bào)表可以包含任意多的分組,組在報(bào)表中的聲明順序很重要,因?yàn)榻M之間相互包含。一個(gè)組包含其后聲明組依此類推,一個(gè)大的組遇到邊界,所有的子組都將被重新初始化。一個(gè)報(bào)表組跟其數(shù)據(jù)分組表達(dá)式一起定義,同時(shí)還需要定義兩個(gè)報(bào)表分組區(qū)域:分組頭區(qū)域和分組尾區(qū)域。

          關(guān)于分組的詳細(xì)信息參考分組的報(bào)表示例。

          10. 字體和Unicode支持

          現(xiàn)在你可以用任何語(yǔ)言來(lái)創(chuàng)建報(bào)表。<font>元素的新屬性允許在Java字體和PDF字體間映射。PDF使用特定的字體集使得以前的JasperReport版本沒(méi)有辦法使用它們。新的屬性使用戶可以指定什么PDF字體用來(lái)顯示不同的字符集(pdfFontName屬性),什么編碼類型(pdfEncoding屬性)和是否將字體嵌入PDF文檔(isPdfEmbedded)。

          為了簡(jiǎn)化字體集的使用,增加了一個(gè)新屬性<reportFont>。報(bào)表字體是報(bào)表級(jí)別的字體定義用來(lái)作為報(bào)表中其他顯示對(duì)象的默認(rèn)字體。因?yàn)閷?duì)國(guó)際字符集的支持不知為何被綁定到iText庫(kù),你可以在iText documentation.文當(dāng)中找到更多關(guān)于如何用不同的語(yǔ)言不同的字符集創(chuàng)建PDF文檔的信息。

          11. Scriptlets

          所有的報(bào)表顯示數(shù)據(jù)來(lái)自報(bào)表變量和報(bào)表字段,這些數(shù)據(jù)可以用報(bào)表變量和表達(dá)式來(lái)處理。

          有時(shí)候報(bào)表需要對(duì)變量進(jìn)行特殊處理,一些變量可能在報(bào)表的某個(gè)事件中(報(bào)表開(kāi)始、換頁(yè)或者換列)被重新初始化,而且,變量在每次從數(shù)據(jù)源中獲得數(shù)據(jù)時(shí)(每一行)都被計(jì)算。而僅僅用簡(jiǎn)單變量表達(dá)式無(wú)法實(shí)現(xiàn)所有的復(fù)雜功能,這時(shí)就要使用Scriptlet。

          因?yàn)镾criptlet主要和報(bào)表變量一起工作,完全控制scriptlet的執(zhí)行時(shí)機(jī)非常重要。JasperReport允許根據(jù)報(bào)表事件定制Java編碼BEFORE或者AFTER:Report、Page、Column和Group的初始化來(lái)執(zhí)行Scriptlet。

          要使用Scriptlet,開(kāi)發(fā)者只需要通過(guò)繼承net.sf.jasperreports.engine.JRAbstractScriptlet或者net.sf.jasperreports.engine.JRDefaultScriptlet來(lái)創(chuàng)建Scritplet類。該定制的Scriptlet類會(huì)被指定為<jasperReport>的scritpletClass屬性的值。創(chuàng)建Scriptlet時(shí)開(kāi)發(fā)這需要實(shí)現(xiàn)或者重載如beforeReportInit(), afterReportInit(), beforePageInit(), afterPageInit(), beforeGroupInit(), afterGroupInit(),等方法。這些方法將在填充數(shù)據(jù)時(shí)被引擎在適當(dāng)?shù)臅r(shí)候調(diào)用。

          有一個(gè)叫做REPORT_SCRIPTLET的默認(rèn)報(bào)表參數(shù)表示對(duì)報(bào)表引擎在填充數(shù)據(jù)時(shí)實(shí)例化的Scriptlet對(duì)象的引用。它可以在整個(gè)報(bào)表的任何表達(dá)式中使用來(lái)調(diào)用Scriptlet的特定方法使整個(gè)報(bào)表機(jī)制更加靈活。

          12. 子報(bào)表
          子報(bào)表是報(bào)表工具的重要特性,它允許創(chuàng)建更復(fù)雜的報(bào)表并簡(jiǎn)化設(shè)計(jì)工作。自報(bào)表在創(chuàng)建主從報(bào)表時(shí)特別有用。
          posted @ 2006-12-21 17:13 soufan 閱讀(4096) | 評(píng)論 (0)編輯 收藏

          如何在JSP頁(yè)面中訪問(wèn)web.xml中的初始化參數(shù)?

          你可以使用預(yù)定義的JSF EL變量??initParam來(lái)訪問(wèn):
          例如,如果你有:
          <context-param>
           <param-name>productId</param-name>
          

          如何從java代碼中訪問(wèn)web.xml 中的初始化參數(shù)?

          你可以使用externalContext的 getInitParameter 方法得到他們.例如 如果你的參數(shù)如下:
          <context-param>
           <param-name>connectionString</param-name>
           <param-value>jdbc:oracle:thin:scott/tiger@cartman:1521:O901DB</param-value>
          </context-param>
          

          你可以使用下面代碼訪問(wèn)connectionString :

          FacesContext?fc?=?FacesContext.getCurrentInstance();
          String?connection?=?fc.getExternalContext().getInitParameter("connectionString");

          ?

          posted @ 2006-12-19 16:25 soufan 閱讀(722) | 評(píng)論 (0)編輯 收藏

          在客戶端實(shí)現(xiàn)可能很簡(jiǎn)單.你可以包裝JSP頁(yè)面(或者你想要隱藏的一部分)到一個(gè)div中,然后你可以添加更多div,當(dāng)用戶點(diǎn)擊提交按鈕時(shí)這些div出現(xiàn).這些div可以包含gif動(dòng)畫(huà)和其他內(nèi)容.
          場(chǎng)景:當(dāng)用戶點(diǎn)擊按鈕,調(diào)用JS函數(shù),該函數(shù)隱藏頁(yè)面并且顯示"請(qǐng)等待..."div.你可以使用CSS來(lái)自定義外觀:
          下面是一個(gè)正常工作的例子:
          <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
          <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
          <f:loadBundle basename="demo.bundle.Messages" var="Message"/>
           
          <html>
          <head> 
            <title>Input Name Page</title>
            <script>
              function gowait() {
                document.getElementById("main").style.visibility="hidden";
                document.getElementById("wait").style.visibility="visible";
              }
             </script>
              
           </head>
           <body bgcolor="white">
            <f:view>
              <div id="main">
                 <h1><h:outputText value="#{Message.inputname_header}"/></h1>
                 <h:messages style="color: red"/>
                 <h:form id="helloForm">
              
                   <h:outputText value="#{Message.prompt}"/>
                   <h:inputText id="userName" value="#{GetNameBean.userName}" required="true">
                     <f:validateLength minimum="2" maximum="20"/>
                   </h:inputText>
                   <h:commandButton onclick="gowait()" id="submit" 
                         action="#{GetNameBean.action}" value="Say Hello" />
                 </h:form>
              </div>
              <div id="wait" style="visibility:hidden; position: absolute; top: 0; left: 0">
                 <table width="100%" height ="300px"> 
                   <tr>
                     <td align="center" valign="middle">
                       <h2>Please, wait...</h2>
                     </td>
                   </tr>
                 </table>
              </div>
            </f:view>
           </body>
          </html>  
          

          如果你想有一個(gè)動(dòng)畫(huà)gif圖片在"請(qǐng)等待..."中,當(dāng)表單提交后該圖片應(yīng)該從新加載.因此,再一次指定圖片的id,并且添加經(jīng)過(guò)一段時(shí)間延時(shí)后重新加載的代碼.下面是個(gè)例子:

          <script>
           function gowait() {
             document.getElementById("main").style.visibility="hidden";
             document.getElementById("wait").style.visibility="visible";
             window.setTimeout('showProgress()', 500);
           }
            function showProgress(){ 
             var wg = document.getElementById("waitgif");
             wg.src=wg.src;
           }
          </script>
          ....
          ....
          ....
           
          <img id="waitgif" src="animated.gif">
          

          下面是一個(gè)使用action listener 的一個(gè)例子.
          添加下面的代碼到backing bean的action listener中:
          public?void?viewPdf(ActionEvent?event)?{
          ?String?filename?=?"filename.pdf";

          ?//?use?your?own?method?that?reads?file?to?the?byte?array
          ?byte[]?pdf?=?getTheContentOfTheFile(filename);?

          ?FacesContext?faces?=?FacesContext.getCurrentInstance();
          ?HttpServletResponse?response?=?(HttpServletResponse)?faces.getExternalContext().getResponse();
          ?response.setContentType("application/pdf");
          ?response.setContentLength(pdf.length);
          ?response.setHeader(?"Content-disposition",?"inline;?filename=\""+fileName+"\"");
          ?try?{
          ??ServletOutputStream?out;
          ??out?=?response.getOutputStream();
          ??out.write(pdf);
          ?}?catch?(IOException?e)?{
          ??e.printStackTrace();
          ?}
          ?faces.responseComplete();
          }
          posted @ 2006-12-19 16:20 soufan 閱讀(495) | 評(píng)論 (0)編輯 收藏

          使用backing bean來(lái)添加UIComponents 到頁(yè)面中?

          下面是一個(gè)例子:

          jsp1.jsp:

          <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
          <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
          <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
          <html>
          <f:view>
          <head>
          <title>jsp1</title>
            <link rel="stylesheet" type="text/css" href="./style.css" title="Style"/>
          </head>
          <body bgcolor="#ffffff">  TESTING...
            <h:form id="form1">
              <h:panelGrid id="panelgridtest" binding="#{jsp1Bean.component}"/>
            </h:form>
          </body>
          </f:view>
          </html>
          

          ?

          Jsp1Bean.java:

          package?test;
          ?
          import?javax.faces.application.Application;
          import?javax.faces.component.UIComponent;
          import?javax.faces.component.UIPanel;
          import?javax.faces.component.UIViewRoot;
          import?javax.faces.component.html.HtmlInputText;
          import?javax.faces.component.html.HtmlOutputText;
          import?javax.faces.context.FacesContext;
          ?
          public?class?Jsp1Bean
          {
          ????UIComponent?component?=?null;
          ????FacesContext?facesContext?=?FacesContext.getCurrentInstance();
          ????UIViewRoot?uIViewRoot?=?facesContext.getViewRoot();
          ????Application?application?=?facesContext.getApplication();
          ?
          ????public?Jsp1Bean()
          ????{
          ????}
          ?
          ????public?UIComponent?getComponent()
          ????{
          ????????if?(component?==?null)
          ????????{
          ????????????component?=?new?UIPanel();
          ????????}
          ????????return?component;
          ????}
          ?
          ????public?void?setComponent(UIComponent?component)
          ????{
          ????????this.component?=?component;
          ????}
          ?
          ?????//initialization?block
          ????{
          ????????try
          ????????{
          ????????????//outputText1
          ????????????HtmlOutputText?outputText1?=?(HtmlOutputText)?
          ??????????????facesContext.getApplication().createComponent(HtmlOutputText.COMPONENT_TYPE);
          ????????????outputText1.setValue("---the?outputText1?value---");
          ????????????//inputText1
          ????????????HtmlInputText?inputText1?=?(HtmlInputText)
          ????????????????facesContext.getApplication().createComponent(HtmlInputText.COMPONENT_TYPE);
          ????????????inputText1.setValue("---the?inputText1?value---");
          ?
          ????????????//add?outputText1?and?inputText1?to?component?("UIPanel")
          ????????????this.getComponent().getChildren().add(outputText1);
          ????????????this.getComponent().getChildren().add(inputText1);
          ????????}
          ????????catch?(java.lang.Throwable?t)
          ????????{
          ????????????System.out.println("java.lang.Throwable?exception?encountered...t.getMessage()="?+?t.getMessage());
          ????????????t.printStackTrace();
          ????????}
          ????}
          ?
          ????public?String?doAction()
          ????{
          ????????return?"submit";
          ????}
          }

          ?

          faces-config.xml:

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
                                        "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
          <faces-config>
            <navigation-rule>
              <from-view-id>/jsp1</from-view-id>
              <navigation-case>
                <from-action>submit</from-action>
                <to-view-id>/jsp1</to-view-id>
                <redirect/>
              </navigation-case>
            </navigation-rule>
            <managed-bean>
              <managed-bean-name>jsp1Bean</managed-bean-name>
              <managed-bean-class>test.Jsp1Bean</managed-bean-class>
              <managed-bean-scope>session</managed-bean-scope>
            </managed-bean>
          </faces-config>
          
          posted @ 2006-12-19 16:14 soufan 閱讀(243) | 評(píng)論 (0)編輯 收藏

          如何在BackBean中使用SelectMany 對(duì)象?

          Hi.

          This page was made fast and I hope don't be a nuisance to someboby

          首先我們定義backbean來(lái)管理我們的 selectMany "list" :

           <managed-bean>
            <managed-bean-name>Manager</managed-bean-name>
           <managed-bean-class>demo.Manager</managed-bean-class>
            <managed-bean-scope>request</managed-bean-scope>
           <managed-bean>
          

          現(xiàn)在Manager類應(yīng)該有個(gè) SelectMany object來(lái)管理信息;

          ?

          package?demo;
          import?javax.faces.component.UISelectMany;
          import?javax.faces.component.UIComponent;

          class?Manager{
          ???
          ????private?UISelectMany?list;
          ???????

          ??????/*
          ???????*?Here?we?must?create?our?list?of?objects
          ???????*?obviously?we?may?add?a?cycle?"while"?or?"for"?
          ???????*?if?we?wouldn't?know?the?number?of?items
          ???????*/?
          ????public?UIComponentBase?getList(){
          ??????
          ?????????list=new?UISelectMany();
          ?????????SelectItem?item?=?new?SelectItem(?"value",?"Description"?);
          ?????????UISelectItem?uiItem?=?new?UISelectItem();
          ?????????uiItem.setValue(?item?);
          ?????????
          ?????????list.getChildren().add(?uiItem?);
          ??????
          ??????return?list;
          ????}

          ????public?void?setList(UIComponentBase?list){
          ????????this.list=(UISelectMany)list;?
          ????}
          ????
          ???public?void?actionListener(ActionEvent?ev){
          ???????
          ???????Object?obj?[]?=?list.getSelectedValues();
          ???????//?obj?is?an?array?of?string?that?contents?the?values?of?our?selectItems
          ???}

          }

          ?

          JSP頁(yè)面的代碼如下:?

          <h:selectManyMenu binding="#{Manager.list}">
          

          如果你想使用CheckBox or a ListBox僅僅在JSF文件中該變標(biāo)簽就可以了.如 <h:selectManyCheckBox> by either <h:selectManyListbox> or <h:selectManyCheckbox>, it is great!!

          posted @ 2006-12-19 16:12 soufan 閱讀(331) | 評(píng)論 (0)編輯 收藏

          How to change destination JSP from within RENDER_RESPONSE phase?

          public?void?
          beforePhase ( PhaseEvent?arg0 )?
          {
          if ( arg0.getPhaseId () ==?PhaseId.RENDER_RESPONSE )
          {
          ?? FacesContext?facesContext?=?arg0.getFacesContext () ;
          ?? ViewHandler?vh??=?facesContext.getApplication () .getViewHandler () ;
          ?? UIViewRoot?newRoot?=?vh.createView ( facesContext,? "/yourNew.jsp" ) ;
          ?? facesContext.setViewRoot ( newRoot ) ;
          }



          How to foward to another JSP from an actionListener ActionEvent

          有兩種方法:

          簡(jiǎn)單的方法是在commandlink中添加一個(gè) action attribute? .然后你有一個(gè)actionListener?和 an action Attribute, 兩個(gè)都是可行的.

          但是你還可以使用下面的代碼:

          String?viewId?=?"/edit.jsp";
          FacesContext?context?=?FacesContext.getCurrentInstance();
          UIViewRoot?view?=?context.getApplication().getViewHandler().createView(context,?viewId);
          view.setViewId(viewId);
          context.setViewRoot(view);
          context.renderResponse();


          如何從java代碼中重定向一個(gè)JSF頁(yè)面

          示例代碼如下:

          public?static?void?redirectPage(String?szPage)
          {
          ?FacesContext?context?=?FacesContext.getCurrentInstance();
          ?javax.faces.application.Application?app?=?context.getApplication();
          ?UIViewRoot?view?=?app.getViewHandler().createView(context,?szPage);
          ?context.setViewRoot(view);
          ?context.renderResponse();
          }
          posted @ 2006-12-19 16:10 soufan 閱讀(384) | 評(píng)論 (0)編輯 收藏

          (轉(zhuǎn))
          下面是一個(gè)email驗(yàn)證器的示例: ?

          EmailValidator.java:

          import?javax.faces.application.FacesMessage;
          import?javax.faces.component.UIComponent;
          import?javax.faces.context.FacesContext;
          import?javax.faces.validator.Validator;
          import?javax.faces.validator.ValidatorException;
          ?
          public?class?EmailValidator?implements?Validator?{
          ?
          ????private?String?errorMessage?=?null;
          ?
          ????public?void?setErrorMessage(String?errorMessage)?{?this.errorMessage?=?errorMessage;?}
          ?
          ????public?void?validate(FacesContext?context,?UIComponent?component,?Object?value)?{
          ????????if?(null?==?value)?{
          ????????????return;
          ????????}
          ?
          ????????String?email?=?(String)?value;
          ?
          ????????if?(-1?==?email.indexOf('@',?1)?||?-1?==?email.indexOf('.'))?{
          ????????????if?(errorMessage?!=?null)?{
          ????????????????throw?new?ValidatorException(new?FacesMessage(Tags.eval(errorMessage)));
          ????????????}?else?{
          ????????????????//?use?default?validator?message
          ????????????????throw?new?ValidatorException(null);
          ????????????}
          ????????}
          ????}
          }

          Tags.java:

          import?javax.faces.application.Application;
          import?javax.faces.component.UIComponent;
          import?javax.faces.component.UIInput;
          import?javax.faces.context.FacesContext;
          import?javax.faces.el.MethodBinding;
          import?javax.faces.el.ValueBinding;
          import?javax.faces.event.ValueChangeEvent;
          import?javax.faces.webapp.ConverterTag;
          import?javax.faces.webapp.UIComponentTag;
          ?
          public?class?Tags?{
          ???//?Converter?Tags?and?Validator?Tags?helper?methods
          ????public?static?String?eval(String?expression)?{
          ????????if?(expression?!=?null?&&?UIComponentTag.isValueReference(expression))?{
          ????????????FacesContext?context?=?FacesContext.getCurrentInstance();
          ????????????Application?app?=?context.getApplication();
          ????????????ValueBinding?vb?=?app.createValueBinding(expression);
          ????????????return?""?+?vb.getValue(context);
          ????????}?else?{
          ????????????return?expression;
          ????????}
          ????}
          }

          ?

          ?

          ?

          EmailValidatorTag.java:

          import?javax.faces.component.UIComponent;
          import?javax.faces.validator.Validator;
          import?javax.faces.webapp.ValidatorTag;
          import?javax.servlet.jsp.JspException;
          ?
          public?class?EmailValidatorTag?extends?ValidatorTag?{
          ?
          ????private?String?errorMessage?=?null;
          ?
          ????public?EmailValidatorTag()?{
          ????????setValidatorId("Email");
          ????}
          ?
          ????public?void?setErrorMessage(String?errorMessage)?{?this.errorMessage?=?errorMessage;?}
          ?
          ????public?Validator?createValidator()?throws?JspException?{
          ????????EmailValidator?validator?=?(EmailValidator)?super.createValidator();
          ????????validator.setErrorMessage(errorMessage);
          ?
          ????????return?validator;
          ????}
          ?
          ????public?void?release()?{
          ????????errorMessage?=?null;
          ????}
          }

          ?

          ?

          faces-config.xml:

          <validator>
              <validator-id>Email</validator-id>
              <validator-class>EmailValidator</validator-class>
          </validator>
          

          mytags.tld:

          <?xml version="1.0" encoding="UTF-8"?>
           
          <!DOCTYPE taglib PUBLIC
              "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
              "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
           
          <taglib>
           
          <tlibversion>1.0</tlibversion>
          <jspversion>1.2</jspversion>
          <shortname>mytags</shortname>
          <uri>mytags</uri>
           
          <tag>
              <name>validateEmail</name>
              <tagclass>EmailValidatorTag</tagclass>
           
              <attribute>
                  <name>errorMessage</name>
                  <description>message if a validation error occurs</description>
              </attribute>
          </tag>
           
          </taglib>
          

          ?

          mypage.jsp:

          <h:inputText id="email" required="true">
              <mytags:validateEmail errorMessage="#{bean.message}"/>
          </h:inputText>
          
          posted @ 2006-12-19 16:02 soufan 閱讀(241) | 評(píng)論 (0)編輯 收藏

          如何為每一個(gè)錯(cuò)誤消息顯示一個(gè)圖片

          使用CSS style來(lái)實(shí)現(xiàn)該功能.例如,你有如下的代碼來(lái)顯示消息:
          <div align="center">
           <h:messages id="errMsgs" styleClass="errorFeedback" layout="table" />
          </div>

          ??errorFeedback style class 可能是下面的代碼:

          .errorFeedback {
           color: black;
           vertical-align: middle;
           background-image: url(/AccountSetup/images/warning_feedback.gif);
           background-repeat: no-repeat;
           background-position: left top;
           font-family: Verdana, Arial, Helvetica, sans-serif;
           font-weight: bold;
           line-height: 18px;
           font-size: 10pt;
           text-align: left;
           text-indent: 22px;}
          
          posted @ 2006-12-19 15:59 soufan 閱讀(176) | 評(píng)論 (0)編輯 收藏

          (轉(zhuǎn)) Filter和Servlet中如何訪問(wèn)FacesContext?

          ?

          在?Faces realm外,例如 在 ?filter 或者servlet中,當(dāng) FacesContent.getCurrentInstance() 返回null時(shí)候,你可以使用FacesContextFactory來(lái)得到FacesContext,下面是一個(gè)示例.


          //?You?need?an?inner?class?to?be?able?to?call?FacesContext.setCurrentInstance
          //?since?it's?a?protected?method
          private?abstract?static?class?InnerFacesContext?extends?FacesContext
          {
          ??protected?static?void?setFacesContextAsCurrentInstance(FacesContext?facesContext)?{
          ????FacesContext.setCurrentInstance(facesContext);
          ??}
          }

          private?FacesContext?getFacesContext(ServletRequest?request,?ServletResponse?response)?{
          ??//?Try?to?get?it?first
          ??FacesContext?facesContext?=?FacesContext.getCurrentInstance();
          ??if?(facesContext?!=?null)?return?facesContext;

          ??FacesContextFactory?contextFactory?=?(FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
          ??LifecycleFactory?lifecycleFactory?=?(LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
          ??Lifecycle?lifecycle?=?lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);

          ??//?Either?set?a?private?member?servletContext?=?filterConfig.getServletContext();
          ??//?in?you?filter?init()?method?or?set?it?here?like?this:
          ??//?ServletContext?servletContext?=?((HttpServletRequest)request).getSession().getServletContext();
          ??//?Note?that?the?above?line?would?fail?if?you?are?using?any?other?protocol?than?http

          ??//?Doesn't?set?this?instance?as?the?current?instance?of?FacesContext.getCurrentInstance
          ??facesContext?=?contextFactory.getFacesContext(servletContext,?request,?response,?lifecycle);

          ??//?Set?using?our?inner?class
          ??InnerFacesContext.setFacesContextAsCurrentInstance(facesContext);

          ??//?set?a?new?viewRoot,?otherwise?context.getViewRoot?returns?null
          ??UIViewRoot?view?=?facesContext.getApplication().getViewHandler().createView(facesContext,?"yourOwnID");
          facesContext.setViewRoot(view);

          ??return?facesContext;
          }
          posted @ 2006-12-19 15:52 soufan 閱讀(427) | 評(píng)論 (0)編輯 收藏

          J2EE 全面簡(jiǎn)介(轉(zhuǎn)載)

          本文從五個(gè)方面對(duì)J2EE進(jìn)行了比較全面的介紹。從J2EE的概念說(shuō)起,到它的優(yōu)勢(shì),到J2EE典型的四層模型,和它的框架結(jié)構(gòu),最后是J2EE十三種核心技術(shù)的一個(gè)簡(jiǎn)介。本文分門(mén)別類的對(duì)J2EE中的服務(wù),組件,層次,容器,API都做了比較詳細(xì)的介紹,相信看完此文,讀者會(huì)對(duì)J2EE有一個(gè)更清晰的認(rèn)識(shí)。

          J2EE的概念

          目前,Java 2平臺(tái)有3個(gè)版本,它們是適用于小型設(shè)備和智能卡的Java 2平臺(tái)Micro版(Java 2 Platform Micro Edition,J2ME)、適用于桌面系統(tǒng)的Java 2平臺(tái)標(biāo)準(zhǔn)版(Java 2 Platform Standard Edition,J2SE)、適用于創(chuàng)建服務(wù)器應(yīng)用程序和服務(wù)的Java 2平臺(tái)企業(yè)版(Java 2 Platform Enterprise Edition,J2EE)。

          J2EE是一種利用Java 2平臺(tái)來(lái)簡(jiǎn)化企業(yè)解決方案的開(kāi)發(fā)、部署和管理相關(guān)的復(fù)雜問(wèn)題的體系結(jié)構(gòu)。J2EE技術(shù)的基礎(chǔ)就是核心Java平臺(tái)或Java 2平臺(tái)的標(biāo)準(zhǔn)版,J2EE不僅鞏固了標(biāo)準(zhǔn)版中的許多優(yōu)點(diǎn),例如"編寫(xiě)一次、隨處運(yùn)行"的特性、方便存取數(shù)據(jù)庫(kù)的JDBC API、CORBA技術(shù)以及能夠在Internet應(yīng)用中保護(hù)數(shù)據(jù)的安全模式等等,同時(shí)還提供了對(duì) EJB(Enterprise JavaBeans)、Java Servlets API、JSP(Java Server Pages)以及XML技術(shù)的全面支持。其最終目的就是成為一個(gè)能夠使企業(yè)開(kāi)發(fā)者大幅縮短投放市場(chǎng)時(shí)間的體系結(jié)構(gòu)。

          J2EE體系結(jié)構(gòu)提供中間層集成框架用來(lái)滿足無(wú)需太多費(fèi)用而又需要高可用性、高可靠性以及可擴(kuò)展性的應(yīng)用的需求。通過(guò)提供統(tǒng)一的開(kāi)發(fā)平臺(tái),J2EE降低了開(kāi)發(fā)多層應(yīng)用的費(fèi)用和復(fù)雜性,同時(shí)提供對(duì)現(xiàn)有應(yīng)用程序集成強(qiáng)有力支持,完全支持Enterprise JavaBeans,有良好的向?qū)еС执虬筒渴饝?yīng)用,添加目錄支持,增強(qiáng)了安全機(jī)制,提高了性能。





          回頁(yè)首


          J2EE的優(yōu)勢(shì)

          J2EE為搭建具有可伸縮性、靈活性、易維護(hù)性的商務(wù)系統(tǒng)提供了良好的機(jī)制:

          1. 保留現(xiàn)存的IT資產(chǎn): 由于企業(yè)必須適應(yīng)新的商業(yè)需求,利用已有的企業(yè)信息系統(tǒng)方面的投資,而不是重新制定全盤(pán)方案就變得很重要。這樣,一個(gè)以漸進(jìn)的(而不是激進(jìn)的,全盤(pán)否定的)方式建立在已有系統(tǒng)之上的服務(wù)器端平臺(tái)機(jī)制是公司所需求的。J2EE架構(gòu)可以充分利用用戶原有的投資,如一些公司使用的BEA Tuxedo、IBM CICS, IBM Encina,、Inprise VisiBroker 以及Netscape Application Server。這之所以成為可能是因?yàn)镴2EE擁有廣泛的業(yè)界支持和一些重要的'企業(yè)計(jì)算'領(lǐng)域供應(yīng)商的參與。每一個(gè)供應(yīng)商都對(duì)現(xiàn)有的客戶提供了不用廢棄已有投資,進(jìn)入可移植的J2EE領(lǐng)域的升級(jí)途徑。由于基于J2EE平臺(tái)的產(chǎn)品幾乎能夠在任何操作系統(tǒng)和硬件配置上運(yùn)行,現(xiàn)有的操作系統(tǒng)和硬件也能被保留使用。
          2. 高效的開(kāi)發(fā): J2EE允許公司把一些通用的、很繁瑣的服務(wù)端任務(wù)交給中間件供應(yīng)商去完成。這樣開(kāi)發(fā)人員可以集中精力在如何創(chuàng)建商業(yè)邏輯上,相應(yīng)地縮短了開(kāi)發(fā)時(shí)間。高級(jí)中間件供應(yīng)商提供以下這些復(fù)雜的中間件服務(wù):
            • 狀態(tài)管理服務(wù) -- 讓開(kāi)發(fā)人員寫(xiě)更少的代碼,不用關(guān)心如何管理狀態(tài),這樣能夠更快地完成程序開(kāi)發(fā)。
            • 持續(xù)性服務(wù) -- 讓開(kāi)發(fā)人員不用對(duì)數(shù)據(jù)訪問(wèn)邏輯進(jìn)行編碼就能編寫(xiě)應(yīng)用程序,能生成更輕巧,與數(shù)據(jù)庫(kù)無(wú)關(guān)的應(yīng)用程序,這種應(yīng)用程序更易于開(kāi)發(fā)與維護(hù)。
            • 分布式共享數(shù)據(jù)對(duì)象CACHE服務(wù) -- 讓開(kāi)發(fā)人員編制高性能的系統(tǒng),極大提高整體部署的伸縮性。
          3. 支持異構(gòu)環(huán)境: J2EE能夠開(kāi)發(fā)部署在異構(gòu)環(huán)境中的可移植程序。基于J2EE的應(yīng)用程序不依賴任何特定操作系統(tǒng)、中間件、硬件。因此設(shè)計(jì)合理的基于J2EE的程序只需開(kāi)發(fā)一次就可部署到各種平臺(tái)。這在典型的異構(gòu)企業(yè)計(jì)算環(huán)境中是十分關(guān)鍵的。J2EE標(biāo)準(zhǔn)也允許客戶訂購(gòu)與J2EE兼容的第三方的現(xiàn)成的組件,把他們部署到異構(gòu)環(huán)境中,節(jié)省了由自己制訂整個(gè)方案所需的費(fèi)用。
          4. 可伸縮性: 企業(yè)必須要選擇一種服務(wù)器端平臺(tái),這種平臺(tái)應(yīng)能提供極佳的可伸縮性去滿足那些在他們系統(tǒng)上進(jìn)行商業(yè)運(yùn)作的大批新客戶。基于J2EE平臺(tái)的應(yīng)用程序可被部署到各種操作系統(tǒng)上。例如可被部署到高端UNIX與大型機(jī)系統(tǒng),這種系統(tǒng)單機(jī)可支持64至256個(gè)處理器。(這是NT服務(wù)器所望塵莫及的)J2EE領(lǐng)域的供應(yīng)商提供了更為廣泛的負(fù)載平衡策略。能消除系統(tǒng)中的瓶頸,允許多臺(tái)服務(wù)器集成部署。這種部署可達(dá)數(shù)千個(gè)處理器,實(shí)現(xiàn)可高度伸縮的系統(tǒng),滿足未來(lái)商業(yè)應(yīng)用的需要。
          5. 穩(wěn)定的可用性: 一個(gè)服務(wù)器端平臺(tái)必須能全天候運(yùn)轉(zhuǎn)以滿足公司客戶、合作伙伴的需要。因?yàn)镮NTERNET是全球化的、無(wú)處不在的,即使在夜間按計(jì)劃停機(jī)也可能造成嚴(yán)重?fù)p失。若是意外停機(jī),那會(huì)有災(zāi)難性后果。J2EE部署到可靠的操作環(huán)境中,他們支持長(zhǎng)期的可用性。一些J2EE部署在WINDOWS環(huán)境中,客戶也可選擇健壯性能更好的操作系統(tǒng)如Sun Solaris、IBM OS/390。最健壯的操作系統(tǒng)可達(dá)到99.999%的可用性或每年只需5分鐘停機(jī)時(shí)間。這是實(shí)時(shí)性很強(qiáng)商業(yè)系統(tǒng)理想的選擇。




          回頁(yè)首


          J2EE 的四層模型

          J2EE使用多層的分布式應(yīng)用模型,應(yīng)用邏輯按功能劃分為組件,各個(gè)應(yīng)用組件根據(jù)他們所在的層分布在不同的機(jī)器上。事實(shí)上,sun設(shè)計(jì)J2EE的初衷正是為了解決兩層模式(client/server)的弊端,在傳統(tǒng)模式中,客戶端擔(dān)當(dāng)了過(guò)多的角色而顯得臃腫,在這種模式中,第一次部署的時(shí)候比較容易,但難于升級(jí)或改進(jìn),可伸展性也不理想,而且經(jīng)常基于某種專有的協(xié)議?D?D通常是某種數(shù)據(jù)庫(kù)協(xié)議。它使得重用業(yè)務(wù)邏輯和界面邏輯非常困難。現(xiàn)在J2EE 的多層企業(yè)級(jí)應(yīng)用模型將兩層化模型中的不同層面切分成許多層。一個(gè)多層化應(yīng)用能夠?yàn)椴煌拿糠N服務(wù)提供一個(gè)獨(dú)立的層,以下是 J2EE 典型的四層結(jié)構(gòu):

          • 運(yùn)行在客戶端機(jī)器上的客戶層組件
          • 運(yùn)行在J2EE服務(wù)器上的Web層組件
          • 運(yùn)行在J2EE服務(wù)器上的業(yè)務(wù)邏輯層組件
          • 運(yùn)行在EIS服務(wù)器上的企業(yè)信息系統(tǒng)(Enterprise information system)層軟件


          J2EE應(yīng)用程序組件
          J2EE應(yīng)用程序是由組件構(gòu)成的.J2EE組件是具有獨(dú)立功能的軟件單元,它們通過(guò)相關(guān)的類和文件組裝成J2EE應(yīng)用程序,并與其他組件交互。J2EE說(shuō)明書(shū)中定義了以下的J2EE組件:

          • 應(yīng)用客戶端程序和applets是客戶層組件.
          • Java Servlet和JavaServer Pages(JSP)是web層組件.
          • Enterprise JavaBeans(EJB)是業(yè)務(wù)層組件.

          客戶層組件
          J2EE應(yīng)用程序可以是基于web方式的,也可以是基于傳統(tǒng)方式的.

          web 層組件
          J2EE web層組件可以是JSP 頁(yè)面或Servlets.按照J(rèn)2EE規(guī)范,靜態(tài)的HTML頁(yè)面和Applets不算是web層組件。

          正如下圖所示的客戶層那樣,web層可能包含某些 JavaBean 對(duì)象來(lái)處理用戶輸入,并把輸入發(fā)送給運(yùn)行在業(yè)務(wù)層上的enterprise bean 來(lái)進(jìn)行處理。



          業(yè)務(wù)層組件
          業(yè)務(wù)層代碼的邏輯用來(lái)滿足銀行,零售,金融等特殊商務(wù)領(lǐng)域的需要,由運(yùn)行在業(yè)務(wù)層上的enterprise bean 進(jìn)行處理. 下圖表明了一個(gè)enterprise bean 是如何從客戶端程序接收數(shù)據(jù),進(jìn)行處理(如果必要的話), 并發(fā)送到EIS 層儲(chǔ)存的,這個(gè)過(guò)程也可以逆向進(jìn)行。

          有三種企業(yè)級(jí)的bean: 會(huì)話(session) beans, 實(shí)體(entity) beans, 和消息驅(qū)動(dòng)(message-driven) beans. 會(huì)話bean 表示與客戶端程序的臨時(shí)交互. 當(dāng)客戶端程序執(zhí)行完后, 會(huì)話bean 和相關(guān)數(shù)據(jù)就會(huì)消失. 相反, 實(shí)體bean 表示數(shù)據(jù)庫(kù)的表中一行永久的記錄. 當(dāng)客戶端程序中止或服務(wù)器關(guān)閉時(shí), 就會(huì)有潛在的服務(wù)保證實(shí)體bean 的數(shù)據(jù)得以保存.消息驅(qū)動(dòng) bean 結(jié)合了會(huì)話bean 和 JMS的消息監(jiān)聽(tīng)器的特性, 允許一個(gè)業(yè)務(wù)層組件異步接收J(rèn)MS 消息.



          企業(yè)信息系統(tǒng)層
          企業(yè)信息系統(tǒng)層處理企業(yè)信息系統(tǒng)軟件包括企業(yè)基礎(chǔ)建設(shè)系統(tǒng)例如企業(yè)資源計(jì)劃 (ERP), 大型機(jī)事務(wù)處理, 數(shù)據(jù)庫(kù)系統(tǒng),和其它的遺留信息系統(tǒng). 例如,J2EE 應(yīng)用組件可能為了數(shù)據(jù)庫(kù)連接需要訪問(wèn)企業(yè)信息系統(tǒng)





          回頁(yè)首


          J2EE 的結(jié)構(gòu)

          這種基于組件,具有平臺(tái)無(wú)關(guān)性的J2EE 結(jié)構(gòu)使得J2EE 程序的編寫(xiě)十分簡(jiǎn)單,因?yàn)闃I(yè)務(wù)邏輯被封裝成可復(fù)用的組件,并且J2EE 服務(wù)器以容器的形式為所有的組件類型提供后臺(tái)服務(wù). 因?yàn)槟悴挥米约洪_(kāi)發(fā)這種服務(wù), 所以你可以集中精力解決手頭的業(yè)務(wù)問(wèn)題.

          容器和服務(wù)
          容器設(shè)置定制了J2EE服務(wù)器所提供得內(nèi)在支持,包括安全,事務(wù)管理,JNDI(Java Naming and Directory Interface)尋址,遠(yuǎn)程連接等服務(wù),以下列出最重要的幾種服務(wù):

          • J2EE安全(Security)模型可以讓你配置 web 組件或enterprise bean ,這樣只有被授權(quán)的用戶才能訪問(wèn)系統(tǒng)資源. 每一客戶屬于一個(gè)特別的角色,而每個(gè)角色只允許激活特定的方法。你應(yīng)在enterprise bean的布置描述中聲明角色和可被激活的方法。由于這種聲明性的方法,你不必編寫(xiě)加強(qiáng)安全性的規(guī)則。
          • J2EE 事務(wù)管理(Transaction Management)模型讓你指定組成一個(gè)事務(wù)中所有方法間的關(guān)系,這樣一個(gè)事務(wù)中的所有方法被當(dāng)成一個(gè)單一的單元. 當(dāng)客戶端激活一個(gè)enterprise bean中的方法,容器介入一管理事務(wù)。因有容器管理事務(wù),在enterprise bean中不必對(duì)事務(wù)的邊界進(jìn)行編碼。要求控制分布式事務(wù)的代碼會(huì)非常復(fù)雜。你只需在布置描述文件中聲明enterprise bean的事務(wù)屬性,而不用編寫(xiě)并調(diào)試復(fù)雜的代碼。容器將讀此文件并為你處理此enterprise bean的事務(wù)。
          • JNDI 尋址(JNDI Lookup)服務(wù)向企業(yè)內(nèi)的多重名字和目錄服務(wù)提供了一個(gè)統(tǒng)一的接口,這樣應(yīng)用程序組件可以訪問(wèn)名字和目錄服務(wù).
          • J2EE遠(yuǎn)程連接(Remote Client Connectivity)模型管理客戶端和enterprise bean間的低層交互. 當(dāng)一個(gè)enterprise bean創(chuàng)建后, 一個(gè)客戶端可以調(diào)用它的方法就象它和客戶端位于同一虛擬機(jī)上一樣.
          • 生存周期管理(Life Cycle Management)模型管理enterprise bean的創(chuàng)建和移除,一個(gè)enterprise bean在其生存周期中將會(huì)歷經(jīng)幾種狀態(tài)。容器創(chuàng)建enterprise bean,并在可用實(shí)例池與活動(dòng)狀態(tài)中移動(dòng)他,而最終將其從容器中移除。即使可以調(diào)用enterprise bean的create及remove方法,容器也將會(huì)在后臺(tái)執(zhí)行這些任務(wù)。
          • 數(shù)據(jù)庫(kù)連接池(Database Connection Pooling)模型是一個(gè)有價(jià)值的資源。獲取數(shù)據(jù)庫(kù)連接是一項(xiàng)耗時(shí)的工作,而且連接數(shù)非常有限。容器通過(guò)管理連接池來(lái)緩和這些問(wèn)題。enterprise bean可從池中迅速獲取連接。在bean釋放連接之可為其他bean使用。

          容器類型
          J2EE應(yīng)用組件可以安裝部署到以下幾種容器中去:

          • EJB 容器管理所有J2EE 應(yīng)用程序中企業(yè)級(jí)bean 的執(zhí)行. enterprise bean 和它們的容器運(yùn)行在J2EE 服務(wù)器上.
          • Web 容器管理所有J2EE 應(yīng)用程序中JSP頁(yè)面和Servlet組件的執(zhí)行. Web 組件和它們的容器運(yùn)行在J2EE 服務(wù)器上.
          • 應(yīng)用程序客戶端容器管理所有J2EE應(yīng)用程序中應(yīng)用程序客戶端組件的執(zhí)行. 應(yīng)用程序客戶端和它們的容器運(yùn)行在J2EE 服務(wù)器上.
          • Applet 容器是運(yùn)行在客戶端機(jī)器上的web瀏覽器和 Java 插件的結(jié)合.






          回頁(yè)首


          J2EE的核心API與組件

          J2EE平臺(tái)由一整套服務(wù)(Services)、應(yīng)用程序接口(APIs)和協(xié)議構(gòu)成,它對(duì)開(kāi)發(fā)基于Web的多層應(yīng)用提供了功能支持,下面對(duì)J2EE中的13種技術(shù)規(guī)范進(jìn)行簡(jiǎn)單的描述(限于篇幅,這里只能進(jìn)行簡(jiǎn)單的描述):

          1. JDBC(Java Database Connectivity): JDBC API為訪問(wèn)不同的數(shù)據(jù)庫(kù)提供了一種統(tǒng)一的途徑,象ODBC一樣,JDBC對(duì)開(kāi)發(fā)者屏蔽了一些細(xì)節(jié)問(wèn)題,另外,JDCB對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)也具有平臺(tái)無(wú)關(guān)性。
          2. JNDI(Java Name and Directory Interface): JNDI API被用于執(zhí)行名字和目錄服務(wù)。它提供了一致的模型來(lái)存取和操作企業(yè)級(jí)的資源如DNS和LDAP,本地文件系統(tǒng),或應(yīng)用服務(wù)器中的對(duì)象。
          3. EJB(Enterprise JavaBean): J2EE技術(shù)之所以贏得某體廣泛重視的原因之一就是EJB。它們提供了一個(gè)框架來(lái)開(kāi)發(fā)和實(shí)施分布式商務(wù)邏輯,由此很顯著地簡(jiǎn)化了具有可伸縮性和高度復(fù)雜的企業(yè)級(jí)應(yīng)用的開(kāi)發(fā)。EJB規(guī)范定義了EJB組件在何時(shí)如何與它們的容器進(jìn)行交互作用。容器負(fù)責(zé)提供公用的服務(wù),例如目錄服務(wù)、事務(wù)管理、安全性、資源緩沖池以及容錯(cuò)性。但這里值得注意的是,EJB并不是實(shí)現(xiàn)J2EE的唯一途徑。正是由于J2EE的開(kāi)放性,使得有的廠商能夠以一種和EJB平行的方式來(lái)達(dá)到同樣的目的。
          4. RMI(Remote Method Invoke): 正如其名字所表示的那樣,RMI協(xié)議調(diào)用遠(yuǎn)程對(duì)象上方法。它使用了序列化方式在客戶端和服務(wù)器端傳遞數(shù)據(jù)。RMI是一種被EJB使用的更底層的協(xié)議。
          5. Java IDL/CORBA: 在Java IDL的支持下,開(kāi)發(fā)人員可以將Java和CORBA集成在一起。他們可以創(chuàng)建Java對(duì)象并使之可在CORBA ORB中展開(kāi), 或者他們還可以創(chuàng)建Java類并作為和其它ORB一起展開(kāi)的CORBA對(duì)象的客戶。后一種方法提供了另外一種途徑,通過(guò)它Java可以被用于將你的新的應(yīng)用和舊的系統(tǒng)相集成。
          6. JSP(Java Server Pages): JSP頁(yè)面由HTML代碼和嵌入其中的Java代碼所組成。服務(wù)器在頁(yè)面被客戶端所請(qǐng)求以后對(duì)這些Java代碼進(jìn)行處理,然后將生成的HTML頁(yè)面返回給客戶端的瀏覽器。
          7. Java Servlet: Servlet是一種小型的Java程序,它擴(kuò)展了Web服務(wù)器的功能。作為一種服務(wù)器端的應(yīng)用,當(dāng)被請(qǐng)求時(shí)開(kāi)始執(zhí)行,這和CGI Perl腳本很相似。Servlet提供的功能大多與JSP類似,不過(guò)實(shí)現(xiàn)的方式不同。JSP通常是大多數(shù)HTML代碼中嵌入少量的Java代碼,而servlets全部由Java寫(xiě)成并且生成HTML。
          8. XML(Extensible Markup Language): XML是一種可以用來(lái)定義其它標(biāo)記語(yǔ)言的語(yǔ)言。它被用來(lái)在不同的商務(wù)過(guò)程中共享數(shù)據(jù)。XML的發(fā)展和Java是相互獨(dú)立的,但是,它和Java具有的相同目標(biāo)正是平臺(tái)獨(dú)立性。通過(guò)將Java和XML的組合,您可以得到一個(gè)完美的具有平臺(tái)獨(dú)立性的解決方案。
          9. JMS(Java Message Service): MS是用于和面向消息的中間件相互通信的應(yīng)用程序接口(API)。它既支持點(diǎn)對(duì)點(diǎn)的域,有支持發(fā)布/訂閱(publish/subscribe)類型的域,并且提供對(duì)下列類型的支持:經(jīng)認(rèn)可的消息傳遞,事務(wù)型消息的傳遞,一致性消息和具有持久性的訂閱者支持。JMS還提供了另一種方式來(lái)對(duì)您的應(yīng)用與舊的后臺(tái)系統(tǒng)相集成。
          10. JTA(Java Transaction Architecture): JTA定義了一種標(biāo)準(zhǔn)的API,應(yīng)用系統(tǒng)由此可以訪問(wèn)各種事務(wù)監(jiān)控。
          11. JTS(Java Transaction Service): JTS是CORBA OTS事務(wù)監(jiān)控的基本的實(shí)現(xiàn)。JTS規(guī)定了事務(wù)管理器的實(shí)現(xiàn)方式。該事務(wù)管理器是在高層支持Java Transaction API (JTA)規(guī)范,并且在較底層實(shí)現(xiàn)OMG OTS specification的Java映像。JTS事務(wù)管理器為應(yīng)用服務(wù)器、資源管理器、獨(dú)立的應(yīng)用以及通信資源管理器提供了事務(wù)服務(wù)。
          12. JavaMail: JavaMail是用于存取郵件服務(wù)器的API,它提供了一套郵件服務(wù)器的抽象類。不僅支持SMTP服務(wù)器,也支持IMAP服務(wù)器。
          13. JTA(JavaBeans Activation Framework): JavaMail利用JAF來(lái)處理MIME編碼的郵件附件。MIME的字節(jié)流可以被轉(zhuǎn)換成Java對(duì)象,或者轉(zhuǎn)換自Java對(duì)象。大多數(shù)應(yīng)用都可以不需要直接使用JAF。
          posted @ 2006-12-18 17:35 soufan 閱讀(136) | 評(píng)論 (0)編輯 收藏

          from:http://www.javaeye.com/topic/9706

          數(shù)據(jù)庫(kù)對(duì)象的緩存策略

          前言
          本文探討Jive(曾經(jīng)開(kāi)源的Java論壇)和Hibernate(Java開(kāi)源持久層)的數(shù)據(jù)庫(kù)對(duì)象的緩存策略,并闡述作者本人的Lightor(Java開(kāi)源持久層)采用的數(shù)據(jù)庫(kù)對(duì)象緩存策略。
          本文的探討基于以前開(kāi)源的Jive代碼,Hibernate2.1.7源碼,和作者本人的Lightor代碼。
          本文用ID (Identifier的縮寫(xiě))來(lái)代表數(shù)據(jù)記錄的關(guān)鍵字。
          數(shù)據(jù)對(duì)象查詢一般分為兩種:條件查詢,返回一個(gè)滿足條件的數(shù)據(jù)對(duì)象列表; ID查詢,返回ID對(duì)應(yīng)的數(shù)據(jù)對(duì)象。
          本文主要探討“條件查詢”和“ID查詢”這兩種情況的緩存策略。
          本文只探討一個(gè)JVM內(nèi)的數(shù)據(jù)緩存策略,不涉及分布式緩存;本文只探討對(duì)應(yīng)單表的數(shù)據(jù)對(duì)象的緩存,不涉及關(guān)聯(lián)表對(duì)象的情況。

          一、Jive的緩存策略
          1.Jive的緩存策略的過(guò)程描述:
          (1)條件查詢的時(shí)候,Jive用 select id from table_name where …. (只選擇ID字段)這樣的SQL語(yǔ)句查詢數(shù)據(jù)庫(kù),來(lái)獲得一個(gè)ID列表。
          (2) Jive根據(jù)ID列表中的每個(gè)ID,首先查看緩存中是否存在對(duì)應(yīng)ID的數(shù)據(jù)對(duì)象:如果存在,那么直接取出,加入到 結(jié)果列表中;如果不存在,那么通過(guò)一條select * from table_name where id = {ID value} 這樣的SQL查詢數(shù)據(jù)庫(kù),取出對(duì)應(yīng)的數(shù)據(jù)對(duì)象,放入到結(jié)果列表,并把這個(gè)數(shù)據(jù)對(duì)象按照ID放入到緩存中。
          (3) ID查詢的時(shí)候,Jive執(zhí)行類似第(2)步的過(guò)程,先從緩存中查找該ID,查不到,再查詢數(shù)據(jù)庫(kù),然后把結(jié)果放入到緩存。
          (4) 刪除、更新、增加數(shù)據(jù)的時(shí)候,同時(shí)更新緩存。
          2.Jive緩存策略的優(yōu)點(diǎn):
          (1) ID查詢的時(shí)候,如果該ID已經(jīng)存在于緩存中,那么可以直接取出。節(jié)省了一條數(shù)據(jù)庫(kù)查詢。
          (2) 當(dāng)多次條件查詢的結(jié)果集相交的情況下,交集里面的數(shù)據(jù)對(duì)象不用重復(fù)從數(shù)據(jù)庫(kù)整個(gè)獲取,直接從緩存中獲取即可。
          比如,第一次查詢的ID列表為{1, 2},然后根據(jù)ID列表的ID從數(shù)據(jù)庫(kù)中一個(gè)一個(gè)取出數(shù)據(jù)對(duì)象,結(jié)果集為{a(id = 1), b(id = 2)}。
          下一次查詢的ID列表為{2, 3},由于ID = 2的數(shù)據(jù)對(duì)象已經(jīng)存在于緩存中,那么只要從數(shù)據(jù)庫(kù)中取出ID = 3的數(shù)據(jù)對(duì)象即可。
          3.Jive緩存策略的缺點(diǎn):
          (1) 在根據(jù)條件查找數(shù)據(jù)對(duì)象列表的過(guò)程中,DAO的第(1)步用來(lái)獲得ID列表的那一次數(shù)據(jù)庫(kù)查詢,是必不可少的。
          (2) 如果第(1)步返回的ID列表中有n個(gè)ID,在最壞的命中率(緩存中一個(gè)對(duì)應(yīng)ID都沒(méi)有)情況下,Jive還要再查詢n次數(shù)據(jù)庫(kù)。最壞情況下,共需要n + 1數(shù)據(jù)庫(kù)查詢。

          二、Hibernate的二級(jí)緩存策略
          Hibernate用Session類包裝了數(shù)據(jù)庫(kù)連接從打開(kāi)到關(guān)閉的過(guò)程。
          Session內(nèi)部維護(hù)一個(gè)數(shù)據(jù)對(duì)象集合,包括了本Session內(nèi)選取的、操作的數(shù)據(jù)對(duì)象。這稱為Session內(nèi)部緩存,是Hibernate的第一級(jí)最快緩存,屬于Hibernate的既定行為,不需要進(jìn)行配置(也沒(méi)有辦法配置 :-)。
          Session的生命期很短,存在于Session內(nèi)部的第一級(jí)最快緩存的生命期當(dāng)然也很短,命中率自然也很低。當(dāng)然,這個(gè)Session內(nèi)部緩存的主要作用是保持Session內(nèi)部數(shù)據(jù)狀態(tài)同步。
          如果需要跨Session的命中率較高的全局緩存,那么必須對(duì)Hibernate進(jìn)行二級(jí)緩存配置。一般來(lái)說(shuō),同樣數(shù)據(jù)類型(Class)的數(shù)據(jù)對(duì)象,共用一個(gè)二級(jí)緩存(或其中的同一塊)。
          1.Hibernate二級(jí)緩存策略的過(guò)程描述:
          (1)條件查詢的時(shí)候,總是發(fā)出一條select * from table_name where …. (選擇所有字段)這樣的SQL語(yǔ)句查詢數(shù)據(jù)庫(kù),一次獲得所有的數(shù)據(jù)對(duì)象。
          (2) 把獲得的所有數(shù)據(jù)對(duì)象根據(jù)ID放入到第二級(jí)緩存中。
          (3) 當(dāng)Hibernate根據(jù)ID訪問(wèn)數(shù)據(jù)對(duì)象的時(shí)候,首先從Session一級(jí)緩存中查;查不到,如果配置了二級(jí)緩存,那么從二級(jí)緩存中查;查不到,再查詢數(shù)據(jù)庫(kù),把結(jié)果按照ID放入到緩存。
          (4) 刪除、更新、增加數(shù)據(jù)的時(shí)候,同時(shí)更新緩存。

          2.Hibernate二級(jí)緩存策略的優(yōu)點(diǎn):
          (1) 具有Jive緩存策略同樣的第(1)條優(yōu)點(diǎn):ID查詢的時(shí)候,如果該ID已經(jīng)存在于緩存中,那么可以直接取出。節(jié)省了一條數(shù)據(jù)庫(kù)查詢。
          (2) 不具有Jive緩存策略的第(2)條缺點(diǎn),即hibernate不會(huì)有最壞情況下的 n + 1次數(shù)據(jù)庫(kù)查詢。
          3.Hibernate二級(jí)緩存策略的缺點(diǎn):
          (1) 同Jive緩存策略的第(1)條缺點(diǎn)一樣,條件查詢的時(shí)候,第(1)步的數(shù)據(jù)庫(kù)查詢語(yǔ)句是不可少的。而且Hibernate選擇所有的字段,比只選擇ID字段花費(fèi)的時(shí)間和空間都多。
          (2) 不具備Jive緩存策略的第(2)條優(yōu)點(diǎn)。條件查詢的時(shí)候,必須把數(shù)據(jù)庫(kù)對(duì)象從數(shù)據(jù)庫(kù)中整個(gè)取出,即使該數(shù)據(jù)庫(kù)的ID已經(jīng)存在于緩存中。

          三、Hibernate的Query緩存策略
          可以看到,Jive緩存和Hibernate的二級(jí)緩存策略,都只是針對(duì)于ID查詢的緩存策略,對(duì)于條件查詢則毫無(wú)作用。(盡管Jive緩存的第(2)個(gè)優(yōu)點(diǎn),能夠避免重復(fù)從數(shù)據(jù)庫(kù)獲取同一個(gè)ID對(duì)應(yīng)的數(shù)據(jù)對(duì)象,但select id from …這條數(shù)據(jù)庫(kù)查詢是每次條件查詢都必不可少的)。
          為此,Hibernate提供了針對(duì)條件查詢的Query緩存。
          1.Hibernate的Query緩存策略的過(guò)程描述:
          (1) 條件查詢的請(qǐng)求一般都包括如下信息:SQL, SQL需要的參數(shù),記錄范圍(起始位置rowStart,最大記錄個(gè)數(shù)maxRows),等。
          (2) Hibernate首先根據(jù)這些信息組成一個(gè)Query Key,根據(jù)這個(gè)Query Key到Query緩存中查找對(duì)應(yīng)的結(jié)果列表。如果存在,那么返回這個(gè)結(jié)果列表;如果不存在,查詢數(shù)據(jù)庫(kù),獲取結(jié)果列表,把整個(gè)結(jié)果列表根據(jù)Query Key放入到Query緩存中。
          (3) Query Key中的SQL涉及到一些表名,如果這些表的任何數(shù)據(jù)發(fā)生修改、刪除、增加等操作,這些相關(guān)的Query Key都要從緩存中清空。
          2.Hibernate的Query緩存策略的優(yōu)點(diǎn)
          (1) 條件查詢的時(shí)候,如果Query Key已經(jīng)存在于緩存,那么不需要再查詢數(shù)據(jù)庫(kù)。命中的情況下,一次數(shù)據(jù)庫(kù)查詢也不需要。
          3.Hibernate的Query緩存策略的缺點(diǎn)
          (1) 條件查詢涉及到的表中,如果有任何一條記錄增加、刪除、或改變,那么緩存中所有和該表相關(guān)的Query Key都會(huì)失效。
          比如,有這樣幾組Query Key,它們的SQL里面都包括table1。
          SQL = select * from table1 where c1 = ? …., parameter = 1, rowStart = 11, maxRows = 20.
          SQL = select * from table1 where c1 = ? …., parameter = 1, rowStart = 21, maxRows = 20.
          SQL = select * from table1 where c1 = ? ….., parameter = 2, rowStart = 11, maxRows = 20.
          SQL = select * from table1 where c1 = ? ….., parameter = 2, rowStart = 11, maxRows = 20.
          SQL = select * from table1 where c2 = ? …., parameter = ‘a(chǎn)bc’, rowStart = 11, maxRows = 20.

          當(dāng)table1的任何數(shù)據(jù)對(duì)象(任何字段)改變、增加、刪除的時(shí)候,這些Query Key對(duì)應(yīng)的結(jié)果集都不能保證沒(méi)有發(fā)生變化。
          很難做到根據(jù)數(shù)據(jù)對(duì)象的改動(dòng)精確判斷哪些Query Key對(duì)應(yīng)的結(jié)果集受到影響。最簡(jiǎn)單的實(shí)現(xiàn)方法,就是清空所有SQL包含table1的Query Key。

          (2) Query緩存中,Query Key對(duì)應(yīng)的是數(shù)據(jù)對(duì)象列表,假如不同的Query Key對(duì)應(yīng)的數(shù)據(jù)對(duì)象列表有交集,那么,交集部分的數(shù)據(jù)對(duì)象就是重復(fù)存儲(chǔ)的。
          比如,Query Key 1對(duì)應(yīng)的數(shù)據(jù)對(duì)象列表為{a(id = 1), b(id = 2)},Query Key 2對(duì)應(yīng)的數(shù)據(jù)對(duì)象列表為{a(id = 1), c(id = 3)},這個(gè)a就在兩個(gè)List同時(shí)存在了兩份。

          4.二級(jí)緩存和Query緩存同步的困惑
          假如,Query緩存中,一個(gè)Query Key對(duì)應(yīng)的結(jié)果列表為{a (id = 1) , b (id = 2), c (id = 3)}; 二級(jí)緩存里面有也id = 1對(duì)應(yīng)的數(shù)據(jù)對(duì)象a。
          這兩個(gè)數(shù)據(jù)對(duì)象a之間是什么關(guān)系?能夠保持狀態(tài)同步嗎?
          我閱讀Hibernate的相關(guān)源碼,沒(méi)有發(fā)現(xiàn)兩個(gè)緩存之間的這種同步關(guān)系。
          或者兩者之間毫無(wú)關(guān)系。就像我上面所說(shuō)的,只要表數(shù)據(jù)發(fā)生變化,相關(guān)的Query Key都要被清空。所以不用考慮同步問(wèn)題?

          四、Lightor的緩存策略
          Lightor是我做的Java開(kāi)源持久層框架。Lightor的意思是,Lightweight O/R。Hibernate,JDO,EJB CMP這些持久層框架,都是Layer。Lightor算不上Layer,而只是一個(gè)Helper。這里的O/R意思不是Object/Relational,而是Object/ResultSet的意思。:-)
          Lightor的緩存策略,主要參照Hibernate的緩存思路,Lightor的緩存也分為 Query緩存和ID緩存。但其中有一點(diǎn)不同,兩者之間并不是毫無(wú)聯(lián)系的,而是相互關(guān)聯(lián)的。
          1.Lightor的緩存策略的過(guò)程描述:
          (1) 條件查詢的請(qǐng)求一般都包括如下信息:SQL, 對(duì)應(yīng)SQL的參數(shù),起始記錄位置(rowStart),最大記錄個(gè)數(shù)(maxRows),等。
          (2) Lightor首先根據(jù)這些信息組成一個(gè)Query Key,根據(jù)這個(gè)Query Key到Query緩存中查找對(duì)應(yīng)的結(jié)果ID列表。注意,這里獲取的是ID列表。
          如果結(jié)果ID列表存在于Query緩存,那么根據(jù)這個(gè)ID列表的每個(gè)ID,到ID緩存中取對(duì)應(yīng)的數(shù)據(jù)對(duì)象。如果所有ID對(duì)應(yīng)的數(shù)據(jù)對(duì)象都找到,那個(gè)返回這個(gè)數(shù)據(jù)對(duì)象結(jié)果列表。注意,這里獲取的是整個(gè)數(shù)據(jù)對(duì)象(所有字段)的列表。
          如果結(jié)果ID列表不存在于Query緩存,或者結(jié)果ID列表中的某一個(gè)ID不存在于ID緩存,那么,就查詢數(shù)據(jù)庫(kù),獲取結(jié)果列表。然后,把獲取的每個(gè)數(shù)據(jù)對(duì)象按照ID放入到ID緩存;并組裝成一個(gè)ID列表,按照Query Key存放到Query緩存中。注意,這里是把ID列表,而不是整個(gè)對(duì)象列表,放入到Query緩存中。
          (3) ID查詢的時(shí)候,Lightor先從ID緩存中查找該ID,如果不存在,那么查詢數(shù)據(jù)庫(kù),把結(jié)果放入ID緩存。
          (4) Query Key中的SQL涉及到一些表名,如果這些表的任何數(shù)據(jù)發(fā)生修改、刪除、增加等操作,這些相關(guān)的Query Key都要從緩存中清空。
          2.Lightor的緩存策略的優(yōu)點(diǎn)
          (1) Lightor的ID緩存具有Jive緩存,和Hibernate二級(jí)ID緩存的優(yōu)點(diǎn)。ID查詢的時(shí)候,如果該ID已經(jīng)存在于緩存中,那么可以直接取出。節(jié)省了一條數(shù)據(jù)庫(kù)查詢。
          (2) Lightor的Query緩存具有Hibernate的Query緩存的優(yōu)點(diǎn)。條件查詢的時(shí)候,如果Query Key已經(jīng)存在于緩存,那么不需要再查詢數(shù)據(jù)庫(kù)。命中的情況下,一次數(shù)據(jù)庫(kù)查詢也不需要。
          (3) Lightor的Query緩存中,Query Key對(duì)應(yīng)的是ID列表,而不是數(shù)據(jù)對(duì)象列表,真正的數(shù)據(jù)對(duì)象只存在于ID緩存中。所以,不同的Query Key對(duì)應(yīng)的ID列表如果有交集,ID對(duì)應(yīng)的數(shù)據(jù)對(duì)象也不會(huì)在ID緩存中重復(fù)存儲(chǔ)。
          (4) Lightor的緩存也沒(méi)有Jive緩存的最壞情況n + 1次數(shù)據(jù)庫(kù)查詢?nèi)秉c(diǎn)。
          3.Lightor的緩存策略的缺點(diǎn)
          (1) Lightor的Query緩存具有Hibernate的Query緩存的缺點(diǎn)。條件查詢涉及到的表中,如果有任何一條記錄增加、刪除、或改變,那么緩存中所有和該表相關(guān)的Query Key都會(huì)失效。
          (2) Lightor的ID緩存也具有hibernate的二級(jí)ID緩存具有的缺點(diǎn)。條件查詢的時(shí)候,即使ID已經(jīng)存在于緩存中,也需要重新把數(shù)據(jù)對(duì)象整個(gè)從數(shù)據(jù)庫(kù)取出,放入到緩存中。

          五、Query Key的效率
          Query緩存的Query Key的空間和時(shí)間開(kāi)銷比較大。
          Query Key里面存放的東西不少,SQL, 參數(shù),范圍(起始,個(gè)數(shù))。
          這里面最大的東西就是SQL。又占地方,又花時(shí)間(hashCode, equals)。
          Query Key最關(guān)鍵的兩個(gè)方法是hashCode和equals,重點(diǎn)是SQL的hashCode和equals。

          Lightor的做法是,由于Lightor直接使用SQL,不用HQL、OQL之類,所以推薦盡量使用static final String的SQL,能夠節(jié)省空間和時(shí)間,以至于Query Key的效率能夠相當(dāng)于ID Key的效率。
          至于Hibernate的QueryKey,有興趣的讀者可以去下載閱讀Hibernate的各個(gè)版本的源代碼,跟蹤一下QueryKey的實(shí)現(xiàn)優(yōu)化過(guò)程。

          六、總結(jié)
          這里列一個(gè)表,綜合表示Jive, Hibernate, Lightor的緩存策略的特征。
          N + 1問(wèn)題 重復(fù)ID緩存問(wèn)題 Query緩存支持
          Jive緩存 有 無(wú) 不支持
          Hibernate緩存 無(wú) 有 支持
          Lightor緩存 無(wú) 有 支持

          注:
          “重復(fù)ID緩存問(wèn)題”的含義是,每次條件查詢,不是只取ID列表,而是取出完整對(duì)象(所有字段)的列表。這樣,同一個(gè)ID對(duì)應(yīng)的數(shù)據(jù)對(duì)象,即使在緩存中已經(jīng)存在,也可能被重新放入緩存。參見(jiàn)相關(guān)緩存的缺點(diǎn)描述。
          “重復(fù)ID緩存問(wèn)題”的負(fù)面效應(yīng)到底有多大,就看你的select id from …(只選擇ID)比你的 select * from … (選擇所有字段)快多少。主要影響因素是,字段的個(gè)數(shù),字段值的長(zhǎng)度,與數(shù)據(jù)庫(kù)服務(wù)器之間網(wǎng)絡(luò)傳輸速度。
          不管怎么說(shuō),即使選擇所有字段,也只是一次數(shù)據(jù)庫(kù)查詢。而N + 1問(wèn)題帶來(lái)的可能最壞的負(fù)面效應(yīng)(N + 1次數(shù)據(jù)查詢)卻是非常大的。
          選擇緩存策略的時(shí)候,應(yīng)根據(jù)這些情況發(fā)生的概率和正負(fù)面效應(yīng)進(jìn)行取舍。

          ----- added later

          看到Robbin在04年6月的一篇相關(guān)文章。

          Hibernate Iterator JCS分析
          http://www.hibernate.org.cn/71.html

          Hibernate Iterator JCS分析 寫(xiě)道

          而Hibernate List方式是JDBC的簡(jiǎn)單封裝,一次sql就把所有的數(shù)據(jù)都取出來(lái)了,它不會(huì)像Iterator那樣先取主鍵,然后再取數(shù)據(jù),因此List無(wú)法利用JCS。不過(guò)List也可以把從數(shù)據(jù)庫(kù)中取出的數(shù)據(jù)填充到JCS里面去。

          最佳的方式:第一次訪問(wèn)使用List,快速填充JCS,以后訪問(wèn)采用Iterator,充分利用JCS。

          posted @ 2006-10-11 08:35 soufan 閱讀(208) | 評(píng)論 (0)編輯 收藏

          原文:http://blog.csdn.net/chenlaoshi/archive/2006/09/12/1210564.aspx

          主要就我所了解的J2EE開(kāi)發(fā)的框架或開(kāi)源項(xiàng)目做個(gè)介紹,可以根據(jù)需求選用適當(dāng)?shù)拈_(kāi)源組件進(jìn)行開(kāi)發(fā).主要還是以Spring為核心,也總結(jié)了一些以前web開(kāi)發(fā)常用的開(kāi)源工具和開(kāi)源類庫(kù)
          ?
          1持久層:
          1)Hibernate
          這個(gè)不用介紹了,用的很頻繁,用的比較多的是映射,包括繼承映射和父子表映射
          對(duì) 于DAO在這里介紹個(gè)在它基礎(chǔ)上開(kāi)發(fā)的包bba96,目前最新版本是bba96 2.0它對(duì)Hibernate進(jìn)行了封裝, 查詢功能包括執(zhí)行hsql或者sql查詢/更新的方法,如果你要多層次邏輯的條件查詢可以自己組裝QueryObject.可以參考它做 HibernateDAO.也可以直接利用它
          2) iBATIS
          另一個(gè)ORM工具,Apache的,沒(méi)有Hibernate那么集成,自由度比較大
          2:SpringMVC
          ?????? 原理說(shuō)明和快速入門(mén):
          ?????? 配置文件為:
          Spring的配置文件默認(rèn)為WEB-INF/xxxx-servelet.xm其中xxx為web.xml中org.springframework.web.servlet.DispatcherServlet的servlet-name。
          ?????? Action分發(fā):
          Spring將按照配置文件定義的URL,Mapping到具體Controller類,再根據(jù)URL里的action= xxx或其他參數(shù),利用反射調(diào)用Controller里對(duì)應(yīng)的Action方法。
          輸入數(shù)據(jù)綁定:
          Spring提供Binder 通過(guò)名字的一一對(duì)應(yīng)反射綁定Pojo,也可以直接從request.getParameter()取數(shù)據(jù)。
          輸入數(shù)據(jù)驗(yàn)證
          Sping 提供了Validator接口當(dāng)然還可以使用開(kāi)源的Commons-Validaor支持最好
          Interceptor(攔截器)
          Spring的攔截器提供接口需要自己編寫(xiě),在這點(diǎn)不如WebWork做的好.全面
          ?????? (這里提一下WebWork和Struts的區(qū)別最主要的區(qū)別在于WebWork在建立一個(gè)Action時(shí)是新New一個(gè)對(duì)象而Struts是SingleMoule所有的都繼承它的一個(gè)Action,所以根據(jù)項(xiàng)目需要合適的選擇.)
          3:View層
          1) 標(biāo)簽庫(kù):JSP2.0/JSTL
          由于Webwork或Spring的標(biāo)簽確實(shí)很有限,一般view層用JSTL標(biāo)簽,而且據(jù)說(shuō)JSTL設(shè)計(jì)很好速度是所有標(biāo)簽中最快的使用起來(lái)也很簡(jiǎn)單
          ?
          2) 富客戶端:DOJO Widgets, YUI(YahooUI),FCKEditor, Coolest日歷控件
          Dojo主要提供Tree, Tab等富客戶端控件,可以用其進(jìn)行輔助客戶端開(kāi)發(fā)
          YahooUI和DOJO一樣它有自己的一套javascript調(diào)試控制臺(tái),主要支持ajax開(kāi)發(fā)也有很多Tree,Table,Menu等富客戶端控件
          FCKEditor 最流行的文本編輯器
          Coolest日歷控件 目前很多日歷控件可用,集成在項(xiàng)目中也比較簡(jiǎn)單,這個(gè)只是其中的一個(gè),界面不錯(cuò)的說(shuō)..
          ?
          3) JavaScript:Prototype.js
          Prototype.js 作為javascript的成功的開(kāi)源框架,封裝了很多好用的功能,通過(guò)它很容易編寫(xiě)AJAX應(yīng)用,現(xiàn)在AJAX技術(shù)逐漸成熟,框架資源比較豐富,比如 YUI,DWR等等,也是因?yàn)镴avaScript沒(méi)有合適的調(diào)試工具,所以沒(méi)有必要從零開(kāi)始編寫(xiě)AJAX應(yīng)用,個(gè)人認(rèn)為多用一些成熟的Ajax框架實(shí)現(xiàn) 無(wú)刷新更新頁(yè)面是不錯(cuò)的選擇.
          ?
          4)表格控件:Display Tag ,Extreme Table
          這兩個(gè)的功能差不多,都是View層表格的生成,界面也比較相向,可以導(dǎo)出Excel,Pdf,對(duì)Spring支持很容易.
          相比較而言比較推薦ExtremeTable,它的設(shè)計(jì)很好功能上比DisplayTag多一些,支持Ajax,封裝了一些攔截器,而且最方面的是在主頁(yè)wiki中有詳細(xì)的中文使用文檔.
          ?
          5):OSCache
          OSCache是OpenSymphony組織提供的一個(gè)J2EE架構(gòu)中Web應(yīng)用層的緩存技術(shù)實(shí)現(xiàn)組件,Cache是一種用于提高系統(tǒng)響應(yīng)速度、改善系統(tǒng)運(yùn)行性能的技術(shù)。尤其是在Web應(yīng)用中,通過(guò)緩存頁(yè)面的輸出結(jié)果,可以很顯著的改善系統(tǒng)的穩(wěn)定性和運(yùn)行性能。
          它主要用在處理短時(shí)間或一定時(shí)間內(nèi)一些數(shù)據(jù)或頁(yè)面不會(huì)發(fā)生變化,或?qū)⒁恍┎蛔兊慕y(tǒng)計(jì)報(bào)表,緩沖在內(nèi)存,可以充分的減輕服務(wù)器的壓力,防治負(fù)載平衡,快速重啟服務(wù)器(通過(guò)硬盤(pán)緩存).
          ?
          6)SiteMesh
          sitemesh 應(yīng)用Decorator模式主要用于提高頁(yè)面的可維護(hù)性和復(fù)用性,其原理是用Filter截取request和response,把頁(yè)面組件head, content,banner結(jié)合為一個(gè)完整的視圖。通常我們都是用include標(biāo)簽在每個(gè)jsp頁(yè)面中來(lái)不斷的包含各種header, stylesheet, scripts and footer,現(xiàn)在,在sitemesh的幫助下,我們刪掉他們輕松達(dá)到復(fù)合視圖模式.
          Sitemesh也是 OpenSymphony的一個(gè)項(xiàng)目現(xiàn)在最近的版本是2.2,目前OpenSymphony自從04年就沒(méi)有更新的版本了..感覺(jué)它還是比較有創(chuàng)新的一種頁(yè)面組裝方式, OpenSymphony開(kāi)源組織的代碼一般寫(xiě)的比較漂亮,可以改其源代碼對(duì)自己的項(xiàng)目進(jìn)行適配.
          測(cè)試發(fā)現(xiàn)Sitemesh還存在一些問(wèn)題,比如中文問(wèn)題,它的默認(rèn)編碼是iso-8859-1在使用時(shí)候需要做一些改動(dòng).
          ?
          7)CSS,XHTML
          這個(gè)不用說(shuō)了,遵循W3C標(biāo)準(zhǔn)的web頁(yè)面開(kāi)發(fā).
          ?
          8)分頁(yè)標(biāo)簽: pager-taglib組件
          Pager-taglib?是一套分頁(yè)標(biāo)簽庫(kù),可以靈活地實(shí)現(xiàn)多種不同風(fēng)格的分頁(yè)導(dǎo)航頁(yè)面,并且可以很好的與服務(wù)器分頁(yè)邏輯分離.使用起來(lái)也比較簡(jiǎn)單.
          ?
          9)Form: Jodd Form taglib
          Jodd Form taglib使用比較簡(jiǎn)單,只要把<form>的頭尾以<jodd:form bean= "mybean">包住
          就會(huì)自動(dòng)綁定mybean, 自動(dòng)綁定mybean的所有同名屬性到普通html標(biāo)記input, selectbox, checkbox,radiobox.....在這些input框里不用再寫(xiě)任何代碼…
          ??????
          10)Ajax:DWR
          ?????? J2EE應(yīng)用最常用的ajax框架
          ??????
          ?????? 11)報(bào)表 圖表
          Eclipse BIRT功能比較強(qiáng)大,也很龐大..好幾十M,一般沒(méi)有特別需求或別的圖表設(shè)計(jì)軟件可以解決的不用它
          JasperReports+ iReport是一個(gè)基于Java的開(kāi)源報(bào)表工具,它可以在Java環(huán)境下像其它IDE報(bào)表工具一樣來(lái)制作報(bào)表。JasperReports支持PDF、 HTML、XLS、CSV和XML文件輸出格式。JasperReports是當(dāng)前Java開(kāi)發(fā)者最常用的報(bào)表工具。
          JFreeChart主要是用來(lái)制作各種各樣的圖表,這些圖表包括:餅圖、柱狀圖(普通柱狀圖以及堆棧柱狀圖)、線圖、區(qū)域圖、分布圖、混合圖、甘特圖以及一些儀表盤(pán)等等。
          ??????琴棋報(bào)表,國(guó)產(chǎn)的..重點(diǎn)推薦,適合中國(guó)的情況,開(kāi)放源代碼,使用完全免費(fèi)。純JAVA開(kāi)發(fā),適用多種系統(tǒng)平臺(tái)。特別適合B/S結(jié)構(gòu)的系統(tǒng)。官方網(wǎng)站有其優(yōu)點(diǎn)介紹,看來(lái)用它還是不錯(cuò)的選擇,最重要的是支持國(guó)產(chǎn)呵呵
          ?
          4:權(quán)限控制: Acegi
          Acegi是Spring Framework 下最成熟的安全系統(tǒng),它提供了強(qiáng)大靈活的企業(yè)級(jí)安全服務(wù),如完善的認(rèn)證和授權(quán)機(jī)制,Http資源訪問(wèn)控制,Method 調(diào)用訪問(wèn)控制等等,支持CAS
          (耶魯大學(xué)的單點(diǎn)登陸技術(shù),這個(gè)單點(diǎn)登陸方案比較出名.我也進(jìn)行過(guò)配置使用,可以根據(jù)項(xiàng)目需要,如果用戶分布在不同的地方不同的系統(tǒng)通用一套登陸口令可以用它進(jìn)行解決,一般注冊(cè)機(jī)登陸機(jī)就是這樣解決的)
          ?????? Acegi只是于Spring結(jié)合最好的安全框架,功能比較強(qiáng)大,當(dāng)然還有一些其他的安全框架,這里列舉一些比較流行的是我從網(wǎng)上找到的,使用方法看其官方文檔把…
          JAAS, Seraph, jSai - Servlet Security, Gabriel, JOSSO, Kasai, jPAM, OpenSAML都是些安全控制的框架..真夠多的呵呵
          ?
          5:全文檢索
          ?????? 1) Lucene
          ?????? Lucene是 一套全文索引接口,可以通過(guò)它將數(shù)據(jù)進(jìn)行倒排文件處理加入索引文件,它的索引速度和查詢速度是相當(dāng)快的,查詢百萬(wàn)級(jí)數(shù)據(jù)毫秒級(jí)出結(jié)果,現(xiàn)在最火的 Apache開(kāi)源項(xiàng)目,版本更新速度很快現(xiàn)在已經(jīng)到了2.0,每個(gè)版本更新的都比較大,目前用的最多的版本應(yīng)該是1.4.3,但它有個(gè)不太方面的地方單個(gè) 索引文件有2G文件限制,現(xiàn)在2.0版本沒(méi)有這個(gè)限制,我研究的比較多,它的擴(kuò)展性比較好,可以很方面的擴(kuò)充其分詞接口和查詢接口.
          ?????? 基于它的開(kāi)發(fā)的系統(tǒng)很多,比如最常用的Eclipse的搜索功能,還有一些開(kāi)源的軟件比如Compass,Nutch,Lius,還有我最近做的InSearch(企業(yè)級(jí)FTP文件網(wǎng)頁(yè)搜索)
          6:公共Util類
          ?????? 主要是Jakarta-Commons類庫(kù),其中最常用得是以下幾個(gè)類庫(kù)
          1) Jakarta-Commons-Language
          ?????? 最常用得類是StringUtils類,提供了使用的字符串處理的常用方法效率比較高
          2) Jakarta-Commons-Beantuils
          ?????? 主要用Beantuils能夠獲得反射函數(shù)封裝及對(duì)嵌套屬性,map,array型屬性的讀取。
          3) Jakarta-Commons-Collections
          ?????? 里面有很多Utils方法
          ?
          7 日志管理
          ?????? Log4J
          ?????? 任務(wù)是日志記錄,分為Info,Warn,error幾個(gè)層次可以更好的調(diào)試程序
          ?
          8 開(kāi)源的J2EE框架
          ?????? 1) Appfuse
          ????????????? Appfuse是Matt Raible 開(kāi)發(fā)的一個(gè)指導(dǎo)性的入門(mén)級(jí)J2EE框架, 它對(duì)如何集成流行的Spring、Hibernate、iBatis、Struts、Xdcolet、JUnit等基礎(chǔ)框架給出了示范. 在持久層,AppFuse采用了Hibernate O/R映射工具;在容器方面,它采用了Spring,用戶可以自由選擇Struts、Spring/MVC,Webwork,JSF這幾個(gè)Web框架。
          ??????
          ?????? 2) SpringSide
          ?????? .SpringSide較完整的演示了企業(yè)應(yīng)用的各個(gè)方面,是一個(gè)電子商務(wù)網(wǎng)站的應(yīng)用 SpringSide也大量參考了Appfuse中的優(yōu)秀經(jīng)驗(yàn)。最重要的是它是國(guó)內(nèi)的一個(gè)開(kāi)源項(xiàng)目,可以了解到國(guó)內(nèi)現(xiàn)在的一些實(shí)際技術(shù)動(dòng)態(tài)和方向很有指導(dǎo)意義…
          ?
          9:模版 Template
          主要有Veloctiy和Freemarker
          模板用Servlet提供的數(shù)據(jù)動(dòng)態(tài)地生成 HTML。編譯器速度快,輸出接近靜態(tài)HTML???????????? 頁(yè)面的速度。
          ?
          10:工作流
          ?????? 我所知道比較出名的主要有JBpm Shark Osworkflow,由于對(duì)它沒(méi)有過(guò)多的研究所以還不是很清楚之間有什么區(qū)別.
          ?
          項(xiàng)目管理軟件
          dotProject:是一個(gè)基于LAMP的開(kāi)源項(xiàng)目管理軟件。最出名的項(xiàng)目管理軟件
          JIRA: 項(xiàng)目計(jì)劃,任務(wù)安排,錯(cuò)誤管理
          Bugzilla:提交和管理bug,和eclipse集成,可以通過(guò)安裝MyEclipse配置一下即可使用
          BugFree借鑒微軟公司軟件研發(fā)理念、免費(fèi)開(kāi)放源代碼、基于Web的精簡(jiǎn)版Bug管理
          CVS:這個(gè)就不介紹了都在用.
          SVN: SubVersion已逐漸超越CVS,更適應(yīng)于JavaEE的項(xiàng)目。Apache用了它很久后,Sourceforge剛剛推出SVN的支持。
          測(cè)試用例:主要JUnit單元測(cè)試,編寫(xiě)TestCase,Spring也對(duì)Junit做了很好的支持
          ?
          后記:
          ?????? 以Spring 為主的應(yīng)用開(kāi)發(fā)可選用的組件中間件真是眼花繚亂,所以針對(duì)不同的項(xiàng)目需求可以利用不同的開(kāi)源產(chǎn)品解決,比如用Spring+Hibernate/ iBATIS或Spring+WebWork+Hibernate/ iBATIS或Spring+Struts+Hibernate/ iBATIS,合理的框架設(shè)計(jì)和代碼復(fù)用設(shè)計(jì)對(duì)項(xiàng)目開(kāi)發(fā)效率和程序性能有很大的提高,也有利于后期的維護(hù).
          posted @ 2006-09-28 20:57 soufan 閱讀(104) | 評(píng)論 (0)編輯 收藏

          Hashtable和HashMap的區(qū)別:
          1.Hashtable是Dictionary的子類,HashMap是Map接口的一個(gè)實(shí)現(xiàn)類;
          2.Hashtable中的方法是同步的,而HashMap中的方法在缺省情況下是非同步的。即是說(shuō),在多線程應(yīng)用程序中,不用專門(mén)的操作就安全地可以使用Hashtable了;而對(duì)于HashMap,則需要額外的同步機(jī)制。但HashMap的同步問(wèn)題可通過(guò)Collections的一個(gè)靜態(tài)方法得到解決:
          Map Collections.synchronizedMap(Map m)
          這個(gè)方法返回一個(gè)同步的Map,這個(gè)Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環(huán)境中也是安全的。
          3.在HashMap中,null可以作為鍵,這樣的鍵只有一個(gè);可以有一個(gè)或多個(gè)鍵所對(duì)應(yīng)的值為null。當(dāng)get()方法返回null值時(shí),即可以表示HashMap中沒(méi)有該鍵,也可以表示該鍵所對(duì)應(yīng)的值為null。因此,在HashMap中不能由get()方法來(lái)判斷HashMap中是否存在某個(gè)鍵,而應(yīng)該用containsKey()方法來(lái)判斷。

          Vector、ArrayList和List的異同

          線性表,鏈表,哈希表是常用的數(shù)據(jù)結(jié)構(gòu),在進(jìn)行Java開(kāi)發(fā)時(shí),JDK已經(jīng)為我們提供了一系列相應(yīng)的類來(lái)實(shí)現(xiàn)基本的數(shù)據(jù)結(jié)構(gòu)。這些類均在java.util包中。本文試圖通過(guò)簡(jiǎn)單的描述,向讀者闡述各個(gè)類的作用以及如何正確使用這些類。

          Collection
          ├List
          │├LinkedList
          │├ArrayList
          │└Vector
          │ └Stack
          └Set
          Map
          ├Hashtable
          ├HashMap
          └WeakHashMap

          Collection接口
            Collection是最基本的集合接口,一個(gè)Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
            所有實(shí)現(xiàn)Collection接口的類都必須提供兩個(gè)標(biāo)準(zhǔn)的構(gòu)造函數(shù):無(wú)參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個(gè)空的Collection,有一個(gè)Collection參數(shù)的構(gòu)造函數(shù)用于創(chuàng)建一個(gè)新的Collection,這個(gè)新的Collection與傳入的Collection有相同的元素。后一個(gè)構(gòu)造函數(shù)允許用戶復(fù)制一個(gè)Collection。
            如何遍歷Collection中的每一個(gè)元素?不論Collection的實(shí)際類型如何,它都支持一個(gè)iterator()的方法,該方法返回一個(gè)迭代子,使用該迭代子即可逐一訪問(wèn)Collection中每一個(gè)元素。典型的用法如下:
              Iterator it = collection.iterator(); // 獲得一個(gè)迭代子
              while(it.hasNext()) {
                Object obj = it.next(); // 得到下一個(gè)元素
              }
            由Collection接口派生的兩個(gè)接口是List和Set。

          List接口
            List是有序的Collection,使用此接口能夠精確的控制每個(gè)元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數(shù)組下標(biāo))來(lái)訪問(wèn)List中的元素,這類似于Java的數(shù)組。
          和下面要提到的Set不同,List允許有相同的元素。
            除了具有Collection接口必備的iterator()方法外,List還提供一個(gè)listIterator()方法,返回一個(gè)ListIterator接口,和標(biāo)準(zhǔn)的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設(shè)定元素,還能向前或向后遍歷。
            實(shí)現(xiàn)List接口的常用類有LinkedList,ArrayList,Vector和Stack。

          LinkedList類
            LinkedList實(shí)現(xiàn)了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊(duì)列(queue)或雙向隊(duì)列(deque)。
            注意LinkedList沒(méi)有同步方法。如果多個(gè)線程同時(shí)訪問(wèn)一個(gè)List,則必須自己實(shí)現(xiàn)訪問(wèn)同步。一種解決方法是在創(chuàng)建List時(shí)構(gòu)造一個(gè)同步的List:
              List list = Collections.synchronizedList(new LinkedList(...));

          ArrayList類
            ArrayList實(shí)現(xiàn)了可變大小的數(shù)組。它允許所有元素,包括null。ArrayList沒(méi)有同步。
          size,isEmpty,get,set方法運(yùn)行時(shí)間為常數(shù)。但是add方法開(kāi)銷為分?jǐn)偟某?shù),添加n個(gè)元素需要O(n)的時(shí)間。其他的方法運(yùn)行時(shí)間為線性。
            每個(gè)ArrayList實(shí)例都有一個(gè)容量(Capacity),即用于存儲(chǔ)元素的數(shù)組的大小。這個(gè)容量可隨著不斷添加新元素而自動(dòng)增加,但是增長(zhǎng)算法并沒(méi)有定義。當(dāng)需要插入大量元素時(shí),在插入前可以調(diào)用ensureCapacity方法來(lái)增加ArrayList的容量以提高插入效率。
            和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

          Vector類
            Vector非常類似ArrayList,但是Vector是同步的。由Vector創(chuàng)建的Iterator,雖然和ArrayList創(chuàng)建的Iterator是同一接口,但是,因?yàn)閂ector是同步的,當(dāng)一個(gè)Iterator被創(chuàng)建而且正在被使用,另一個(gè)線程改變了Vector的狀態(tài)(例如,添加或刪除了一些元素),這時(shí)調(diào)用Iterator的方法時(shí)將拋出ConcurrentModificationException,因此必須捕獲該異常。

          Stack 類
            Stack繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的堆棧。Stack提供5個(gè)額外的方法使得Vector得以被當(dāng)作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂?shù)脑兀琫mpty方法測(cè)試堆棧是否為空,search方法檢測(cè)一個(gè)元素在堆棧中的位置。Stack剛創(chuàng)建后是空棧。

          Set接口
            Set是一種不包含重復(fù)的元素的Collection,即任意的兩個(gè)元素e1和e2都有e1.equals(e2)=false,Set最多有一個(gè)null元素。
            很明顯,Set的構(gòu)造函數(shù)有一個(gè)約束條件,傳入的Collection參數(shù)不能包含重復(fù)的元素。
            請(qǐng)注意:必須小心操作可變對(duì)象(Mutable Object)。如果一個(gè)Set中的可變?cè)馗淖兞俗陨頎顟B(tài)導(dǎo)致Object.equals(Object)=true將導(dǎo)致一些問(wèn)題。

          Map接口
            請(qǐng)注意,Map沒(méi)有繼承Collection接口,Map提供key到value的映射。一個(gè)Map中不能包含相同的key,每個(gè)key只能映射一個(gè)value。Map接口提供3種集合的視圖,Map的內(nèi)容可以被當(dāng)作一組key集合,一組value集合,或者一組key-value映射。

          Hashtable類
            Hashtable繼承Map接口,實(shí)現(xiàn)一個(gè)key-value映射的哈希表。任何非空(non-null)的對(duì)象都可作為key或者value。
            添加數(shù)據(jù)使用put(key, value),取出數(shù)據(jù)使用get(key),這兩個(gè)基本操作的時(shí)間開(kāi)銷為常數(shù)。
          Hashtable通過(guò)initial capacity和load factor兩個(gè)參數(shù)調(diào)整性能。通常缺省的load factor 0.75較好地實(shí)現(xiàn)了時(shí)間和空間的均衡。增大load factor可以節(jié)省空間但相應(yīng)的查找時(shí)間將增大,這會(huì)影響像get和put這樣的操作。
          使用Hashtable的簡(jiǎn)單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
              Hashtable numbers = new Hashtable();
              numbers.put(“one”, new Integer(1));
              numbers.put(“two”, new Integer(2));
              numbers.put(“three”, new Integer(3));
            要取出一個(gè)數(shù),比如2,用相應(yīng)的key:
              Integer n = (Integer)numbers.get(“two”);
              System.out.println(“two = ” + n);
            由于作為key的對(duì)象將通過(guò)計(jì)算其散列函數(shù)來(lái)確定與之對(duì)應(yīng)的value的位置,因此任何作為key的對(duì)象都必須實(shí)現(xiàn)hashCode和equals方法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當(dāng)作key的話,要相當(dāng)小心,按照散列函數(shù)的定義,如果兩個(gè)對(duì)象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個(gè)對(duì)象不同,則它們的hashCode不一定不同,如果兩個(gè)不同對(duì)象的hashCode相同,這種現(xiàn)象稱為沖突,沖突會(huì)導(dǎo)致操作哈希表的時(shí)間開(kāi)銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。
            如果相同的對(duì)象有不同的hashCode,對(duì)哈希表的操作會(huì)出現(xiàn)意想不到的結(jié)果(期待的get方法返回null),要避免這種問(wèn)題,只需要牢記一條:要同時(shí)復(fù)寫(xiě)equals方法和hashCode方法,而不要只寫(xiě)其中一個(gè)。
            Hashtable是同步的。

          HashMap類
            HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(shí)(values()方法可返回Collection),其迭代子操作時(shí)間開(kāi)銷和HashMap的容量成比例。因此,如果迭代操作的性能相當(dāng)重要的話,不要將HashMap的初始化容量設(shè)得過(guò)高,或者load factor過(guò)低。

          WeakHashMap類
            WeakHashMap是一種改進(jìn)的HashMap,它對(duì)key實(shí)行“弱引用”,如果一個(gè)key不再被外部所引用,那么該key可以被GC回收。

          總結(jié)
            如果涉及到堆棧,隊(duì)列等操作,應(yīng)該考慮用List,對(duì)于需要快速插入,刪除元素,應(yīng)該使用LinkedList,如果需要快速隨機(jī)訪問(wèn)元素,應(yīng)該使用ArrayList。
            如果程序在單線程環(huán)境中,或者訪問(wèn)僅僅在一個(gè)線程中進(jìn)行,考慮非同步的類,其效率較高,如果多個(gè)線程可能同時(shí)操作一個(gè)類,應(yīng)該使用同步的類。
            要特別注意對(duì)哈希表的操作,作為key的對(duì)象要正確復(fù)寫(xiě)equals和hashCode方法。
            盡量返回接口而非實(shí)際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時(shí),客戶端代碼不用改變。這就是針對(duì)抽象編程。

          posted @ 2006-09-08 17:45 soufan 閱讀(3412) | 評(píng)論 (0)編輯 收藏

               摘要: (轉(zhuǎn)載文章) 1 什么是Java、Java2、JDK?JDK后面的1.3、1.4.2版本號(hào)又是怎么回事?   答:Java是一種通用的,并發(fā)的,強(qiáng)類型的,面向?qū)ο蟮木幊陶Z(yǔ)言(摘自Java規(guī)范第二版) JDK是Sun公司分發(fā)的免費(fèi)Java開(kāi)發(fā)工具,正式名稱為J2SDK(Java2 Software Develop Kit)。 ...  閱讀全文
          posted @ 2006-09-08 17:43 soufan 閱讀(231) | 評(píng)論 (0)編輯 收藏

          摘自:ChinaITLab 作者: 瀏覽率:70

            JSF對(duì)通過(guò)關(guān)聯(lián)組件和事件來(lái)構(gòu)建頁(yè)面而說(shuō)是非常棒的,但是,與所有現(xiàn)有的技術(shù)一樣,它需要一個(gè)控制器來(lái)分離出頁(yè)面間的導(dǎo)航?jīng)Q策,并提供到業(yè)務(wù)層的鏈接。它擁有一個(gè)基本的導(dǎo)航處理程序,可以用功能完備的處理程序來(lái)替換它。Page Flow為創(chuàng)建可重用的封裝頁(yè)面流提供了基礎(chǔ),并可以與視圖層并行工作。它是一個(gè)功能完備的導(dǎo)航處理程序,將JSF頁(yè)面作為最優(yōu)先的處理對(duì)象。本文將討論如何集成這兩種技術(shù)來(lái)利用二者的優(yōu)點(diǎn)。

            構(gòu)建Beehive/JSF應(yīng)用程序

            要構(gòu)建Beehive/JSF應(yīng)用程序,首先要啟動(dòng)Page Flow,然后添加對(duì)JSF的支持。起點(diǎn)是從基本的支持NetUI(Beehive中包含Page Flow的組件)的項(xiàng)目開(kāi)始。根據(jù)指導(dǎo)構(gòu)建基本的支持NetUI的Web應(yīng)用程序。在本文中,我們暫且稱之為“jsf-beehive”,可以在 http://localhost:8080/jsf-beehive 上獲得。

            接下來(lái),安裝并配置JSF。Page Flow可以使用任何與JavaServer Faces 1.1兼容的實(shí)現(xiàn),并針對(duì)兩種主流實(shí)現(xiàn)進(jìn)行了測(cè)試:Apache MyFaces和JSF Reference Implementation。根據(jù)下面的指導(dǎo)在新的Web應(yīng)用程序中安裝JSF:MyFaces v1.0.9及更高版本,JSF Reference Implementation v1.1_01,或者其他實(shí)現(xiàn)。之后,可以使用WEB-INF/faces-config.xml中的一個(gè)簡(jiǎn)單入口啟動(dòng)Page Flow集成,入口在<application>標(biāo)簽之下,<navigation-rule>標(biāo)簽之上:

          																		<factory>
           <application-factory>
            org.apache.beehive.netui.pageflow.faces.PageFlowApplicationFactory
           </application-factory>
          </factory>
          																

            添加了這些就為頁(yè)面流提供了一個(gè)機(jī)會(huì),使其可以提供自己的JSF框架對(duì)象版本來(lái)定制其行為。通常來(lái)說(shuō),只有在使用頁(yè)面流功能的時(shí)候,JSF行為才會(huì)被修改;JSF的基本行為不會(huì)改變。

            基本集成

            JSF中頁(yè)面流的最基本用處是引發(fā)(調(diào)用)來(lái)自JSF頁(yè)面的動(dòng)作。JSF頁(yè)面可以處理頁(yè)面內(nèi)事件,而頁(yè)面流動(dòng)作則是從一個(gè)頁(yè)面導(dǎo)航到另一頁(yè)面的方法。首先,在Web應(yīng)用程序中創(chuàng)建一個(gè)名為“example”的目錄,在其中創(chuàng)建一個(gè)頁(yè)面流控制器類:

          																		package example;
          
          import org.apache.beehive.netui.pageflow.Forward;
          import org.apache.beehive.netui.pageflow.PageFlowController;
          import org.apache.beehive.netui.pageflow.annotations.Jpf;
          
          @Jpf.Controller(
            simpleActions={
              @Jpf.SimpleAction(name="begin", path="page1.faces")
            }
          )
          public class ExampleController extends PageFlowController
          {
            @Jpf.Action(
              forwards={
                @Jpf.Forward(name="success", path="page2.faces")
              }
            )
            public Forward goPage2()
            {
              Forward fwd = new Forward("success");
              return fwd;
            }
          }
          
          																

            在這個(gè)頁(yè)面流中有兩個(gè)動(dòng)作:跳轉(zhuǎn)到page1.faces的begin動(dòng)作和跳轉(zhuǎn)到page2.faces的goPage2動(dòng)作。將goPage2作為一個(gè)方法動(dòng)作(而不是簡(jiǎn)單動(dòng)作)的原因是稍后將會(huì)對(duì)其進(jìn)行擴(kuò)充。

            在構(gòu)造頁(yè)面的時(shí)候,應(yīng)當(dāng)以.jsp為擴(kuò)展名創(chuàng)建page1和page2;JSF servlet處理每個(gè).faces請(qǐng)求,并最終跳轉(zhuǎn)到相關(guān)的JSP。所以,跳轉(zhuǎn)到page1.faces最終將顯示page1.jsp,如下:

          																		<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
          <%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
          ?
          <html>
           <body>
             <f:view>
               <h:form>
                 <h:panelGrid>
                   <h:outputText value="Page 1 of page flow #{pageFlow.URI}"/>
                   <h:commandLink action="goPage2" value="Go to page 2"/>
                 </h:panelGrid>
               </h:form>
             </f:view>
           </body>
          </html>
          																

            從JSF頁(yè)面引發(fā)一個(gè)動(dòng)作很簡(jiǎn)單:使用命令組件的action屬性中的動(dòng)作名字就可以了。在上面的例子中,commandLink指向goPage2動(dòng)作。使用頁(yè)面流集成,這意味著goPage2動(dòng)作會(huì)在example.ExampleController中運(yùn)行。

            就是這樣。要試驗(yàn)的話,構(gòu)建應(yīng)用程序,點(diǎn)擊 http://localhost:8080/jsf-beehive/example/ExampleController.jpf ,這將通過(guò)begin動(dòng)作跳轉(zhuǎn)到page1.faces。單擊鏈接“Go to page 2”,會(huì)引發(fā)goPage2動(dòng)作并跳轉(zhuǎn)到page2.faces。

            后臺(tái)Bean

            Page Flow框架可以管理與JSF頁(yè)面相關(guān)的后臺(tái)bean(backing bean)。該類是放置與頁(yè)面相關(guān)的事件處理程序和狀態(tài)的方便場(chǎng)所。可以把它看作是集中放置與頁(yè)面交互時(shí)所運(yùn)行的所有代碼的單一場(chǎng)所。當(dāng)點(diǎn)擊一個(gè)JSF頁(yè)面時(shí),Page Flow會(huì)判斷是否有具有同樣名稱和包的類,例如,page /example/page1.faces的example.page1類。如果存在這樣的類,并且它用@Jpf.FacesBacking進(jìn)行注釋并擴(kuò)展了FacesBackingBean,它就會(huì)創(chuàng)建該類的一個(gè)實(shí)例。當(dāng)離開(kāi)JSF頁(yè)面而轉(zhuǎn)到一個(gè)動(dòng)作或者其它任何頁(yè)面時(shí),后臺(tái)bean會(huì)被銷毀。后臺(tái)bean與JSF頁(yè)面共存亡。

            綁定到后臺(tái)bean中的屬性

            下面是page1.faces的一個(gè)非常簡(jiǎn)單的后臺(tái)bean,以及屬性someProperty。文件名是page1.java:

          																		package example;
          
          import org.apache.beehive.netui.pageflow.FacesBackingBean;
          import org.apache.beehive.netui.pageflow.annotations.Jpf;
          
          @Jpf.FacesBacking
          public class page1 extends FacesBackingBean
          {
            private String _someProperty = "This is a property value from" 
                                           + getClass().getName() + ".";
          
            public String getSomeProperty()
            {
                return _someProperty;
            }
          
            public void setSomeProperty(String someProperty)
            {
                _someProperty = someProperty;
            }
          }
          
          																

            在JSF頁(yè)面(page1.jsp)中,可以利用backing綁定上下文來(lái)綁定到這個(gè)屬性:

            <h:outputText value="#{backing.someProperty}"/>

            上面的例子顯示了someProperty(最終在后臺(tái)bean上調(diào)用getSomeProperty())的值。類似地,設(shè)置這個(gè)值:

            <h:inputText value="#{backing.someProperty}"/>

            注意,在這個(gè)例子中,后臺(tái)bean中沒(méi)有出現(xiàn)事件處理程序或組件引用。這就縮短了代碼;后臺(tái)bean是放置頁(yè)面所有的處理程序和組件引用的好地方。

            從后臺(tái)bean引發(fā)頁(yè)面流動(dòng)作

            在上面的“基本集成”部分,我們直接從JSF組件引發(fā)頁(yè)面流動(dòng)作。通常情況下,只需這樣即可;當(dāng)單擊一個(gè)按鈕或者鏈接時(shí),會(huì)運(yùn)行一個(gè)動(dòng)作并跳轉(zhuǎn)到另一個(gè)頁(yè)面上。如果想在調(diào)用控制器之前運(yùn)行一些與頁(yè)面相關(guān)的代碼,或者如果希望頁(yè)面可以在幾個(gè)動(dòng)作之間進(jìn)行動(dòng)態(tài)選擇的話,可以在命令處理程序(JSF頁(yè)面所運(yùn)行的一個(gè)Java方法)中引發(fā)一個(gè)動(dòng)作。下面是一個(gè)命令處理程序的例子,可以把它放到后臺(tái)bean page2.java中(或者其它任何可公開(kāi)訪問(wèn)的bean中):

          																		public String
          chooseNextPage()
          {
            return "goPage3";
          }
          																

            這是一個(gè)非常簡(jiǎn)單的命令處理程序,它選擇了goPage3動(dòng)作。可以用標(biāo)準(zhǔn)的JSF方式從一個(gè)JSF命令組件綁定到這個(gè)命令處理程序:

          																		<h:commandButton action="#{backing.chooseNextPage}" 
                           value="Submit"/>
          																

            當(dāng)單擊鏈接時(shí),會(huì)運(yùn)行chooseNextPage命令處理程序,它會(huì)選擇引發(fā)goPage3動(dòng)作。還可以對(duì)命令處理程序方法使用一個(gè)特殊的頁(yè)面流注釋——@Jpf.CommandHandler:

          																		@Jpf.CommandHandler(
           raiseActions={
                @Jpf.RaiseAction(action="goPage3")
           }
          )
          public String chooseNextPage()
          {
           return "goPage3";
          }
          																

            該注釋使支持Beehive的工具可以知道命令處理程序引發(fā)了后臺(tái)bean中的哪個(gè)動(dòng)作,并允許擴(kuò)展JSF動(dòng)作處理的能力(參見(jiàn)下面“從JSF頁(yè)面向頁(yè)面流發(fā)送數(shù)據(jù)”部分)。

            從后臺(tái)bean訪問(wèn)當(dāng)前頁(yè)面流或共享流

            在某些情況下,您或許想直接從后臺(tái)bean訪問(wèn)當(dāng)前頁(yè)面流或一個(gè)活動(dòng)的共享流。為此,只需創(chuàng)建一個(gè)適當(dāng)類型的字段,并使用@Jpf.PageFlowField或@Jpf.SharedFlowField對(duì)其進(jìn)行適當(dāng)注釋:

          																		@Jpf.CommandHandler(
           raiseActions={
                @Jpf.RaiseAction(action="goPage3")
           }
          )
          public String chooseNextPage()
          {
           return "goPage3";
          }
          
          																

            這些字段將在創(chuàng)建后臺(tái)bean的時(shí)候被初始化。無(wú)需手動(dòng)對(duì)其進(jìn)行初始化。下面的例子使用了自動(dòng)初始化的ExampleController字段。在這個(gè)例子中,“show hints”單選鈕的事件處理程序在頁(yè)面流中設(shè)置了一個(gè)普通優(yōu)先級(jí)。

          																		@Jpf.PageFlowField
          private ExampleController myController;
          
          @Jpf.SharedFlowField(name="sharedFlow2") // "sharedFlow2" is a 
                                        // name defined in the
                                        // page flow controller
          private ExampleSharedFlow mySharedFlow;
          
          
          																

            在很多情況下,頁(yè)面不需要直接與頁(yè)面流或者共享流進(jìn)行交互;使用其它方法從頁(yè)面流向JSF頁(yè)面?zhèn)鬟f數(shù)據(jù)就足夠了,反之亦然。下面我將給出一些例子。

            從頁(yè)面流控制器訪問(wèn)后臺(tái)bean

            您不能從頁(yè)面流控制器訪問(wèn)后臺(tái)bean!至少,這不容易做到,這是有意為之的。后臺(tái)bean與JSF頁(yè)面緊密相關(guān),當(dāng)您離開(kāi)頁(yè)面的時(shí)候,后臺(tái)bean會(huì)被銷毀。正如頁(yè)面流控制器不應(yīng)了解頁(yè)面細(xì)節(jié)一樣,它也不應(yīng)了解后臺(tái)bean。當(dāng)然了,可以從后臺(tái)bean向控制器傳遞數(shù)據(jù)(稍后將會(huì)介紹),甚至可以傳遞后臺(tái)bean實(shí)例本身,但是在大多數(shù)情況下,后臺(tái)bean的內(nèi)容是不應(yīng)當(dāng)泄露給控制器的。

            生命周期方法

            通常,當(dāng)后臺(tái)bean發(fā)生某些事情的時(shí)候,比如當(dāng)它被創(chuàng)建或銷毀時(shí),我們希望能運(yùn)行代碼。在Page Flow框架的生命周期中,它會(huì)對(duì)后臺(tái)bean調(diào)用一些方法:

          • onCreate():創(chuàng)建bean時(shí)
          • onDestroy():銷毀bean時(shí)(從用戶會(huì)話移除)
          • onRestore():這個(gè)需要詳細(xì)解釋一下。我說(shuō)過(guò),當(dāng)您離開(kāi)頁(yè)面的時(shí)候,后臺(tái)bean會(huì)被銷毀。在大多數(shù)情況下是這樣的,但是如果頁(yè)面流使用了navigateTo特性(它使您可以再次訪問(wèn)先前顯示的頁(yè)面),在您離開(kāi)頁(yè)面之后,Page Flow框架會(huì)保留后臺(tái)bean一小段時(shí)間,以防它需要還原。當(dāng)通過(guò)@Jpf.Forward或@Jpf.SimpleAction使用navigateTo=Jpf.NavigateTo.currentPage或navigateTo=Jpf.NavigateTo.previousPage還原一個(gè)JSF頁(yè)面時(shí),頁(yè)面的組件樹(shù)及其后臺(tái)bean都被Page Flow框架還原。當(dāng)這種情況發(fā)生時(shí),onRestore()就被調(diào)用。

            不管要在哪個(gè)時(shí)期運(yùn)行代碼,只需重寫(xiě)適當(dāng)?shù)姆椒ǎ?/font>

          																		protected void onCreate()
          {
           /*some create-time logic */
          }
          																

            當(dāng)重寫(xiě)這些方法時(shí),不需要調(diào)用空的super版本。

            在JSF頁(yè)面和頁(yè)面流之間傳遞數(shù)據(jù)

            現(xiàn)在我們?cè)摽纯慈绾卧贘SF頁(yè)面和頁(yè)面流之間傳遞數(shù)據(jù)了。

            從頁(yè)面流向JSF頁(yè)面發(fā)送數(shù)據(jù)

            通常,您會(huì)想要利用頁(yè)面流的數(shù)據(jù)來(lái)初始化一個(gè)頁(yè)面。為此,可以向page2.faces的Forward添加“action outputs”:

          																		@Jpf.Action(
           forwards={
            @Jpf.Forward(
              name="success", path="page2.faces",
              actionOutputs={
                @Jpf.ActionOutput(name="message", type=String.class,required=true)
              }
            )
           }
          )
          
          public Forward goPage2()
          {
            Forward fwd = new
            Forward("success");
             fwd.addActionOutput("message", "Got the message.");
            return fwd;
          }
          
          																

            做完這些之后,可以直接從JSF頁(yè)面或者后臺(tái)bean將該值作為頁(yè)面輸入來(lái)訪問(wèn)。(如果您不喜歡鍵入冗長(zhǎng)的注釋,可以省去斜體的。它們主要用于再次檢查添加的對(duì)象類型是否正確,確定不缺失類型。)

            可以在頁(yè)面中利用JSF表示語(yǔ)言中的頁(yè)面流pageInput綁定上下文綁定到這個(gè)值:

          																		<h:outputText value="#{pageInput.message}"/>
          																

            注意,可以利用pageFlow和sharedFlow綁定上下文綁定到頁(yè)面流控制器自身或者任何可用的共享流的屬性:

          																		<h:outputText value="#{pageFlow.someProperty}"/>
          <h:outputText value="#{sharedFlow.mySharedFlow.someProperty}"/>
          																

            最后,要想從后臺(tái)bean訪問(wèn)頁(yè)面輸入,只需在bean類代碼中的任意地方調(diào)用getPageInput:

          																		String message = (String) getPageInput("message");
          																

            從JSF頁(yè)面向頁(yè)面流發(fā)送數(shù)據(jù)

            還可以隨著頁(yè)面流所引發(fā)的動(dòng)作發(fā)送數(shù)據(jù)。很多動(dòng)作將要求表單bean作為輸入;通常,表單bean用于從頁(yè)面獲取數(shù)據(jù)送到控制器。首先,讓我們構(gòu)建一個(gè)動(dòng)作來(lái)接收表單bean并跳轉(zhuǎn)到頁(yè)面:

          																		@Jpf.Action(
             forwards={
                 @Jpf.Forward(name="success", path="page3.faces")
             }
          )
          public Forward goPage3(NameBean nameBean)
          {
              _userName = nameBean.getFirstName() + ' ' + 
                          nameBean.getLastName();
              return new Forward("success");
          }
          
          																

            該動(dòng)作包含一個(gè)NameBean,它是一個(gè)將getters/setters作為其firstName和lastName屬性的表單bean類。它設(shè)置一個(gè)成員變量保存完整名字,之后跳轉(zhuǎn)到page3.faces。我們知道,可以直接從JSF頁(yè)面或者它的后臺(tái)bean引發(fā)一個(gè)動(dòng)作。在這兩種情況下,都可以向動(dòng)作發(fā)送表單bean。下面讓我們依次看看每種情況。

            從后臺(tái)bean發(fā)送表單bean

            要從后臺(tái)bean中的命令處理程序發(fā)送表單bean,需要使用一個(gè)特定的注釋。下面給出了page2.java中的情況:

          																		private ExampleController.NameBean _nameBean;
          
          protected void onCreate()
          {
              _nameBean = new ExampleController.NameBean();
          }
          
          public ExampleController.NameBean getName()
          {
              return _nameBean;
          }
          
          @Jpf.CommandHandler(
              raiseActions={
                  @Jpf.RaiseAction(action="goPage3", 
                       outputFormBean="_nameBean")
              }
          )
          public String chooseNextPage()
          {
              return "goPage3";
          }
          
          																

            在這個(gè)例子中,JSF頁(yè)面可以用它選擇的任何方式填充_nameBean的值(例如,通過(guò)將h:inputText值綁定到#{backing.name.firstName}和#{backing.name.lastName})。之后它使用@Jpf.RaiseAction上的outputFormBean屬性來(lái)標(biāo)記_nameBean應(yīng)當(dāng)被傳遞到動(dòng)作goPage3。

            從JSF頁(yè)面發(fā)送表單bean

            從JSF頁(yè)面直接發(fā)送表單bean很容易,只要您可以通過(guò)數(shù)據(jù)綁定表達(dá)式得到bean值。這是通過(guò)在commandButton組件內(nèi)部添加名為submitFormBean的h:attribute組件來(lái)實(shí)現(xiàn)的:

          																		<h:commandButton action="#{backing.chooseNextPage}" 
                           value="Submit directly from page">
              <f:attribute name="submitFormBean" value="backing.name" />
          </h:commandButton>
          																

            在這里,為了使表單bean發(fā)送到動(dòng)作goPage3,按鈕綁定到后臺(tái)bean的“name”屬性(getName)。

            結(jié)束語(yǔ)

            本文展示了如何將JSF在構(gòu)建頁(yè)面方面的豐富特性與Beehive Page Flow在控制頁(yè)面間導(dǎo)航方面的強(qiáng)大功能相結(jié)合。二者的集成非常容易,但是卻會(huì)對(duì)應(yīng)用造成深遠(yuǎn)的影響:它將JSF頁(yè)面與應(yīng)用級(jí)邏輯相分離,并把頁(yè)面帶入Page Flow所提供的功能領(lǐng)域中。JSF頁(yè)面得到了清楚的任務(wù):作為單個(gè)(如果有足夠能力的話)視圖元素參與到應(yīng)用程序的流中。文中沒(méi)有展示JSF頁(yè)面中具有事件處理功能且控制器中具有復(fù)雜的導(dǎo)航邏輯的完備應(yīng)用程序。但是隨著應(yīng)用程序的復(fù)雜程度提高,它就會(huì)更加需要責(zé)任的劃分以及頁(yè)面流添加給JSF的高級(jí)流功能。您可以花幾分鐘嘗試一下——很快您就將意識(shí)到這樣做所帶來(lái)的好處。

          posted @ 2006-09-03 02:40 soufan 閱讀(208) | 評(píng)論 (0)編輯 收藏


          [原創(chuàng)文章,轉(zhuǎn)載請(qǐng)保留或注明出處:http://www.regexlab.com/zh/regref.htm]

          引言

          ??? 正則表達(dá)式(regular expression)描述了一種字符串匹配的模式,可以用來(lái):(1)檢查一個(gè)串中是否含有符合某個(gè)規(guī)則的子串,并且可以得到這個(gè)子串;(2)根據(jù)匹配規(guī)則對(duì)字符串進(jìn)行靈活的替換操作。

          ??? 正則表達(dá)式學(xué)習(xí)起來(lái)其實(shí)是很簡(jiǎn)單的,不多的幾個(gè)較為抽象的概念也很容易理解。之所以很多人感覺(jué)正則表達(dá)式比較復(fù)雜,一方面是因?yàn)榇蠖鄶?shù)的文檔沒(méi)有做到由淺 入深地講解,概念上沒(méi)有注意先后順序,給讀者的理解帶來(lái)困難;另一方面,各種引擎自帶的文檔一般都要介紹它特有的功能,然而這部分特有的功能并不是我們首 先要理解的。

          ??? 文章中的每一個(gè)舉例,都可以點(diǎn)擊進(jìn)入到測(cè)試頁(yè)面進(jìn)行測(cè)試。閑話少說(shuō),開(kāi)始。


          1. 正則表達(dá)式規(guī)則
          1.1 普通字符

          ??? 字母、數(shù)字、漢字、下劃線、以及后邊章節(jié)中沒(méi)有特殊定義的標(biāo)點(diǎn)符號(hào),都是"普通字符"。表達(dá)式中的普通字符,在匹配一個(gè)字符串的時(shí)候,匹配與之相同的一個(gè)字符。

          ??? ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"c";匹配到的位置是:開(kāi)始于2,結(jié)束于3。(注:下標(biāo)從0開(kāi)始還是從1開(kāi)始,因當(dāng)前編程語(yǔ)言的不同而可能不同)

          ???
          ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"bcd";匹配到的位置是:開(kāi)始于1,結(jié)束于4。


          1.2 簡(jiǎn)單的轉(zhuǎn)義字符

          ??? 一些不便書(shū)寫(xiě)的字符,采用在前面加 "\" 的方法。這些字符其實(shí)我們都已經(jīng)熟知了。

          表達(dá)式

          可匹配

          \r, \n

          代表回車和換行符

          \t

          制表符

          \\

          代表 "\" 本身

          ??? 還有其他一些在后邊章節(jié)中有特殊用處的標(biāo)點(diǎn)符號(hào),在前面加 "\" 后,就代表該符號(hào)本身。比如:^, $ 都有特殊意義,如果要想匹配字符串中 "^" 和 "$" 字符,則表達(dá)式就需要寫(xiě)成 "\^" 和 "\$"。

          表達(dá)式

          可匹配

          \^

          匹配 ^ 符號(hào)本身

          \$

          匹配 $ 符號(hào)本身

          \.

          匹配小數(shù)點(diǎn)(.)本身

          ??? 這些轉(zhuǎn)義字符的匹配方法與 "普通字符" 是類似的。也是匹配與之相同的一個(gè)字符。

          ??? ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"$d";匹配到的位置是:開(kāi)始于3,結(jié)束于5。


          1.3 能夠與 '多種字符' 匹配的表達(dá)式

          ??? 正則表達(dá)式中的一些表示方法,可以匹配 '多種字符' 其中的任意一個(gè)字符。比如,表達(dá)式 "\d" 可以匹配任意一個(gè)數(shù)字。雖然可以匹配其中任意字符,但是只能是一個(gè),不是多個(gè)。這就好比玩撲克牌時(shí)候,大小王可以代替任意一張牌,但是只能代替一張牌。

          表達(dá)式

          可匹配

          \d

          任意一個(gè)數(shù)字,0~9 中的任意一個(gè)

          \w

          任意一個(gè)字母或數(shù)字或下劃線,也就是 A~Z,a~z,0~9,_ 中任意一個(gè)

          \s

          包括空格、制表符、換頁(yè)符等空白字符的其中任意一個(gè)

          .

          小數(shù)點(diǎn)可以匹配除了換行符(\n)以外的任意一個(gè)字符

          ??? ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"12";匹配到的位置是:開(kāi)始于3,結(jié)束于5。

          ???
          ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"aa1";匹配到的位置是:開(kāi)始于1,結(jié)束于4。


          1.4 自定義能夠匹配 '多種字符' 的表達(dá)式

          ??? 使用方括號(hào) [ ] 包含一系列字符,能夠匹配其中任意一個(gè)字符。用 [^ ] 包含一系列字符,則能夠匹配其中字符之外的任意一個(gè)字符。同樣的道理,雖然可以匹配其中任意一個(gè),但是只能是一個(gè),不是多個(gè)。

          表達(dá)式

          可匹配

          [ab5@]

          匹配 "a" 或 "b" 或 "5" 或 "@"

          [^abc]

          匹配 "a","b","c" 之外的任意一個(gè)字符

          [f-k]

          匹配 "f"~"k" 之間的任意一個(gè)字母

          [^A-F0-3]

          匹配 "A"~"F","0"~"3" 之外的任意一個(gè)字符

          ??? ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"bc";匹配到的位置是:開(kāi)始于1,結(jié)束于3。

          ???
          ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"1";匹配到的位置是:開(kāi)始于3,結(jié)束于4。


          1.5 修飾匹配次數(shù)的特殊符號(hào)

          ??? 前面章節(jié)中講到的表達(dá)式,無(wú)論是只能匹配一種字符的表達(dá)式,還是可以匹配多種字符其中任意一個(gè)的表達(dá)式,都只能匹配一次。如果使用表達(dá)式再加上修飾匹配次數(shù)的特殊符號(hào),那么不用重復(fù)書(shū)寫(xiě)表達(dá)式就可以重復(fù)匹配。

          ??? 使用方法是:"次數(shù)修飾"放在"被修飾的表達(dá)式"后邊。比如:"[bcd][bcd]" 可以寫(xiě)成 "[bcd]{2}"。

          表達(dá)式

          作用

          {n}

          表達(dá)式重復(fù)n次,比如:

          {m,n}

          表達(dá)式至少重復(fù)m次,最多重復(fù)n次,比如:

          {m,}

          表達(dá)式至少重復(fù)m次,比如:

          ?

          匹配表達(dá)式0次或者1次,相當(dāng)于 {0,1},比如:

          +

          表達(dá)式至少出現(xiàn)1次,相當(dāng)于 {1,},比如:

          *

          表達(dá)式不出現(xiàn)或出現(xiàn)任意次,相當(dāng)于 {0,},比如:

          ??? ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"12.5";匹配到的位置是:開(kāi)始于10,結(jié)束于14。

          ???
          ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"goooooogle";匹配到的位置是:開(kāi)始于7,結(jié)束于17。


          1.6 其他一些代表抽象意義的特殊符號(hào)

          ??? 一些符號(hào)在表達(dá)式中代表抽象的特殊意義:

          表達(dá)式

          作用

          ^

          與字符串開(kāi)始的地方匹配,不匹配任何字符

          $

          與字符串結(jié)束的地方匹配,不匹配任何字符

          \b

          匹配一個(gè)單詞邊界,也就是單詞和空格之間的位置,不匹配任何字符

          ??? 進(jìn)一步的文字說(shuō)明仍然比較抽象,因此,舉例幫助大家理解。

          ??? ,匹配結(jié)果是:失敗。因?yàn)?"^" 要求與字符串開(kāi)始的地方匹配,因此,只有當(dāng) "aaa" 位于字符串的開(kāi)頭的時(shí)候,"^aaa" 才能匹配,

          ???
          舉例2:表達(dá)式 "aaa$" 在匹配 "xxx aaa xxx" 時(shí),匹配結(jié)果是:失敗。因?yàn)?"$" 要求與字符串結(jié)束的地方匹配,因此,只有當(dāng) "aaa" 位于字符串的結(jié)尾的時(shí)候,"aaa$" 才能匹配,

          ???
          ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"@a";匹配到的位置是:開(kāi)始于2,結(jié)束于4。
          ??? 進(jìn)一步說(shuō)明:"\b" 與 "^" 和 "$" 類似,本身不匹配任何字符,但是它要求它在匹配結(jié)果中所處位置的左右兩邊,其中一邊是 "\w" 范圍,另一邊是 非"\w" 的范圍。

          ???
          ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"end";匹配到的位置是:開(kāi)始于15,結(jié)束于18。

          ??? 一些符號(hào)可以影響表達(dá)式內(nèi)部的子表達(dá)式之間的關(guān)系:

          表達(dá)式

          作用

          |

          左右兩邊表達(dá)式之間 "或" 關(guān)系,匹配左邊或者右邊

          ( )

          (1). 在被修飾匹配次數(shù)的時(shí)候,括號(hào)中的表達(dá)式可以作為整體被修飾
          (2). 取匹配結(jié)果的時(shí)候,括號(hào)中的表達(dá)式匹配到的內(nèi)容可以被單獨(dú)得到

          ??? ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:"Tom";匹配到的位置是:開(kāi)始于4,結(jié)束于7。匹配下一個(gè)時(shí),匹配結(jié)果是:成功;匹配到的內(nèi)容是:"Jack";匹配到的位置時(shí):開(kāi)始于15,結(jié)束于19。

          ???
          ,匹配結(jié)果是:成功;匹配到內(nèi)容是:"go go go";匹配到的位置是:開(kāi)始于6,結(jié)束于14。

          ???
          ,匹配的結(jié)果是:成功;匹配到的內(nèi)容是:"¥20.5";匹配到的位置是:開(kāi)始于6,結(jié)束于10。單獨(dú)獲取括號(hào)范圍匹配到的內(nèi)容是:"20.5"。


          2. 正則表達(dá)式中的一些高級(jí)規(guī)則
          2.1 匹配次數(shù)中的貪婪與非貪婪

          ??? 在使用修飾匹配次數(shù)的特殊符號(hào)時(shí),有幾種表示方法可以使同一個(gè)表達(dá)式能夠匹配不同的次數(shù),比如:"{m,n}", "{m,}", "?", "*", "+",具體匹配的次數(shù)隨被匹配的字符串而定。這種重復(fù)匹配不定次數(shù)的表達(dá)式在匹配過(guò)程中,總是盡可能多的匹配。比如,針對(duì)文本 "dxxxdxxxd",舉例如下:

          表達(dá)式

          匹配結(jié)果

          (d)(\w+)

          "\w+" 將匹配第一個(gè) "d" 之后的所有字符 "xxxdxxxd"

          (d)(\w+)(d)

          "\w+" 將匹配第一個(gè) "d" 和最后一個(gè) "d" 之間的所有字符 "xxxdxxx"。雖然 "\w+" 也能夠匹配上最后一個(gè) "d",但是為了使整個(gè)表達(dá)式匹配成功,"\w+" 可以 "讓出" 它本來(lái)能夠匹配的最后一個(gè) "d"

          ??? 由此可見(jiàn),"\w+" 在匹配的時(shí)候,總是盡可能多的匹配符合它規(guī)則的字符。雖然第二個(gè)舉例中,它沒(méi)有匹配最后一個(gè) "d",但那也是為了讓整個(gè)表達(dá)式能夠匹配成功。同理,帶 "*" 和 "{m,n}" 的表達(dá)式都是盡可能地多匹配,帶 "?" 的表達(dá)式在可匹配可不匹配的時(shí)候,也是盡可能的 "要匹配"。這 種匹配原則就叫作 "貪婪" 模式 。

          ??? 非貪婪模式:

          ??? 在修飾匹配次數(shù)的特殊符號(hào)后再加上一個(gè) "?" 號(hào),則可以使匹配次數(shù)不定的表達(dá)式盡可能少的匹配,使可匹配可不匹配的表達(dá)式,盡可能的 "不匹配"。這種匹配原則叫作 "非貪婪" 模式,也叫作 "勉強(qiáng)" 模式。如果少匹配就會(huì)導(dǎo)致整個(gè)表達(dá)式匹配失敗的時(shí)候,與貪婪模式類似,非貪婪模式會(huì)最小限度的再匹配一些,以使整個(gè)表達(dá)式匹配成功。舉例如下,針對(duì)文本 "dxxxdxxxd" 舉例:

          表達(dá)式

          匹配結(jié)果

          (d)(\w+?)

          "\w+?" 將盡可能少的匹配第一個(gè) "d" 之后的字符,結(jié)果是:"\w+?" 只匹配了一個(gè) "x"

          (d)(\w+?)(d)

          為了讓整個(gè)表達(dá)式匹配成功,"\w+?" 不得不匹配 "xxx" 才可以讓后邊的 "d" 匹配,從而使整個(gè)表達(dá)式匹配成功。因此,結(jié)果是:"\w+?" 匹配 "xxx"

          ??? 更多的情況,舉例如下:

          ??? 舉 例1:表達(dá)式 "<td>(.*)</td>" 與字符串 "<td><p>aa</p></td> <td><p>bb</p></td>" 匹配時(shí),匹配的結(jié)果是:成功;匹配到的內(nèi)容是 "<td><p>aa</p></td> <td><p>bb</p></td>" 整個(gè)字符串, 表達(dá)式中的 "</td>" 將與字符串中最后一個(gè) "</td>" 匹配。

          ??? ,將只得到 "<td><p>aa</p></td>", 再次匹配下一個(gè)時(shí),可以得到第二個(gè) "<td><p>bb</p></td>"。


          2.2 反向引用 \1, \2...

          ??? 表達(dá)式在匹配時(shí),表達(dá)式引擎會(huì)將小括號(hào) "( )" 包含的表達(dá)式所匹配到的字符串記錄下來(lái)。在獲取匹配結(jié)果的時(shí)候,小括號(hào)包含的表達(dá)式所匹配到的字符串可以單獨(dú)獲取。這一點(diǎn),在前面的舉例中,已經(jīng)多次展示 了。在實(shí)際應(yīng)用場(chǎng)合中,當(dāng)用某種邊界來(lái)查找,而所要獲取的內(nèi)容又不包含邊界時(shí),必須使用小括號(hào)來(lái)指定所要的范圍。比如前面的 "<td>(.*?)</td>"。

          ??? 其實(shí),"小括號(hào)包含的表達(dá)式所匹配到的字符串" 不僅是在匹配結(jié)束后才可以使用,在匹配過(guò)程中也可以使用。表達(dá)式后邊的部分,可以引用前面 "括號(hào)內(nèi)的子匹配已經(jīng)匹配到的字符串"。引用方法是 "\" 加上一個(gè)數(shù)字。"\1" 引用第1對(duì)括號(hào)內(nèi)匹配到的字符串,"\2" 引用第2對(duì)括號(hào)內(nèi)匹配到的字符串……以此類推,如果一對(duì)括號(hào)內(nèi)包含另一對(duì)括號(hào),則外層的括號(hào)先排序號(hào)。換句話說(shuō),哪一對(duì)的左括號(hào) "(" 在前,那這一對(duì)就先排序號(hào)。

          ??? 舉例如下:

          ??? ,匹配結(jié)果是:成功;匹配到的內(nèi)容是:" 'Hello' "。再次匹配下一個(gè)時(shí),可以匹配到 " "World" "。

          ???
          ,匹配結(jié)果是:成功;匹配到的內(nèi)容是 "ccccc"。再次匹配下一個(gè)時(shí),將得到 999999999。這個(gè)表達(dá)式要求 "\w" 范圍的字符至少重復(fù)5次,

          ???
          舉例3:表達(dá)式 "<(\w+)\s*(\w+(=('|").*?\4)?\s*)*>.*?</\1>" 在匹配 "<td id='td1' style="bgcolor:white"></td>" 時(shí),匹配結(jié)果是成功。如果 "<td>" 與 "</td>" 不配對(duì),則會(huì)匹配失敗;如果改成其他配對(duì),也可以匹配成功。


          2.3 預(yù)搜索,不匹配;反向預(yù)搜索,不匹配

          ??? 前面的章節(jié)中,我講到了幾個(gè)代表抽象意義的特殊符號(hào):"^","$","\b"。它們都有一個(gè)共同點(diǎn),那就是:它們本身不匹配任何字符,只是對(duì) "字符串的兩頭" 或者 "字符之間的縫隙" 附加了一個(gè)條件。理解到這個(gè)概念以后,本節(jié)將繼續(xù)介紹另外一種對(duì) "兩頭" 或者 "縫隙" 附加條件的,更加靈活的表示方法。

          ??? 正向預(yù)搜索:"(?=xxxxx)","(?!xxxxx)"

          ??? 格式:"(?=xxxxx)",在被匹配的字符串中,它對(duì)所處的 "縫隙" 或者 "兩頭" 附加的條件是:所在縫隙的右側(cè),必須能夠匹配上 xxxxx 這部分的表達(dá)式。因?yàn)樗皇窃诖俗鳛檫@個(gè)縫隙上附加的條件,所以它并不影響后邊的表達(dá)式去真正匹配這個(gè)縫隙之后的字符。這就類似 "\b",本身不匹配任何字符。"\b" 只是將所在縫隙之前、之后的字符取來(lái)進(jìn)行了一下判斷,不會(huì)影響后邊的表達(dá)式來(lái)真正的匹配。

          ??? ,將只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字樣則不被匹配。

          ???
          ,將可以匹配6個(gè)"f"的前4個(gè),可以匹配9個(gè)"9"的前7個(gè)。這個(gè)表達(dá)式可以讀解成:重復(fù)4次以上的字母數(shù)字,則匹配其剩下最后2位之前的部分。當(dāng)然,這個(gè)表達(dá)式可以不這樣寫(xiě),在此的目的是作為演示之用。

          ??? 格式:"(?!xxxxx)",所在縫隙的右側(cè),必須不能匹配 xxxxx 這部分表達(dá)式。

          ???
          ,將從頭一直匹配到 "stop" 之前的位置,如果字符串中沒(méi)有 "stop",則匹配整個(gè)字符串。

          ???
          ,只能匹配 "do"。在本條舉例中,"do" 后邊使用 "(?!\w)" 和使用 "\b" 效果是一樣的。

          ??? 反向預(yù)搜索:"(?<=xxxxx)","(?<!xxxxx)"

          ??? 這兩種格式的概念和正向預(yù)搜索是類似的,反向預(yù)搜索要求的條件是:所在縫隙的 "左側(cè)",兩種格式分別要求必須能夠匹配和必須不能夠匹配指定表達(dá)式,而不是去判斷右側(cè)。與 "正向預(yù)搜索" 一樣的是:它們都是對(duì)所在縫隙的一種附加條件,本身都不匹配任何字符。

          ??? 舉例5:表達(dá)式 "(?<=\d{4})\d+(?=\d{4})" 在匹配 "1234567890123456" 時(shí),將匹配除了前4個(gè)數(shù)字和后4個(gè)數(shù)字之外的中間8個(gè)數(shù)字。由于 JScript.RegExp 不支持反向預(yù)搜索,因此,本條舉例不能夠進(jìn)行演示。很多其他的引擎可以支持反向預(yù)搜索,比如:Java 1.4 以上的 java.util.regex 包,.NET 中System.Text.RegularExpressions 命名空間,boost::regex 以及
          GRETA 正則表達(dá)式庫(kù)等。


          3. 其他通用規(guī)則

          ??? 還有一些在各個(gè)正則表達(dá)式引擎之間比較通用的規(guī)則,在前面的講解過(guò)程中沒(méi)有提到。

          3.1 表達(dá)式中,可以使用 "\xXX" 和 "\uXXXX" 表示一個(gè)字符("X" 表示一個(gè)十六進(jìn)制數(shù))

          形式

          字符范圍

          \xXX

          編號(hào)在 0 ~ 255 范圍的字符,比如:

          \uXXXX

          任何字符可以使用 "\u" 再加上其編號(hào)的4位十六進(jìn)制數(shù)表示,比如:

          3.2 在表達(dá)式 "\s","\d","\w","\b" 表示特殊意義的同時(shí),對(duì)應(yīng)的大寫(xiě)字母表示相反的意義

          表達(dá)式

          可匹配

          \S

          \D

          匹配所有的非數(shù)字字符

          \W

          匹配所有的字母、數(shù)字、下劃線以外的字符

          \B

          3.3 在表達(dá)式中有特殊意義,需要添加 "\" 才能匹配該字符本身的字符匯總

          字符

          說(shuō)明

          ^

          匹配輸入字符串的開(kāi)始位置。要匹配 "^" 字符本身,請(qǐng)使用 "\^"

          $

          匹配輸入字符串的結(jié)尾位置。要匹配 "$" 字符本身,請(qǐng)使用 "\$"

          ( )

          標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置。要匹配小括號(hào),請(qǐng)使用 "\(" 和 "\)"

          [ ]

          用來(lái)自定義能夠匹配 '多種字符' 的表達(dá)式。要匹配中括號(hào),請(qǐng)使用 "\[" 和 "\]"

          { }

          修飾匹配次數(shù)的符號(hào)。要匹配大括號(hào),請(qǐng)使用 "\{" 和 "\}"

          .

          匹配除了換行符(\n)以外的任意一個(gè)字符。要匹配小數(shù)點(diǎn)本身,請(qǐng)使用 "\."

          ?

          修飾匹配次數(shù)為 0 次或 1 次。要匹配 "?" 字符本身,請(qǐng)使用 "\?"

          +

          修飾匹配次數(shù)為至少 1 次。要匹配 "+" 字符本身,請(qǐng)使用 "\+"

          *

          修飾匹配次數(shù)為 0 次或任意次。要匹配 "*" 字符本身,請(qǐng)使用 "\*"

          |

          左右兩邊表達(dá)式之間 "或" 關(guān)系。匹配 "|" 本身,請(qǐng)使用 "\|"

          3.4 括號(hào) "( )" 內(nèi)的子表達(dá)式,如果希望匹配結(jié)果不進(jìn)行記錄供以后使用,可以使用 "(?:xxxxx)" 格式

          ??? ,結(jié)果是 "bbccdd"。括號(hào) "(?:)" 范圍的匹配結(jié)果不進(jìn)行記錄,因此 "(\w)" 使用 "\1" 來(lái)引用。

          3.5 常用的表達(dá)式屬性設(shè)置簡(jiǎn)介:Ignorecase,Singleline,Multiline,Global

          表達(dá)式屬性

          說(shuō)明

          Ignorecase

          默認(rèn)情況下,表達(dá)式中的字母是要區(qū)分大小寫(xiě)的。配置為 Ignorecase 可使匹配時(shí)不區(qū)分大小寫(xiě)。有的表達(dá)式引擎,把 "大小寫(xiě)" 概念延伸至 UNICODE 范圍的大小寫(xiě)。

          Singleline

          默認(rèn)情況下,小數(shù)點(diǎn) "." 匹配除了換行符(\n)以外的字符。配置為 Singleline 可使小數(shù)點(diǎn)可匹配包括換行符在內(nèi)的所有字符。

          Multiline

          默認(rèn)情況下,表達(dá)式 "^" 和 "$" 只匹配字符串的開(kāi)始 ① 和結(jié)尾 ④ 位置。如:

          ①xxxxxxxxx②\n
          ③xxxxxxxxx④

          配置為 Multiline 可以使 "^" 匹配 ① 外,還可以匹配換行符之后,下一行開(kāi)始前 ③ 的位置,使 "$" 匹配 ④ 外,還可以匹配換行符之前,一行結(jié)束 ② 的位置。

          Global

          主要在將表達(dá)式用來(lái)替換時(shí)起作用,配置為 Global 表示替換所有的匹配。


          4. 綜合提示

          4.1 如果要要求表達(dá)式所匹配的內(nèi)容是整個(gè)字符串,而不是從字符串中找一部分,那么可以在表達(dá)式的首尾使用 "^" 和 "$",比如:"^\d+$" 要求整個(gè)字符串只有數(shù)字。

          4.2 如果要求匹配的內(nèi)容是一個(gè)完整的單詞,而不會(huì)是單詞的一部分,那么在表達(dá)式首尾使用 "\b",比如:

          4.3 表達(dá)式不要匹配空字符串。否則會(huì)一直得到匹配成功,而結(jié)果什么都沒(méi)有匹配到。比如:準(zhǔn)備寫(xiě)一個(gè)匹配 "123"、"123."、"123.5"、".5" 這幾種形式的表達(dá)式時(shí),整數(shù)、小數(shù)點(diǎn)、小數(shù)數(shù)字都可以省略,但是不要將表達(dá)式寫(xiě)成:"\d*\.?\d*",因?yàn)槿绻裁炊紱](méi)有,這個(gè)表達(dá)式也可以匹配成 功。

          4.4 能匹配空字符串的子匹配不要循環(huán)無(wú)限次。如果括號(hào)內(nèi)的子表達(dá)式中的每一部分都可以匹配 0 次,而這個(gè)括號(hào)整體又可以匹配無(wú)限次,那么情況可能比上一條所說(shuō)的更嚴(yán)重,匹配過(guò)程中可能死循環(huán)。雖然現(xiàn)在有些正則表達(dá)式引擎已經(jīng)通過(guò)辦法避免了這種情況 出現(xiàn)死循環(huán)了,比如 .NET 的正則表達(dá)式,但是我們?nèi)匀粦?yīng)該盡量避免出現(xiàn)這種情況。如果我們?cè)趯?xiě)表達(dá)式時(shí)遇到了死循環(huán),也可以從這一點(diǎn)入手,查找一下是否是本條所說(shuō)的原因。

          4.5 合理選擇貪婪模式與非貪婪模式,參見(jiàn)話題討論

          4.6 或 "|" 的左右兩邊,對(duì)某個(gè)字符最好只有一邊可以匹配,這樣,不會(huì)因?yàn)?"|" 兩邊的表達(dá)式因?yàn)榻粨Q位置而有所不同。

          posted @ 2006-08-21 20:10 soufan 閱讀(215) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 霍州市| 尚志市| 得荣县| 东台市| 涞水县| 荔波县| 高雄市| 西昌市| 宜兰县| 哈密市| 旅游| 融水| 祥云县| 石泉县| 新宁县| 乐平市| 安图县| 鲜城| 西林县| 永定县| 邢台县| 红原县| 宣城市| 定边县| 临湘市| 佛学| 寿光市| 玛多县| 黎川县| 抚顺县| 万宁市| 禄劝| 长海县| 明光市| 江门市| 稻城县| 桂平市| 临湘市| 临邑县| 武汉市| 金寨县|