Jakarta Commons是Jakarta的一個(gè)子項(xiàng)目,目的是創(chuàng)建和維護(hù)獨(dú)立于其他框架和產(chǎn)品的程序包(packages)。這些程序包是一些服務(wù)于小范圍的有效組件的集合,通常適用于服務(wù)器端編程。

   Commons項(xiàng)目分為兩部分:Sandbox和Commons庫(kù)。Sandbox用于測(cè)試。本文關(guān)注庫(kù)組件,包括它們什么時(shí)候使用,在那里,以及用例子說(shuō)明如何使用。

簡(jiǎn)要介紹

  Jakarta Commons項(xiàng)目源于重用,其中的程序包必須確保能夠重用。有一些包來(lái)自于其他項(xiàng)目,例如通用日志包是Jakarta Struts的一部分。當(dāng)開(kāi)發(fā)者發(fā)現(xiàn)某個(gè)包對(duì)于其他項(xiàng)目很有用,可以縮短開(kāi)發(fā)周期,他們決定將這些包做成通用組件。這就是Jakarta Commons項(xiàng)目。

   要真正做到可重用,每個(gè)程序包必須獨(dú)立于其他較大的框架和項(xiàng)目。因此,Commons項(xiàng)目中的每個(gè)包在很大程度上是獨(dú)立的,不僅相對(duì)于其他項(xiàng)目,甚至對(duì)于其他包也是如此。違反這一原則的情況是存在的,但決大多數(shù)情況是使用成熟的APIs。例如,Betwixt包建立在XML APIs基礎(chǔ)之上。盡管這個(gè)項(xiàng)目的本意是建立不依賴其他組件的程序包。

   大多數(shù)程序包十分簡(jiǎn)潔,以至于缺少必要的文檔、維護(hù)和幫助。有些包甚至只有錯(cuò)誤的連接和極少的文檔。大多數(shù)情況下,你只能自己摸索如何使用它們,為什么使用它們。希望這篇文章對(duì)你有幫助。

    注意:Jakarta Commons與Apache Commons是不同的。后者是Apache Software Foundation(ASF)的頂級(jí)項(xiàng)目。而前者是ASF的另一個(gè)頂級(jí)項(xiàng)目Jakarta的子項(xiàng)目,是本文介紹的對(duì)象。而且,Jakarta Commons只使用Java。在本文中Commons指的是Jakarta Commons。

 
組件

    為了組織方便,我將18個(gè)(包括EL,Latka和Jexl)Commons組件分為五類(lèi)。如下表:

組件類(lèi)別
 組件
 
Web相關(guān)
 FileUpload,HTTPClient和Net
 
XML相關(guān)
 Betwixt,Digester,Jelly和JXPath
 
工具
 BeanUtils,Logging,DBCP,Pool和 Validator
 
打包
 Codec 和 Modeler
 
小程序
 CLI,Discovery,Lang和 Collections
 

       要注意的是這個(gè)分類(lèi)只是對(duì)本文而言,在Commons項(xiàng)目中是不存在的。在某種程度上分類(lèi)是重疊的。本文將介紹Web相關(guān)和小程序類(lèi),下篇文章包括XML相關(guān)和打包類(lèi),工具類(lèi)在最后一篇文章中。

小程序類(lèi)
     將CLI,Discovery,Lang和 Collections歸入小程序類(lèi)是因?yàn)樗鼈兌际菫榱艘粋€(gè)小而實(shí)用的目的編寫(xiě)的。

