<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    limq

    rainman
    隨筆 - 19, 文章 - 2, 評(píng)論 - 115, 引用 - 1
    數(shù)據(jù)加載中……

    Jakarta Commons:巧用類和組件(轉(zhuǎn))

    Jakarta Commons是Jakarta的子項(xiàng)目,它創(chuàng)建和維護(hù)著許多獨(dú)立軟件包,這些包一般與其他框架或產(chǎn)品無關(guān),其中收集了大量小型、實(shí)用的組件,大部分面向服務(wù)器端編程。

      Commons的包分成兩部分:Sandbox,Commons代碼庫。Sandbox是一個(gè)測(cè)試平臺(tái),用來檢驗(yàn)各種設(shè)想、計(jì)劃。本文介紹的組件屬于Commons代碼庫,文章將展示各個(gè)組件的功能、適用場(chǎng)合,并通過簡(jiǎn)單的例子介紹其用法。

      一、概述

      可重用性是Jakarta Commons項(xiàng)目的靈魂所在。這些包在設(shè)計(jì)階段就已經(jīng)考慮了可重用性問題。其中一些包,例如Commons里面用來記錄日志的Logging包,最初是為其他項(xiàng)目設(shè)計(jì)的,例如Jakarta Struts項(xiàng)目,當(dāng)人們發(fā)現(xiàn)這些包對(duì)于其他項(xiàng)目也非常有用,能夠極大地幫助其他項(xiàng)目的開發(fā),他們決定為這些包構(gòu)造一個(gè)"公共"的存放位置,這就是Jakarta Commons項(xiàng)目。

      為了真正提高可重用性,每一個(gè)包都必須不依賴于其他大型的框架或項(xiàng)目。因此,Commons項(xiàng)目的包基本上都是獨(dú)立的,不僅是相對(duì)于其他項(xiàng)目的獨(dú)立,而且相對(duì)于Commons內(nèi)部的大部分其他包獨(dú)立。雖然存在一些例外的情況,例如Betwixt包要用到XML API,但絕大部分只使用最基本的API,其主要目的就是要能夠通過簡(jiǎn)單的接口方便地調(diào)用。

      不過由于崇尚簡(jiǎn)潔,許多包的文檔變得過于簡(jiǎn)陋,缺乏維護(hù)和支持,甚至有一部分還有錯(cuò)誤的鏈接,文檔也少得可憐。大部分的包需要我們自己去找出其用法,甚至有時(shí)還需要我們自己去分析其適用場(chǎng)合。本文將逐一介紹這些包,希望能夠幫助你迅速掌握這一積累了許多人心血的免費(fèi)代碼庫。

      說明:Jakarta Commons和Apache Commons是不同的,后者是Apache Software Foundation的一個(gè)頂層項(xiàng)目,前者則是Jakarta項(xiàng)目的一個(gè)子項(xiàng)目,同是也是本文要討論的主角。本文后面凡是提到Commons的地方都是指Jakarta的Commons。

      為了便于說明,本文把Commons項(xiàng)目十八個(gè)成品級(jí)的組件(排除了EL、Latka和Jexl)分成5類,如下表所示。


    參考 http://www.tkk7.com/sean/archive/2005/08.html

    ?


      必須指出的是,這種分類只是為了方便文章說明,Commons項(xiàng)目里面實(shí)際上并不存在這種分類,同時(shí)這些分類的邊界有時(shí)也存在一定的重疊。

      本文首先介紹Web相關(guān)類和其他類里面的組件,下一篇文章將涉及XML相關(guān)、包裝這兩類,最后一篇文章專門介紹屬于工具類的包。

      二、其他類

      CLI、Discovery、Lang和Collections包歸入其他類,這是因?yàn)樗鼈兌几髯葬槍?duì)某個(gè)明確、實(shí)用的小目標(biāo),可謂專而精。

      2.1 CLI

      ■ 概況:CLI即Command Line Interface,也就是"命令行接口",它為Java程序訪問和解析命令行參數(shù)提供了一種統(tǒng)一的接口。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:當(dāng)你需要以一種一致的、統(tǒng)一的方式訪問命令行參數(shù)之時(shí)。

      ■ 示例應(yīng)用:CLIDemo.java。CLASSPATH中必須包含commons-cli-1.0.jar。

      ■ 說明:

      有多少次你不得不為一個(gè)新的應(yīng)用程序重新設(shè)計(jì)新的命令行參數(shù)處理方式?如果能夠只用某個(gè)單一的接口,統(tǒng)一完成諸如定義輸入?yún)?shù)(是否為強(qiáng)制參數(shù),數(shù)值還是字符串,等等)、根據(jù)一系列規(guī)則分析參數(shù)、確定應(yīng)用要采用的路徑等任務(wù),那該多好!答案就在CLI。

      在CLI中,每一個(gè)想要在命令中指定的參數(shù)都是一個(gè)Option對(duì)象。首先創(chuàng)建一個(gè)Options對(duì)象,將各個(gè)Option對(duì)象加入Options對(duì)象,然后利用CLI提供的方法來解析用戶的輸入?yún)?shù)。Option對(duì)象可以要求用戶必須輸入某個(gè)參數(shù),例如必須在命令行提供文件名字。如果某個(gè)參數(shù)是必須的,創(chuàng)建Option對(duì)象的時(shí)候就要顯式地指定。

      下面是使用CLI的步驟。

    // …
    // ①  創(chuàng)建一個(gè)Options:
    Options options = new Options();
    options.addOption("t", false, "current time");
    // …
    // ② 創(chuàng)建一個(gè)解析器,分析輸入:
    CommandLineParser parser = new BasicParser();
    CommandLine cmd;
    try {
    	cmd = parser.parse(options, args); 
    } catch (ParseException pe) {
    	usage(options);
    	return;
    }
    // …
    // ③ 最后就可以根據(jù)用戶的輸入,采取相應(yīng)的操作:
    if (cmd.hasOption("n")) {
    	System.err.println("Nice to meet you: " +
    	cmd.getOptionValue('n'));
    }


      這就是使用CLI的完整過程了。當(dāng)然,CLI還提供了其他高級(jí)選項(xiàng),例如控制格式和解析過程等,但基本的使用思路仍是一致的。請(qǐng)參見本文最后提供的示例程序。

      2.2 Discovery

      ■ 概況:Discovery組件是發(fā)現(xiàn)模式(Discovery Pattern)的一個(gè)實(shí)現(xiàn),它的目標(biāo)是按照一種統(tǒng)一的方式定位和實(shí)例化類以及其他資源。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:當(dāng)你想用最佳的算法在Java程序中查找Java接口的各種實(shí)現(xiàn)之時(shí)。

      ■ 應(yīng)用實(shí)例:DiscoveryDemo.java,MyInterface.java,MyImpl1.java,MyImpl2.java,MyInterface。要求CLASSPATH中必須包含commons-discovery.jar和commons-logging.jar。

      ■ 說明:

      Discovery的意思就是"發(fā)現(xiàn)",它試圖用最佳的算法查找某個(gè)接口的所有已知的實(shí)現(xiàn)。在使用服務(wù)的場(chǎng)合,當(dāng)我們想要查找某個(gè)服務(wù)的所有已知的提供者時(shí),Discovery組件尤其有用。

      考慮一下這種情形:我們?yōu)槟硞€(gè)特別復(fù)雜的任務(wù)編寫了一個(gè)接口,所有該接口的實(shí)現(xiàn)都用各不相同的方式來完成這個(gè)復(fù)雜任務(wù),最終用戶可以根據(jù)需要來選擇完成任務(wù)的具體方式。那么,在這種情形下,最終用戶應(yīng)該用什么辦法來找出接口的所有可用實(shí)現(xiàn)(即可能的完成任務(wù)的方式)呢?

      上面描述的情形就是所謂的服務(wù)-服務(wù)提供者體系。服務(wù)的功能由接口描述,服務(wù)提供者則提供具體的實(shí)現(xiàn)。現(xiàn)在的問題是最終用戶要用某種辦法來尋找系統(tǒng)中已經(jīng)安裝了哪些服務(wù)提供者。在這種情形下,Discovery組件就很有用了,它不僅可以用來查找那些實(shí)現(xiàn)了特定接口的類,而且還可以用來查找資源,例如圖片或其他文件等。在執(zhí)行這些操作時(shí),Discovery遵從Sun的服務(wù)提供者體系所定義的規(guī)則。

      由于這個(gè)原因,使用Discovery組件確實(shí)帶來許多方便。請(qǐng)讀者參閱本文后面示例程序中的接口MyInterface.java和兩個(gè)實(shí)現(xiàn)類MyImpl1.java、MyImple2.java,了解下面例子的細(xì)節(jié)。在使用Discovery的時(shí)候要提供MyInterface文件,把它放入META-INF/services目錄,注意該文件的名字對(duì)應(yīng)接口的完整限定名稱(Fully Qualified Name),如果接口屬于某個(gè)包,該文件的名字也必須相應(yīng)地改變。

    // …
    // ① 創(chuàng)建一個(gè)類裝入器的實(shí)例。
    ClassLoaders loaders =
    	ClassLoaders.getAppLoaders(MyInterface.class, getClass(), false);
    // …
    // ② 用DiscoverClass的實(shí)例來查找實(shí)現(xiàn)類。
    DiscoverClass discover = new DiscoverClass(loaders);
    // …
    // ③ 查找實(shí)現(xiàn)了指定接口的類:
    Class implClass = discover.find(MyInterface.class);
    System.err.println("Implementing Provider: " + implClass.getName());


      運(yùn)行上面的代碼,就可以得到在MyInterface文件中注冊(cè)的類。再次提醒,如果你的實(shí)現(xiàn)是封裝在包里面的,在這里注冊(cè)的名字也應(yīng)該作相應(yīng)地修改,如果該文件沒有放在正確的位置,或者指定名字的實(shí)現(xiàn)類不能找到或?qū)嵗绦驅(qū)伋鯠iscoverException,表示找不到符合條件的實(shí)現(xiàn)。下面是MyInterface文件內(nèi)容的一個(gè)例子:MyImpl2 # Implementation 2。

      當(dāng)然,實(shí)現(xiàn)類的注冊(cè)辦法并非只有這么一種,否則的話Discovery的實(shí)用性就要大打折扣了!實(shí)際上,按照Discovery內(nèi)部的類查找機(jī)制,按照這種方法注冊(cè)的類將是Discovery最后找到的類。另一種常用的注冊(cè)方法是通過系統(tǒng)屬性或用戶定義的屬性來傳遞實(shí)現(xiàn)類的名字,例如,放棄META-INF/services目錄下的文件,改為執(zhí)行java -DMyInterface=MyImpl1 DiscoveryDemo命令來運(yùn)行示例程序,這里的系統(tǒng)屬性是接口的名字,值是該接口的提供者,運(yùn)行的結(jié)果是完全一樣的。

      Discovery還可以用來創(chuàng)建服務(wù)提供者的(singleton)實(shí)例并調(diào)用其方法,語法如下:((MyInterface)discover.newInstance(MyInterface.class)).myMethod();。注意在這個(gè)例子中,我們并不知道到底哪一個(gè)服務(wù)提供者實(shí)現(xiàn)了myMethod,甚至我們根本不必關(guān)心這一點(diǎn)。具體的情形與運(yùn)行這段代碼的方式以及運(yùn)行環(huán)境中已經(jīng)注冊(cè)了什么服務(wù)提供者有關(guān),在不同的環(huán)境下運(yùn)行,實(shí)際得到的服務(wù)提供者可能不同。

      2.3 Lang

      ■ 概況:Lang是java.lang的一個(gè)擴(kuò)展包,增加了許多操作String的功能,另外還支持C風(fēng)格的枚舉量。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:當(dāng)java.lang包提供的方法未能滿足需要,想要更多的功能來處理String、數(shù)值和System屬性時(shí);還有,當(dāng)你想要使用C風(fēng)格的枚舉量時(shí)。

      ■ 示例應(yīng)用:LangDemo.java,Mortgage.java,OnTV.java。CLASSPATH中必須包含commons-lang.jar。

      ■ 說明:

      這個(gè)包提供了許多出于方便目的而提供的方法,它們中的大多數(shù)是靜態(tài)的,簡(jiǎn)化了日常編碼工作。StringUtils類是其中的一個(gè)代表,它使得開發(fā)者能夠超越標(biāo)準(zhǔn)的java.lang.String包來處理字符串。使用這些方法很簡(jiǎn)單,通常只要在調(diào)用靜態(tài)方法時(shí)提供適當(dāng)?shù)膮?shù)就可以了。例如,如果要將某個(gè)單詞的首字符改為大寫,只需調(diào)用:StringUtils.capitalise("name"),調(diào)用的輸出結(jié)果是Name。請(qǐng)瀏覽StringUtils API文檔了解其他靜態(tài)方法,也許你會(huì)找到一些可以直接拿來使用的代碼。本文提供的示例程序示范了其中一些方法的使用。

      另一個(gè)值得注意的類是RandomStringUtils,它提供了生成隨機(jī)字符串的方法,用來創(chuàng)建隨機(jī)密碼實(shí)在太方便了。

      NumberUtils類提供了處理數(shù)值數(shù)據(jù)的方法,許多方法值得一用,例如尋找最大、最小數(shù)的方法,將String轉(zhuǎn)換成數(shù)值的方法,等等。NumberRange和CharRange類分別提供了創(chuàng)建和操作數(shù)值范圍、字符范圍的方法。

      Builder包里的類提供了一些特殊的方法,可用來構(gòu)造類的toString、hashCode、compareTo和equals方法,其基本思路就是構(gòu)造出類的高質(zhì)量的toString、hashCode、compareTo和equals方法,從而免去了用戶自己定義這些方法之勞,只要調(diào)用一下Builder包里面的方法就可以了。例如,我們可以用ToStringBuilder來構(gòu)造出類的toString描述,如下例所示:

    public class Mortgage {
    	private float rate;
    	private int years;
    	....
    	public String toString() {
    		return new ToStringBuilder(this).
    			append("rate",  this.rate).
    			append("years", this.years).
    			toString();
    	}
    }
      使用這類方法有什么好處呢?顯然,它使得我們有可能通過一種統(tǒng)一的方式處理所有數(shù)據(jù)類型。所有Builder方法的用法都和上例相似。

      Java沒有C風(fēng)格的枚舉量,為此,lang包提供了一個(gè)類型安全的Enum類型,填補(bǔ)了空白。Enum類是抽象的,如果你要?jiǎng)?chuàng)建枚舉量,就要擴(kuò)展Enum類。下面的例子清楚地說明了Enum的用法。

    import org.apache.commons.lang.enum.Enum;
    import java.util.Map;
    import java.util.List;
    import java.util.Iterator;
        
    public final class OnTV extends Enum {
                
    	public static final OnTV IDOL= 
    	  new OnTV("Idol");
    	public static final OnTV SURVIVOR =
    	  new OnTV("Survivor");
    	public static final OnTV SEINFELD = 
    	  new OnTV("Seinfeld");
    
    	private OnTV(String show) {
    		super(show);
    	}
    	public static OnTV getEnum(String show){
    		return (OnTV) getEnum(OnTV.class, show);
    	}
    	public static Map getEnumMap() {
    		return getEnumMap(OnTV.class);
    	}
    	public static List getEnumList() {
    		return getEnumList(OnTV.class);
    	}
    	public static Iterator iterator() {
    		return iterator(OnTV.class);
    	}
    }


      以后我們就可以按照下面的方式使用枚舉變量:OnTV.getEnum("Idol")。該調(diào)用從前面創(chuàng)建的枚舉數(shù)據(jù)類型返回Idol。這個(gè)例子比較簡(jiǎn)單,實(shí)際上Enum類還提供了許多有用的方法,請(qǐng)參見本文后面提供的完整實(shí)例。

      2.4 Collections

      ■ 概況:擴(kuò)展了Java Collection框架,增添了新的數(shù)據(jù)結(jié)構(gòu)、迭代機(jī)制和比較操作符。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:幾乎所有需要操作數(shù)據(jù)結(jié)構(gòu)的重要Java開發(fā)項(xiàng)目都可以使用Collections API。和Java的標(biāo)準(zhǔn)實(shí)現(xiàn)相比,Collections API有著諸多優(yōu)勢(shì)。

      ■ 示例應(yīng)用:CollectionsDemo.java。要求CLASSPATH中包含commons-collections.jar。

      ■ 說明:

      要在有限的文章篇幅之內(nèi)詳盡地介紹 Collections API實(shí)在是太困難了,不過這里仍將涵蓋大多數(shù)最重要的類,希望能夠引起你的興趣,認(rèn)真了解一下其余的類。Collections本身的文檔也提供了許多資料并解釋了每一個(gè)類的用法。

      Bag接口擴(kuò)展標(biāo)準(zhǔn)的Java Collection,允許生成計(jì)數(shù)器來跟蹤Bag里面的所有元素。當(dāng)你想要跟蹤進(jìn)出某個(gè)集合的元素的總數(shù)時(shí),Bag是非常有用的。由于Bag本身是一個(gè)接口,所以實(shí)際使用的應(yīng)該是實(shí)現(xiàn)了該接口的類,例如HashBag或TreeBag--從這些類的名字也可以看出,HashBag實(shí)現(xiàn)的是一個(gè)HashMap的Bag,而TreeBag實(shí)現(xiàn)的是TreeMap的Bag。Bag接口中兩個(gè)最重要的方法是:getCount(Object o),用來返回Bag里面特定對(duì)象的出現(xiàn)次數(shù);uniqueSet(),返回所有唯一元素。

      Buffer接口允許按照預(yù)定義的次序刪除集合中的對(duì)象,刪除次序可以是LIFO(Last In First Out,后進(jìn)先出),或FIFO(First In First Out,先進(jìn)先出),另外還可以是自定義的次序。下面來看看如何實(shí)現(xiàn)一個(gè)Buffer,按照自然次序刪除元素。

      BinaryHeap類實(shí)現(xiàn)了Buffer接口,能夠按照自然次序刪除元素。如果要顛倒次序,則必須傳入一個(gè)false,告訴Heap采用自然次序的逆序。

    BinaryHeap heap = new BinaryHeap();
    // …
    // 將元素加入該Heap
    heap.add(new Integer(-1));
    heap.add(new Integer(-10));
    heap.add(new Integer(0));
    heap.add(new Integer(-3));
    heap.add(new Integer(5));
    //…
    // 刪除一個(gè)元素
    heap.remove();


      調(diào)用該Heap的remove,按照自然次序,元素集合中的-10將被刪除。如果我們要求按照逆序排序,則被刪除的將是5。

      FastArrayList、FastHashMap和FastTreeMap類能夠按照兩種模式操作,超越了與它們對(duì)應(yīng)的標(biāo)準(zhǔn)Collection。第一種模式是"慢模式",類的修改操作(添加、刪除元素)是同步的。與此相對(duì),另一種模式是"快模式",對(duì)這些類的訪問假定為只讀操作,因此不需要同步,速度較快。在快模式中,結(jié)構(gòu)性的改動(dòng)通過下列方式完成:首先克隆現(xiàn)有的類,修改克隆得到的類,最后用克隆得到的類替換原有的類。FastArrayList、FastHashMap和FastTreeMap類特別適合于那種初始化之后大部分操作都是只讀操作的多線程環(huán)境。

      iterators包為各種集合和對(duì)象提供標(biāo)準(zhǔn)Java Collection包沒有提供的迭代器。本文的示例應(yīng)用示范了ArrayIterator,通過迭代方式訪問Array的內(nèi)容。iterators包里面各種迭代器的用法基本上與標(biāo)準(zhǔn)Java迭代器一樣。

      最后,comparators包提供了一些實(shí)用的比較符。所謂比較符其實(shí)也是一個(gè)類,它定義的是如何比較兩個(gè)屬于同一類的對(duì)象,決定它們的排序次序。例如,在前面提到的Buffer類中,我們可以定義自己的比較符,用自定義的比較符來決定元素的排序次序,而不是采用元素的自然排序次序。下面來看看具體的實(shí)現(xiàn)經(jīng)過。

    // …
    // ① 創(chuàng)建一個(gè)BinaryHeap類,但這一次參數(shù)中
    //    指定NullComparator。NullComparator比較
    //    null與其他對(duì)象,根據(jù)nullsAreHigh標(biāo)記來
    //    判斷null值比其他對(duì)象大還是小:如果
    //    nullsAreHigh的值是false,則認(rèn)為null要比
    //    其他對(duì)象小。
    BinaryHeap heap2 = new BinaryHeap
     (new NullComparator(false));
    // …
    // ② 將一些數(shù)據(jù)(包括幾個(gè)null值)加入heap:
    heap2.add(null);
    heap2.add(new Integer("6"));
    heap2.add(new Integer("-6"));
    heap2.add(null);
    // …
    // ③ 最后刪除一個(gè)元素,Bag包含的null將減少
    //    一個(gè),因?yàn)閚ull要比其他對(duì)象小。
    heap2.remove();


      有關(guān)其他類Commons組件的介紹就到這里結(jié)束。如果你想了解更多細(xì)節(jié)信息,請(qǐng)參見API文檔,最好再看看這些包的源代碼。

      三、Web類

      Web類的組件用來執(zhí)行與Web相關(guān)的任務(wù)。

      3.1 FileUpload

      ■ 概況:一個(gè)可以直接使用的文件上載組件。

      ■ 官方資源:主頁。由于這個(gè)組件尚未正式發(fā)布,今年二月發(fā)布的Beta版又有許多BUG,所以建議從nightly builds下載最新的版本。

      ■ 何時(shí)適用:當(dāng)你想要在Java服務(wù)器環(huán)境中加入一個(gè)易用、高性能的文件上載組件之時(shí)。

      ■ 示例應(yīng)用:fileuploaddemo.jsp,fileuploaddemo.htm,和msg.jsp。要求服務(wù)器端應(yīng)用目錄的WEB-INF/lib下面有commons-fileupload-1.0-dev.jar。

      ■ 說明:

      FileUpload組件解決了常見的文件上載問題。它提供了一個(gè)易用的接口來管理上載到服務(wù)器的文件,可用于JSP和Servlet之中。FileUpload組件遵從RFC1867,它分析輸入請(qǐng)求,向應(yīng)用程序提供一系列上載到服務(wù)器的文件。上載的文件可以保留在內(nèi)存中,也可以放入一個(gè)臨時(shí)位置(允許配置一個(gè)表示文件大小的參數(shù),如果上載的文件超過了該參數(shù)指定的大小,則把文件寫入一個(gè)臨時(shí)位置)。另外還有一些參數(shù)可供配置,包括可接受的最大文件、臨時(shí)文件的位置等。

      下面介紹一下使用FileUpload組件的步驟。

      首先創(chuàng)建一個(gè)HTML頁面。注意,凡是要上載文件的表單都必須設(shè)置enctype屬性,且屬性的值必須是multipart/form-data,同時(shí)請(qǐng)求方法必須是POST。下面的表單除了上載兩個(gè)文件,另外還有一個(gè)普通的文本輸入框:

    
        輸入你的名字:

    圖形:

    文件:




      接下來創(chuàng)建JSP頁面。

    // …
    // ① 檢查輸入請(qǐng)求是否為multipart的表單數(shù)據(jù)。
    boolean isMultipart = FileUpload.
      isMultipartContent(request);
    // …
    // ② 為該請(qǐng)求創(chuàng)建一個(gè)句柄,通過它來解析請(qǐng)求。執(zhí)行
    //    解析后,所有的表單項(xiàng)目都保存在一個(gè)List中。
    DiskFileUpload upload = new DiskFileUpload();
    // 通過句柄解析請(qǐng)求,解析得到的項(xiàng)目保存在一個(gè)List中
    List items = upload.parseRequest(request);
    // …
    // ③ 通過循環(huán)依次獲得List里面的文件項(xiàng)目。要區(qū)分表示
    //    文件的項(xiàng)目和普通的表單輸入項(xiàng)目,使用isFormField()
    //    方法。根據(jù)處理請(qǐng)求的要求,我們可以保存上載的文
    //    件,或者一個(gè)字節(jié)一個(gè)字節(jié)地處理文件內(nèi)容,或者打
    //    開文件的輸入流。
    Iterator itr = items.iterator();
    
    while(itr.hasNext()) {
    	FileItem item = (FileItem) itr.next();
            
    // 檢查當(dāng)前的項(xiàng)目是普通的表單元素,還是一個(gè)上載的文件
    	if(item.isFormField()) {
    // 獲得表單域的名字
    	String fieldName = item.getFieldName();
    // 如果表單域的名字是name…
    	if(fieldName.equals("name"))
    		request.setAttribute("msg", 
    		"Thank You: " + item.getString());
    		
    	} else {
    // 該項(xiàng)目是一個(gè)上載的文件,把它保存到磁盤。
    // 注意item.getName()
    // 會(huì)返回上載文件在客戶端的完整路徑名稱,這似乎是一個(gè)BUG。
    // 為解決這個(gè)問題,這里使用了fullFile.getName()。
    		File fullFile  = new File(item.getName());  
    		File savedFile = new File
    		(getServletContext().getRealPath("/"),
    		fullFile.getName());
    		item.write(savedFile);
    	}
    }


      我們可以通過上載句柄的upload.setSizeMax來限制上載文件的大小。當(dāng)上載文件的大小超過允許的值時(shí),程序?qū)⒂龅疆惓!T谏厦娴睦又校募笮〉南拗浦凳?1,表示允許上載任意大小的文件。

      還有其他一些略有變化的使用形式,正如前面所指出的,我們可以在上載的文件上打開一個(gè)輸入流,或者讓它們駐留在內(nèi)存中直至空間占用達(dá)到一定的限制值,或者在判斷文件類型的基礎(chǔ)上,以String或Byte數(shù)組的形式獲取其內(nèi)容,或者直接刪除文件。這一切都只要使用FileItem類提供的方法就可以方便地做到(DefaultFileItem是FileItem的一個(gè)實(shí)現(xiàn))。
      3.2 HttpClient

      ■ 概況:這個(gè)API擴(kuò)展了java.net包,提供了模擬瀏覽器的功能。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:當(dāng)你要構(gòu)造Web瀏覽器的功能;當(dāng)你的應(yīng)用需要一種高效的辦法進(jìn)行HTTP/HTTPS通信時(shí)。

      ■ 示例應(yīng)用:HttpClientDemo.java。要求CLASSPATH中有commons-httpclient.jar,common-logging.jar。要求使用JDK 1.4或更高版本。

      ■ 說明:

      HttpClient擴(kuò)展和增強(qiáng)了標(biāo)準(zhǔn)java.net包,是一個(gè)內(nèi)容廣泛的代碼庫,功能極其豐富,能夠構(gòu)造出各種使用HTTP協(xié)議的分布式應(yīng)用,或者也可以嵌入到現(xiàn)有應(yīng)用,為應(yīng)用增加訪問HTTP協(xié)議的能力。在Commons穩(wěn)定版中,HttpClient的文檔似乎要比其他包更完善一些,而且還帶有幾個(gè)實(shí)例。下面我們通過一個(gè)簡(jiǎn)單的例子來了解如何提取一個(gè)Web頁面,HttpClient文檔中也有一個(gè)類似的例子,我們將擴(kuò)充那個(gè)例子使其支持SSL。注意本例需要JDK 1.4支持,因?yàn)樗玫絁ava Secure Socket Connection庫,而這個(gè)庫只有JDK 1.4及更高的版本才提供。

      ① 首先確定一個(gè)可以通過HTTPS下載的頁面,本例使用的是https://www.paypal.com/。同時(shí)確保%JAVA_HOME%/jre/lib/security/java.security文件包含了下面這行代碼:security.provider.2=com.sun.net.ssl.internal.ssl.Provider。

      除了這些設(shè)置之外,HTTPS連接的處理方式?jīng)]有其他特別的地方--至少對(duì)于本例來說如此。不過,如果遠(yuǎn)程網(wǎng)站使用的根證書不被你使用的Java認(rèn)可,則首先必須導(dǎo)入它的證書。

      ② 創(chuàng)建一個(gè)HttpClient的實(shí)例。HttpClient類可以看成是應(yīng)用的主驅(qū)動(dòng)程序,所有針對(duì)網(wǎng)絡(luò)的功能都依賴于它。HttpClient類需要一個(gè)Connection Manager來管理連接。HttpConnectionManager允許我們創(chuàng)建自己的連接管理器,或者,我們也可以直接使用內(nèi)建的SimpleHttpConnectionManager或MultiThreadedHttpConnectionManager類。如果在創(chuàng)建HttpClient時(shí)沒有指定連接管理器,HttpClient默認(rèn)使用SimpleHttpConnectionManager。

    // 創(chuàng)建一個(gè)HttpClient的實(shí)例
    HttpClient client = new HttpClient();


      ③ 創(chuàng)建一個(gè)HttpMethod的實(shí)例,即確定與遠(yuǎn)程服務(wù)器的通信要采用哪種傳輸方式,HTTP允許采用的傳輸方式包括:GET,POST,PUT,DELETE,HEAD,OPTIONS,以及TRACE。這些傳輸方式分別作為一個(gè)獨(dú)立的類實(shí)現(xiàn),但所有這些類都實(shí)現(xiàn)HttpMethod接口。在本例中,我們使用的是GetMethod,創(chuàng)建GetMethod實(shí)例時(shí)在參數(shù)中指定我們想要GET的URL。

    // 創(chuàng)建一個(gè)HttpMethod的實(shí)例
    HttpMethod method = new GetMethod(url);


      ④ 執(zhí)行HttpMethod定義的提取操作。執(zhí)行完畢后,executeMethod方法將返回遠(yuǎn)程服務(wù)器報(bào)告的狀態(tài)代碼。注意executeMethod屬于HttpClient,而不是HttpMethod。

    // 執(zhí)行HttpMethod定義的提取操作
    statusCode = client.executeMethod(method);


      ⑤ 讀取服務(wù)器返回的應(yīng)答。如果前面的連接操作失敗,程序?qū)⒂龅紿ttpException或IOException,其中IOException一般意味著網(wǎng)絡(luò)出錯(cuò),繼續(xù)嘗試也不太可能獲得成功。服務(wù)器返回的應(yīng)答可以按照多種方式讀取,例如作為一個(gè)字節(jié)數(shù)組,作為一個(gè)輸入流,或者作為一個(gè)String。獲得服務(wù)器返回的應(yīng)答后,我們就可以按照自己的需要任意處置它了。

    byte[] responseBody = method.getResponseBody();


      ⑥ 最后要做的就是釋放連接。

    method.releaseConnection();


      以上只是非常簡(jiǎn)單地介紹了一下HttpClient庫,HttpClient實(shí)際的功能要比本文介紹的豐富得多,不僅健壯而且高效,請(qǐng)參閱API文檔了解詳情。

      3.3 Net

      ■ 概況:一個(gè)用于操作Internet基礎(chǔ)協(xié)議的底層API。

      ■ 官方資源:主頁二進(jìn)制源代碼

      ■ 何時(shí)適用:當(dāng)你想要訪問各種Internet底層協(xié)議之時(shí)(Finger,Whois,TFTP,Telnet,POP3,F(xiàn)TP,NNTP,以及SMTP)。

      ■ 示例應(yīng)用:NetDemo.java。要求CLASSPATH中包含commons-net-1.0.0.jar。

      ■ 說明:

      Net包是一個(gè)強(qiáng)大、專業(yè)的類庫,類庫里的類最初屬于一個(gè)叫做NetComponents的商業(yè)產(chǎn)品。

      Net包不僅支持對(duì)各種低層次協(xié)議的訪問,而且還提供了一個(gè)高層的抽象。大多數(shù)情況下,Net包提供的抽象已能滿足一般需要,它使得開發(fā)者不再需要直接面對(duì)各種協(xié)議的Socket級(jí)的低層命令。使用高層抽象并不減少任何功能,Net API在這方面做得很出色,既提供了足夠的功能,又不至于在特色方面作過多的妥協(xié)。

      SocketClient是支持所有協(xié)議的基礎(chǔ)類,它是一個(gè)抽象類,聚合了各種協(xié)議都需要的公用功能。各種不同協(xié)議的使用過程其實(shí)很相似,首先利用connect方法建立一個(gè)指向遠(yuǎn)程服務(wù)器的連接,執(zhí)行必要的操作,最后終止與服務(wù)器的連接。下面通過實(shí)例介紹具體的使用步驟。

    // …
    // ① 創(chuàng)建一個(gè)客戶端。我們將用NNTPClient
    //  從新聞服務(wù)器下載新聞組清單。
    client = new NNTPClient();
    // …
    // ② 利用前面創(chuàng)建的客戶端連接到新聞服務(wù)器。
    //  這里選用的是一個(gè)新聞組較少的服務(wù)器。
    client.connect("aurelia.deine.net");
    // …
    // ③ 提取新聞組清單。下面的命令將返回一個(gè)
    //  NewsGroupInfo對(duì)象的數(shù)組。如果指定的服
    //  務(wù)器上不包含新聞組,返回的數(shù)組將是空的,
    //  如果遇到了錯(cuò)誤,則返回值是null。
    list = client.listNewsgroups();
    //...
    // ④ 最后終止與服務(wù)器的連接。
     if (client.isConnected())
       client.disconnect();


      必須說明的是,listNewsgroups命令可能需要較長(zhǎng)的時(shí)間才能返回,一方面是因?yàn)榫W(wǎng)絡(luò)速度的影響,另外也可能是由于新聞組清單往往是很龐大的。NewsGroupInfo對(duì)象包含有關(guān)新聞組的詳細(xì)信息,并提供了一些操作新聞組的命令,比如提取文章總數(shù)、最后發(fā)布的文章、發(fā)布文章的權(quán)限,等等。

      其他客戶端,例如FingerClient、POP3Client、TelnetClient等,用法也差不多。

      結(jié)束語:有關(guān)Web相關(guān)類和其他類的介紹就到此結(jié)束。在下一篇文章中,我們將探討XML類和包裝類,最后一篇文章則介紹工具類。

      希望讀者有興趣試試本文提供的程序?qū)嵗:芏鄷r(shí)候Jakarta Commons給人以混亂的感覺,希望本文使你加深了對(duì)Jakarta Commons了解,或者至少引起了你對(duì)Commons子項(xiàng)目以及它提供的各種實(shí)用API和庫的興趣。

    請(qǐng)從這里下載本文代碼:JakartaCommons1_code.zip

    posted on 2005-09-21 10:03 limq 閱讀(5069) 評(píng)論(0)  編輯  收藏 所屬分類: 編程技巧

    主站蜘蛛池模板: 亚洲s码欧洲m码吹潮| 亚洲韩国精品无码一区二区三区| 中文字幕人成无码免费视频| 中文免费观看视频网站| 18禁黄网站禁片免费观看不卡| 久久精品毛片免费观看| 永久免费在线观看视频| 很黄很黄的网站免费的| 无码永久免费AV网站| 精品国产麻豆免费网站| 全部免费毛片免费播放| 亚洲人成人网站在线观看| 亚洲一区二区三区自拍公司| 亚洲精品无码久久久影院相关影片 | 亚洲中文字幕久久精品蜜桃 | 亚洲无av在线中文字幕| 久久亚洲国产中v天仙www| 亚洲av最新在线网址| 亚洲精品国产情侣av在线| 亚洲AV无码一区二区三区在线| 亚洲熟女www一区二区三区| 毛片亚洲AV无码精品国产午夜| 黄色a级免费网站| 免费久久人人爽人人爽av| 精品一区二区三区无码免费视频 | 中文字幕免费在线看线人动作大片| 日韩电影免费在线观看网站| 99热在线精品免费播放6| 久久99九九国产免费看小说| 国产精品无码一区二区三区免费| 亚洲一区二区视频在线观看| 亚洲AV永久无码精品| 亚洲精品国产精品国自产网站| 爱情岛论坛亚洲品质自拍视频网站| 国产日韩精品无码区免费专区国产| 日本高清免费观看| 天天摸天天碰成人免费视频| 亚洲午夜av影院| 亚洲黄网在线观看| 国产精品亚洲专区无码不卡| 日韩免费高清播放器|