1.CLI

       概要:CLI(Command Line Interface)為你的Java程序提供讀取和解析命令行參數(shù)的通用接口。
     在那得到:主頁(yè),程序,源代碼。
     何時(shí)使用:需要統(tǒng)一操作命令行參數(shù)時(shí)。
     例子程序:CLIDemo.java,需要將commons-cli-1.0.jarcommons加入CLASSPATH中。
     描述:通常在完成一個(gè)Java程序時(shí)不得不重寫(xiě)應(yīng)用程序輸入?yún)?shù)的處理部分。如果有一個(gè)唯一的接口用來(lái)定義﹑解析和讀取輸入?yún)?shù),以決定程序的運(yùn)行方式不是很好嗎?CLI就是答案。
     對(duì)于CLI,命令行中每個(gè)要處理的參數(shù)都是一個(gè)Option。創(chuàng)建一個(gè)Options對(duì)象,將Option對(duì)象添加進(jìn)去,然后用CLI提供的函數(shù)解析用戶的輸入?yún)?shù)。一個(gè)Option也許也需要用戶輸入一個(gè)值,例如文件名。這時(shí)Option必須在指定處創(chuàng)建。
     CLI使用步驟如下:
     1.創(chuàng)建Options:
      Options options = new Options();
         Options.addOption(“t”,false,”current time”);

       2.創(chuàng)建解析器解析用戶輸入:
       CommandLineParser parser = new BasicParser();
           CommandLine cmd;
            try{
                     cmd = parser.parse(options, args);
                 } catch(ParseException pe) {
                     usage(options);
                     return;
              }

      3.根據(jù)用戶輸入執(zhí)行相應(yīng)操作:

              if(cmd.hasOption(“n”)) {
                     System.err.println(“Nice to meet you: ”+   cmd.getOptionvalue(‘n’));
}

       以上基本就是使用CLI的全過(guò)程。當(dāng)然,CLI提供其他高級(jí)選項(xiàng)用于控制各種格式和解析器,但基本操作是相同的。完整的例子可以看demo。

2.Discovery

       概要:discovery模式的實(shí)現(xiàn),提供定位與實(shí)例化類(lèi)或其他資源的通用方法。
       在那得到:主頁(yè),程序,源代碼。該包處于pre-release狀態(tài)。
       何時(shí)使用:需要快速找到你的代碼中Java接口的實(shí)現(xiàn)時(shí)。
       例子程序:DiscoveryDemo.java,MyInterface.java,MyImpl1.java,MyImpl2.java, MyInterface。需要將commons-discovery.jar和commons-logging.jar添到CLASSPATH中。

       描述:Discovery的目的是使用最好的算法得到接口的所有實(shí)現(xiàn)。當(dāng)用戶想找到所有的提供某一服務(wù)的提供商時(shí),這將特別有用。

       假設(shè)你寫(xiě)了一個(gè)針對(duì)某一難題的接口。這個(gè)接口的所有實(shí)現(xiàn)將以唯一的編碼方式解決這一難題。真正的用戶在實(shí)際解決這一難題時(shí)將會(huì)有多種選擇。他怎么才能知道接口的那種實(shí)現(xiàn)在他的系統(tǒng)中是可行的?

       這就是Service與Service Provider結(jié)構(gòu)。Service就是你定義的接口。Service Providers提供Service的實(shí)現(xiàn)。用戶需要選擇Service Providers。Discovery組件用多種方法提供幫助。注意Discovery不僅用于發(fā)現(xiàn)實(shí)現(xiàn)類(lèi),而且可以尋找資源,例如圖像或其他文件。它遵照Sun的Service Provider Architecture規(guī)范。

       同樣,Discovery的使用也很簡(jiǎn)單。例子程序中,MyImpl1和MyImpl2是MyInterface接口的實(shí)現(xiàn)。MyInterface文件必須在META-INF/services目錄下。注意這個(gè)文件必須對(duì)應(yīng)接口的全路徑。如果接口在包內(nèi),那么文件名也要相應(yīng)改動(dòng)。

       1.取得ClassLoader:

              ClassLoaders loaders =

ClassLoaders.getAppLoaders(MyInterface.class, getClass(), false);

       2.創(chuàng)建DiscoverClass用于查找實(shí)現(xiàn)類(lèi):

              DiscoverClass discover = new DiscoverClass(loaders);

       3.查找實(shí)現(xiàn)類(lèi):

              Class implClass = discover.find(MyInterface.class);

              System.err.println("Implementing Provider: " + implClass.getName());

       運(yùn)行以上代碼(DiscoveryDemo.java)將得到MyInterface文件中注冊(cè)的類(lèi),如下所示。再次提醒,如果實(shí)現(xiàn)包含在一個(gè)包結(jié)構(gòu)內(nèi),文件名必須做相應(yīng)的修改。如果這個(gè)文件不在規(guī)定目錄下,或?qū)崿F(xiàn)類(lèi)不能實(shí)例化或定位,將拋出DiscoveryException異常,表明找不到MyInterface的實(shí)現(xiàn)。

       MyImpl2 # Implementation 2

       當(dāng)然,這不是注冊(cè)實(shí)現(xiàn)的唯一方法,否則Discovery還有什么用!事實(shí)上,這是Discovery發(fā)現(xiàn)類(lèi)的內(nèi)部機(jī)制的最后一步。其他方法包括在系統(tǒng)屬性或用戶屬性中定義實(shí)現(xiàn)類(lèi)的名字。例如,刪除META-INF/services目錄下的文件,按以下輸入運(yùn)行demo,結(jié)果相同。這里系統(tǒng)屬性是接口名,而值是接口實(shí)現(xiàn)提供者。

       java -DMyInterface=MyImpl1 DiscoveryDemo

       Discovery也可用于創(chuàng)建(單例)服務(wù)提供者的實(shí)例并調(diào)用它們的函數(shù)。如下:

       ((MyInterface)discover.newInstance(MyInterface.class)).myMethod();

       注意此時(shí)我們并不知道那個(gè)服務(wù)提供者實(shí)現(xiàn)myMethod函數(shù),我們也不關(guān)心。這個(gè)函數(shù)的實(shí)現(xiàn)取決于以何種方式運(yùn)行以上代碼以及注冊(cè)的服務(wù)提供者。

3.Lang

       概要:java.lang包的擴(kuò)展,增加許多對(duì)String的操作。提供類(lèi)C語(yǔ)言的枚舉。

       在那得到:主頁(yè),程序,源代碼。這里介紹的是Lang1.0,翻譯本文時(shí)Lang2.0已經(jīng)發(fā)布。

       何時(shí)使用:當(dāng)對(duì)java.lang提供的默認(rèn)實(shí)現(xiàn)感到厭煩,想更好的控制String的操作,數(shù)值函數(shù)以及系統(tǒng)屬性時(shí),還有,想使用C語(yǔ)言風(fēng)格的枚舉時(shí)。

       例子程序:LangDemo.java, Mortgage.java, OnTV.java。需要將commons-lang.jar加入CLASSPATH中。

       描述:這個(gè)包中提供的很多工具函數(shù)可以簡(jiǎn)化Java程序員的工作。這些函數(shù)可以減少實(shí)現(xiàn)日常功能的編程量。特別是StringUtils類(lèi),它提供比標(biāo)準(zhǔn)的java.lang.String包更強(qiáng)的操作字符串的功能。它們的使用十分簡(jiǎn)單,只要用正確的參數(shù)調(diào)用一個(gè)靜態(tài)函數(shù)。例如,要將一句話變?yōu)橐源髮?xiě)開(kāi)頭只要:

       StringUtils.capitalise("name");

       這個(gè)函數(shù)的輸出就象我們需要的“Name”。瀏覽StringUtils API的其他靜態(tài)函數(shù),你可能會(huì)發(fā)現(xiàn)對(duì)你有用的。例子程序中使用了一些。

       另一個(gè)有趣的類(lèi)是RandomStringUtils。這個(gè)類(lèi)中的函數(shù)產(chǎn)生隨機(jī)字符串,這在生成隨機(jī)密碼時(shí)很有用。

       類(lèi)NumberUtils提供數(shù)據(jù)操作的函數(shù),包括最大最小值函數(shù),以及將字符串轉(zhuǎn)換為數(shù)字的函數(shù)。NumberRange和CharRange分別處理數(shù)字與字符的范圍。

       Builder包中的類(lèi)提供為類(lèi)添加toString,hashCode,compareTo和equals函數(shù)的功能。也就是說(shuō),自己不需編碼就可以在類(lèi)中添加高質(zhì)量的toString,hashCode,compareTo和equals函數(shù),只要使用Builder包中的函數(shù)就可以了。例如,用ToStringBuilder函數(shù)給類(lèi)添加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();
               }
}
       為什么使用這個(gè)函數(shù)那?因?yàn)樗褂猛ㄓ玫姆椒ㄌ幚硭械臄?shù)據(jù)類(lèi)型,恰當(dāng)?shù)姆祷豱ull,同時(shí)可以控制對(duì)象和聚集的細(xì)節(jié)層次。這對(duì)于所有builder中的函數(shù)有效,而且語(yǔ)法同上所示相近。

       作為一個(gè)Java程序員,如果你懷念C語(yǔ)言風(fēng)格的枚舉,那么這個(gè)包中的類(lèi)型安全的Enum數(shù)據(jù)類(lèi)型將填補(bǔ)這一空白。Enum類(lèi)是抽象類(lèi),所以要?jiǎng)?chuàng)建自己的枚舉,必須擴(kuò)展這個(gè)類(lèi)。如下例所示:

       1.定義并擴(kuò)展枚舉類(lèi):

              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);

       }

}

       2.現(xiàn)在就可以在你的方法中使用枚舉了:

       OnTV.getEnum("Idol");

       該行代碼從我們創(chuàng)建的枚舉數(shù)據(jù)類(lèi)型中返回Idol項(xiàng)。Enum類(lèi)還有其他有用的函數(shù)。

4.Collections

       概要:對(duì)Java Collection框架的擴(kuò)展,加入了新的數(shù)據(jù)結(jié)構(gòu),iterators和比較器。

       在那得到:主頁(yè),程序,源代碼。

       何時(shí)使用:強(qiáng)烈建議在需要處理數(shù)據(jù)結(jié)構(gòu)的Java項(xiàng)目盡可能使用Collections API,從中你會(huì)獲得比Java默認(rèn)實(shí)現(xiàn)大的多的好處。

       例子程序:CollectionsDemo.java。需要將commons-collections.jar加入CLASSPATH中。

       描述:Collections API中有很多類(lèi),很難在一節(jié)中全介紹出來(lái)。所以這里我著重介紹最重要的類(lèi),希望你能感興趣去仔細(xì)研究其他類(lèi)。API附帶的文檔對(duì)每個(gè)類(lèi)都有詳細(xì)的描述。

       Bag接口擴(kuò)展了Java Collections,加入了對(duì)所有成員的計(jì)數(shù),它在要統(tǒng)計(jì)進(jìn)入進(jìn)出元素?cái)?shù)時(shí)很有用。因?yàn)锽ag是一個(gè)接口,所以實(shí)際使用的是它的實(shí)現(xiàn)類(lèi),如HashBag或TreeBag。顧名思義,HashBag是基于HashMap的Bag的實(shí)現(xiàn),而Treebag是基于TreeMap的。Bag接口中的兩個(gè)重要方法是getCount(Object o)和uniqueSet()。前者返回Bag中某特殊元素的個(gè)數(shù),后者返回Bag中的唯一元素(譯者理解為:元素類(lèi)型,原文:the unique elements)的集合。

       Buffer接口允許按照預(yù)定順序從聚集中刪除對(duì)象,可以是后進(jìn)先出,先進(jìn)先出,或自定義的順序。下面的例子演示了如何以自然排序的順序刪除元素的:

       1.BinaryHeap類(lèi)實(shí)現(xiàn)Buffer接口,并按自然排序刪除元素。若想以反自然排序刪除,以false為參數(shù)即可:

       BinaryHeap heap = new BinaryHeap();

       2.添加元素:

       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));

3.調(diào)用remove方法。按自然排序,-10將被刪除,反之5被刪除:

heap.remove();

       FastArrayList﹑FastHashMap和FastTreeMap類(lèi)使用兩種模式操作相應(yīng)的Collection類(lèi)。第一種為慢模式,是這些類(lèi)初始化后的默認(rèn)模式。在慢模式下,這些類(lèi)的結(jié)構(gòu)變化是同步的。在快模式下,對(duì)這些類(lèi)的訪問(wèn)被認(rèn)為是只讀的,因此更快一些,而且不發(fā)生同步。在快模式下要改變類(lèi)的結(jié)構(gòu),要先克隆該類(lèi),在克隆類(lèi)上修改,然后覆蓋該類(lèi)。這些類(lèi)在多數(shù)訪問(wèn)為只讀的多線程環(huán)境中十分有用。

       Iterator包提供了許多常規(guī)Java Collections包中沒(méi)有的聚集和對(duì)象的iterator。例子程序中演示了iterator數(shù)組的ArrayIterator。這些iterator同普通Java iterators的用法相同。

       最后,comparator包中提供了一些有用的比較器,它們用來(lái)定義比較和決定同一類(lèi)的兩個(gè)對(duì)象的順序。例如,在我們前面提到的Buffer中,可以定義自己比較器,用它替代自然排序決定順序。如下:

       1.這次使用NullComparator創(chuàng)建BinaryHeap。NullComparator根據(jù)標(biāo)志nullAreHigh的值決定null與其他對(duì)象的大小。如果取值為false,表示null比其他對(duì)象小:

       BinaryHeap heap2 = new BinaryHeap(new NullComparator(false));

       2.添加對(duì)象,包括一些null

       heap2.add(null);

heap2.add(new Integer("6"));

heap2.add(new Integer("-6"));

heap2.add(null);

       3.最后,執(zhí)行刪除操作。因?yàn)閚ull小于其他對(duì)象,Bag最后剩下的是null

       heap2.remove();

       到這里,小程序類(lèi)就介紹完了。更多的細(xì)節(jié)請(qǐng)看API文檔,或者這些包的源代碼。

 

Web相關(guān)類(lèi)

       Web相關(guān)類(lèi)中組件幫助Java程序員完成Web相關(guān)的任務(wù)。

1.FileUpload

       概要:現(xiàn)成的文件上傳組件。

       在那得到:主頁(yè)。

       何時(shí)使用:當(dāng)Java服務(wù)器環(huán)境中需要簡(jiǎn)單易用并且高效的文檔上傳組件時(shí)。

       例子程序:fileuploaddemo.jsp,fileuploaddemo.htm,msg.jsp。需要將commons-fileupload-1.0-dev.jar添加到程序的WEB-INF/lib目錄下。

       描述:FileUpload解決了文件上傳時(shí)服務(wù)端的常見(jiàn)問(wèn)題,提供了一個(gè)控制文件上傳的易用的接口,可用在JSP頁(yè)和servlet中。它符合RFC1867協(xié)議標(biāo)準(zhǔn),解析輸入請(qǐng)求,并將上傳到服務(wù)器的一系列文件的分塊交給應(yīng)用程序。上傳的文件保存在內(nèi)存中或臨時(shí)目錄中(這由一個(gè)表示文件大小的參數(shù)決定,如果上傳的文件大小超過(guò)該參數(shù)值,文件將被寫(xiě)入臨時(shí)目錄)。你也可以設(shè)置其他參數(shù),例如可接收的文件的最大尺寸以及臨時(shí)文件目錄。

       FileUpload的使用分為幾步,我將用一個(gè)在一個(gè)頁(yè)中同時(shí)上傳兩個(gè)不同文件的例子說(shuō)明。

       1.創(chuàng)建HTML頁(yè)。注意為了確保上傳文件的類(lèi)型是被允許的,enctype參數(shù)必須為multipart/form-data,請(qǐng)求參數(shù)method必須為POST。還有一點(diǎn)要注意的是該頁(yè)面不但有兩個(gè)文件控件還有一個(gè)普通文本控件。

       <form name="myform" action="fileuploaddemo.jsp" 

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

    Specify your name:<br />

         <input type="text" name="name" size="15"/><br />

    Specify your Image:<br />

         <input type="file" name="myimage"><br/>

    Specify your file&:<br />

         <input type="file" name="myfile"><br /><br />

           <input type="submit" name="Submit" value="Submit your files"/>

</form>

2.創(chuàng)建JSP頁(yè)。

       a.檢查輸入請(qǐng)求是不是多段數(shù)據(jù)。

              boolean isMultipart = FileUpload.isMultipartContent(request);

       b.創(chuàng)建請(qǐng)求處理器,解析請(qǐng)求,結(jié)果存于一個(gè)list中。

              DiskFileUpload upload = new DiskFileUpload();

List items = upload.parseRequest(request);

c.遍歷這個(gè)list訪問(wèn)每個(gè)單獨(dú)的文件項(xiàng)。用isFormField()函數(shù)區(qū)分上傳文件和常規(guī)類(lèi)型域。根據(jù)需要,可以逐字節(jié)的讀取上傳的文件,或者使用輸入流。

       Iterator itr = items.iterator();

 

while(itr.hasNext()) {

   FileItem item = (FileItem) itr.next();

        

   // check if the current item is a form field or an uploaded file

   if(item.isFormField()) {

            

   // get the name of the field

   String fieldName = item.getFieldName();

   

   // if it is name, we can set it in request to thank the user

   if(fieldName.equals("name"))

          request.setAttribute("msg", "Thank You: " + item.getString());

          

   } else {

 

          // the item must be an uploaded file save it to disk. Note that there

          // seems to be a bug in item.getName() as it returns the full path on

          // the client's machine for the uploaded file name, instead of the file

          // name only. To overcome that, I have used a workaround using

          // fullFile.getName().

          File fullFile  = new File(item.getName());  

          File savedFile = new File(getServletContext().getRealPath("/"),

          fullFile.getName());

          item.write(savedFile);

   }

}

       可以在上傳處理器中用upload.setSizeMax限制上傳文件的最大尺寸,當(dāng)上傳文件大小超過(guò)該尺寸將會(huì)拋出異常。上例中,若將該尺寸設(shè)為-1,就可以上傳任何大小的文件。

       這個(gè)例子還可以有一個(gè)小變化。想上面提到的,可以使用輸入流上傳文件。過(guò)程是將上傳的內(nèi)容駐留在內(nèi)存中直到某一閾值,取得內(nèi)容的類(lèi)型,把它們存為字符串或字節(jié)數(shù)組,最后從內(nèi)存中刪除。FileItem中函數(shù)完成了該過(guò)程(DefaultFileItem是它的實(shí)現(xiàn))。

2.HttpClient

       概要:擴(kuò)展java.net包,提供類(lèi)似瀏覽器的功能。

       在那得到:主頁(yè),程序,源代碼。源代碼和程序?yàn)閎eta1版。

       何時(shí)使用:當(dāng)要實(shí)現(xiàn)Web瀏覽器時(shí),或你的程序需要有效的控制HTTP/HTTPS連接時(shí)。

       例子程序:HttpClientDemo.java。需要將commons-httpclient.jar和common-logging.jar加入CLASSPATH中,JDK為1.4或更高版本。

       描述:HttpClient是java.net的擴(kuò)展程序包,它提供許多函數(shù)幫助你創(chuàng)建基于HTTP協(xié)議的各種分布式應(yīng)用或者嵌入應(yīng)用程序處理HTTP操作。這個(gè)庫(kù)提供比Commons的其他包更詳細(xì)的文檔,并附帶很多例子。這里將講解怎樣開(kāi)發(fā)一個(gè)提取Web網(wǎng)頁(yè)的程序。HttpClient附帶的文檔中有一個(gè)類(lèi)似的例子,我將擴(kuò)展它使它支持SSL。注意這個(gè)例子必須運(yùn)行于JDK 1.4或更高版本上,因?yàn)樗枰狫DK1.4中的Java Secure Socket Connection庫(kù)。

       1.找一個(gè)可以通過(guò)HTTPS下載的網(wǎng)頁(yè),例如https://www.paypal.com/。確保文件%JAVA_HOME%/jre/lib/security/java.security有類(lèi)似如下的一行:

       security.provider.2=com.sun.net.ssl.internal.ssl.Provider

       這樣,至少在你的程序中處理HTTPS連接的方式是沒(méi)有區(qū)別的。如果遠(yuǎn)端的站點(diǎn)需要驗(yàn)證,那么你必須做相應(yīng)的配置。

       2.創(chuàng)建HttpClient類(lèi)的一個(gè)實(shí)例,所有的函數(shù)都將用到它。這個(gè)類(lèi)包含一個(gè)連接管理器操作實(shí)際的連接。HttpConnectionManager接口允許你創(chuàng)建自己的管理器,否則可以使用內(nèi)建的SimpleHttpConnectionManager或MultiThreadedHttpConnectionManager。如果無(wú)參數(shù)創(chuàng)建HttpClient,那么默認(rèn)連接管理器為SimpleHttpConnectionManager。

       HttpClient client = new HttpClient();

       3.創(chuàng)建一個(gè)method實(shí)例,用來(lái)定義使用那種HTTP方法與遠(yuǎn)端站點(diǎn)傳遞信息,可以選擇的方法有GET, POST, PUT, DELETE, HEAD, OPTIONS和TRACE。這些method類(lèi)是HttpMethod接口的不同實(shí)現(xiàn)。在這個(gè)例子中使用GetMethod,創(chuàng)建時(shí)將要GET的URL作為參數(shù)。

       HttpMethod method = new GetMethod(url);

       4.連接這個(gè)URL,也就是用剛才定義的方法連接URL。這個(gè)方法將返回server返回的狀態(tài)碼。注意executeMethod是client的函數(shù)而不是method的。

       statusCode = client.executeMethod(method);

       5.讀取服務(wù)器的返回。如果連接失敗,將拋出HttpException或IOException異常。IOException異常說(shuō)明是網(wǎng)絡(luò)出了問(wèn)題,重試也不會(huì)成功。返回值可以字節(jié)數(shù)組﹑輸入流或字符串的格式讀取。這樣,就可以隨意處理輸入了。

       byte[] responseBody = method.getResponseBody();

       6.最后,釋放連接,使之在需要時(shí)可重用。

       method.releaseConnection();

       這時(shí)一個(gè)關(guān)于HttpClient庫(kù)的很粗略的介紹,它還有很多功能,十分健壯。

3.Net

       概要:基本Internet協(xié)議的底層API。

       在那得到:主頁(yè),程序,源代碼。

       何時(shí)使用:當(dāng)在Java應(yīng)用程序中需要Internet協(xié)議的底層互連時(shí)。

       例子程序:NetDemo.java。需要將commons-net-1.0.0.jar加入CLASSPATH中。

       描述:Net包是很多健壯的和專(zhuān)業(yè)的類(lèi)的集合。這些類(lèi)來(lái)自于一個(gè)叫做NetComponents的商業(yè)產(chǎn)品的一部分。

       Net包中的類(lèi)既提供對(duì)協(xié)議的底層訪問(wèn)也有高層的抽象。在大多數(shù)情況下,抽象是足夠的,它可以使你不必編寫(xiě)解析各種協(xié)議的底層套接字的代碼。使用抽象不會(huì)損失任何功能。

       SocketClient是所有協(xié)議的基類(lèi),它是一個(gè)抽象類(lèi)包含所有協(xié)議的共同功能。各種協(xié)議的使用方法是很相近的:首先使用connect方法建立與遠(yuǎn)端服務(wù)器的連接,執(zhí)行服務(wù),最后斷開(kāi)連接。讓我們通過(guò)例子來(lái)看:

       1.創(chuàng)建一個(gè)client。我們將使用一個(gè)NNTPClient從新聞服務(wù)器上下載新聞組列表。

              client = new NNTPClient();

       2.連接服務(wù)器,我用的是新聞組列表較短的服務(wù)器。

              client.connect("aurelia.deine.net");

       3.提取新聞組列表。如下的命令返回NewsGroupInfo數(shù)組。如果服務(wù)器上沒(méi)有新聞組則數(shù)組為空,出錯(cuò)則返回null。注意當(dāng)新聞組列表很大時(shí),這個(gè)命令會(huì)花很長(zhǎng)時(shí)間。每個(gè)NewsGroupInfo對(duì)象包含關(guān)于新聞組的詳細(xì)信息,有公用函數(shù)可以解析它們(如文章數(shù),最后發(fā)表的文章,發(fā)表權(quán)限等)。

              list = client.listNewsgroups();

       4.最后,斷開(kāi)與服務(wù)器的連接。

              if (client.isConnected())

                                   client.disconnect();

       其余的client如FingerClient, POP3Client, TelnetClient等用法相似。

結(jié)束語(yǔ)

       這篇文章介紹了Web相關(guān)和小程序類(lèi),下篇文章包括XML相關(guān)和打包類(lèi),工具類(lèi)在最后一篇文章中。

       希望你能從這篇文章的例子得到收獲。最后,我希望這篇文章能夠激起你對(duì)Commons子項(xiàng)目的興趣。