原文引自:
http://linux.ccidnet.com/art/322/20030805/57869_1.html作者:Vikram Goyal;仙人掌工作室譯 來源:賽迪網 發布時間:2003.08.05Jakarta Commons是Jakarta的子項目,它創建和維護著許多獨立軟件包,這些包一般與其他框架或產品無關,其中收集了大量小型、實用的組件,大部分面向服務器端編程。
Commons的包分成兩部分:Sandbox,Commons代碼庫。Sandbox是一個測試平臺,用來檢驗各種設想、計劃。本文介紹的組件屬于Commons代碼庫,文章將展示各個組件的功能、適用場合,并通過簡單的例子介紹其用法。
一、概述
可重用性是Jakarta Commons項目的靈魂所在。這些包在設計階段就已經考慮了可重用性問題。其中一些包,例如Commons里面用來記錄日志的Logging包,最初是為其他項目設計的,例如Jakarta Struts項目,當人們發現這些包對于其他項目也非常有用,能夠極大地幫助其他項目的開發,他們決定為這些包構造一個"公共"的存放位置,這就是Jakarta Commons項目。
為了真正提高可重用性,每一個包都必須不依賴于其他大型的框架或項目。因此,Commons項目的包基本上都是獨立的,不僅是相對于其他項目的獨立,而且相對于Commons內部的大部分其他包獨立。雖然存在一些例外的情況,例如Betwixt包要用到XML API,但絕大部分只使用最基本的API,其主要目的就是要能夠通過簡單的接口方便地調用。
不過由于崇尚簡潔,許多包的文檔變得過于簡陋,缺乏維護和支持,甚至有一部分還有錯誤的鏈接,文檔也少得可憐。大部分的包需要我們自己去找出其用法,甚至有時還需要我們自己去分析其適用場合。本文將逐一介紹這些包,希望能夠幫助你迅速掌握這一積累了許多人心血的免費代碼庫。
說明:Jakarta Commons和Apache Commons是不同的,后者是Apache Software Foundation的一個頂層項目,前者則是Jakarta項目的一個子項目,同是也是本文要討論的主角。本文后面凡是提到Commons的地方都是指Jakarta的Commons。
為了便于說明,本文把Commons項目十八個成品級的組件(排除了EL、Latka和Jexl)分成5類,如下表所示。

必須指出的是,這種分類只是為了方便文章說明,Commons項目里面實際上并不存在這種分類,同時這些分類的邊界有時也存在一定的重疊。
本文首先介紹Web相關類和其他類里面的組件,下一篇文章將涉及XML相關、包裝這兩類,最后一篇文章專門介紹屬于工具類的包。
二、其他類
CLI、Discovery、Lang和Collections包歸入其他類,這是因為它們都各自針對某個明確、實用的小目標,可謂專而精。
2.1 CLI
■ 概況:CLI即Command Line Interface,也就是"命令行接口",它為Java程序訪問和解析命令行參數提供了一種統一的接口。
■ 官方資源:主頁,二進制,源代碼
■ 何時適用:當你需要以一種一致的、統一的方式訪問命令行參數之時。
■ 示例應用:CLIDemo.java。CLASSPATH中必須包含commons-cli-1.0.jar。
■ 說明:
有多少次你不得不為一個新的應用程序重新設計新的命令行參數處理方式?如果能夠只用某個單一的接口,統一完成諸如定義輸入參數(是否為強制參數,數值還是字符串,等等)、根據一系列規則分析參數、確定應用要采用的路徑等任務,那該多好!答案就在CLI。
在CLI中,每一個想要在命令中指定的參數都是一個Option對象。首先創建一個Options對象,將各個Option對象加入Options對象,然后利用CLI提供的方法來解析用戶的輸入參數。Option對象可以要求用戶必須輸入某個參數,例如必須在命令行提供文件名字。如果某個參數是必須的,創建Option對象的時候就要顯式地指定。
下面是使用CLI的步驟。
// …
// ① 創建一個Options:
Options options = new Options();
options.addOption("t", false, "current time");
// …
// ② 創建一個解析器,分析輸入:
CommandLineParser parser = new BasicParser();
CommandLine cmd;
try {
cmd = parser.parse(options, args);
} catch (ParseException pe) {
usage(options);
return;
}
// …
// ③ 最后就可以根據用戶的輸入,采取相應的操作:
if (cmd.hasOption("n")) {
System.err.println("Nice to meet you: " +
cmd.getOptionValue('n'));
} |
這就是使用CLI的完整過程了。當然,CLI還提供了其他高級選項,例如控制格式和解析過程等,但基本的使用思路仍是一致的。請參見本文最后提供的示例程序。
2.2 Discovery
■ 概況:Discovery組件是發現模式(Discovery Pattern)的一個實現,它的目標是按照一種統一的方式定位和實例化類以及其他資源。
■ 官方資源:主頁,二進制,源代碼。
■ 何時適用:當你想用最佳的算法在Java程序中查找Java接口的各種實現之時。
■ 應用實例:DiscoveryDemo.java,MyInterface.java,MyImpl1.java,MyImpl2.java,MyInterface。要求CLASSPATH中必須包含commons-discovery.jar和commons-logging.jar。
■ 說明:
Discovery的意思就是"發現",它試圖用最佳的算法查找某個接口的所有已知的實現。在使用服務的場合,當我們想要查找某個服務的所有已知的提供者時,Discovery組件尤其有用。
考慮一下這種情形:我們為某個特別復雜的任務編寫了一個接口,所有該接口的實現都用各不相同的方式來完成這個復雜任務,最終用戶可以根據需要來選擇完成任務的具體方式。那么,在這種情形下,最終用戶應該用什么辦法來找出接口的所有可用實現(即可能的完成任務的方式)呢?
上面描述的情形就是所謂的服務-服務提供者體系。服務的功能由接口描述,服務提供者則提供具體的實現。現在的問題是最終用戶要用某種辦法來尋找系統中已經安裝了哪些服務提供者。在這種情形下,Discovery組件就很有用了,它不僅可以用來查找那些實現了特定接口的類,而且還可以用來查找資源,例如圖片或其他文件等。在執行這些操作時,Discovery遵從Sun的服務提供者體系所定義的規則。
由于這個原因,使用Discovery組件確實帶來許多方便。請讀者參閱本文后面示例程序中的接口MyInterface.java和兩個實現類MyImpl1.java、MyImple2.java,了解下面例子的細節。在使用Discovery的時候要提供MyInterface文件,把它放入META-INF/services目錄,注意該文件的名字對應接口的完整限定名稱(Fully Qualified Name),如果接口屬于某個包,該文件的名字也必須相應地改變。
// …
// ① 創建一個類裝入器的實例。
ClassLoaders loaders =
ClassLoaders.getAppLoaders(MyInterface.class, getClass(), false);
// …
// ② 用DiscoverClass的實例來查找實現類。
DiscoverClass discover = new DiscoverClass(loaders);
// …
// ③ 查找實現了指定接口的類:
Class implClass = discover.find(MyInterface.class);
System.err.println("Implementing Provider: " + implClass.getName()); |
運行上面的代碼,就可以得到在MyInterface文件中注冊的類。再次提醒,如果你的實現是封裝在包里面的,在這里注冊的名字也應該作相應地修改,如果該文件沒有放在正確的位置,或者指定名字的實現類不能找到或實例化,程序將拋出DiscoverException,表示找不到符合條件的實現。下面是MyInterface文件內容的一個例子:MyImpl2 # Implementation 2。
當然,實現類的注冊辦法并非只有這么一種,否則的話Discovery的實用性就要大打折扣了!實際上,按照Discovery內部的類查找機制,按照這種方法注冊的類將是Discovery最后找到的類。另一種常用的注冊方法是通過系統屬性或用戶定義的屬性來傳遞實現類的名字,例如,放棄META-INF/services目錄下的文件,改為執行java -DMyInterface=MyImpl1 DiscoveryDemo命令來運行示例程序,這里的系統屬性是接口的名字,值是該接口的提供者,運行的結果是完全一樣的。
Discovery還可以用來創建服務提供者的(singleton)實例并調用其方法,語法如下:((MyInterface)discover.newInstance(MyInterface.class)).myMethod();。注意在這個例子中,我們并不知道到底哪一個服務提供者實現了myMethod,甚至我們根本不必關心這一點。具體的情形與運行這段代碼的方式以及運行環境中已經注冊了什么服務提供者有關,在不同的環境下運行,實際得到的服務提供者可能不同。
2.3 Lang
■ 概況:Lang是java.lang的一個擴展包,增加了許多操作String的功能,另外還支持C風格的枚舉量。
■ 官方資源:主頁,二進制,源代碼。
■ 何時適用:當java.lang包提供的方法未能滿足需要,想要更多的功能來處理String、數值和System屬性時;還有,當你想要使用C風格的枚舉量時。
■ 示例應用:LangDemo.java,Mortgage.java,OnTV.java。CLASSPATH中必須包含commons-lang.jar。
■ 說明:
這個包提供了許多出于方便目的而提供的方法,它們中的大多數是靜態的,簡化了日常編碼工作。StringUtils類是其中的一個代表,它使得開發者能夠超越標準的java.lang.String包來處理字符串。使用這些方法很簡單,通常只要在調用靜態方法時提供適當的參數就可以了。例如,如果要將某個單詞的首字符改為大寫,只需調用:StringUtils.capitalise("name"),調用的輸出結果是Name。請瀏覽StringUtils API文檔了解其他靜態方法,也許你會找到一些可以直接拿來使用的代碼。本文提供的示例程序示范了其中一些方法的使用。
另一個值得注意的類是RandomStringUtils,它提供了生成隨機字符串的方法,用來創建隨機密碼實在太方便了。
NumberUtils類提供了處理數值數據的方法,許多方法值得一用,例如尋找最大、最小數的方法,將String轉換成數值的方法,等等。NumberRange和CharRange類分別提供了創建和操作數值范圍、字符范圍的方法。
Builder包里的類提供了一些特殊的方法,可用來構造類的toString、hashCode、compareTo和equals方法,其基本思路就是構造出類的高質量的toString、hashCode、compareTo和equals方法,從而免去了用戶自己定義這些方法之勞,只要調用一下Builder包里面的方法就可以了。例如,我們可以用ToStringBuilder來構造出類的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();
}
} |
使用這類方法有什么好處呢?顯然,它使得我們有可能通過一種統一的方式處理所有數據類型。所有Builder方法的用法都和上例相似。
Java沒有C風格的枚舉量,為此,lang包提供了一個類型安全的Enum類型,填補了空白。Enum類是抽象的,如果你要創建枚舉量,就要擴展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")。該調用從前面創建的枚舉數據類型返回Idol。這個例子比較簡單,實際上Enum類還提供了許多有用的方法,請參見本文后面提供的完整實例。
2.4 Collections
■ 概況:擴展了Java Collection框架,增添了新的數據結構、迭代機制和比較操作符。
■ 官方資源:主頁,二進制,源代碼。
■ 何時適用:幾乎所有需要操作數據結構的重要Java開發項目都可以使用Collections API。和Java的標準實現相比,Collections API有著諸多優勢。
■ 示例應用:CollectionsDemo.java。要求CLASSPATH中包含commons-collections.jar。
■ 說明:
要在有限的文章篇幅之內詳盡地介紹 Collections API實在是太困難了,不過這里仍將涵蓋大多數最重要的類,希望能夠引起你的興趣,認真了解一下其余的類。Collections本身的文檔也提供了許多資料并解釋了每一個類的用法。
Bag接口擴展標準的Java Collection,允許生成計數器來跟蹤Bag里面的所有元素。當你想要跟蹤進出某個集合的元素的總數時,Bag是非常有用的。由于Bag本身是一個接口,所以實際使用的應該是實現了該接口的類,例如HashBag或TreeBag--從這些類的名字也可以看出,HashBag實現的是一個HashMap的Bag,而TreeBag實現的是TreeMap的Bag。Bag接口中兩個最重要的方法是:getCount(Object o),用來返回Bag里面特定對象的出現次數;uniqueSet(),返回所有唯一元素。
Buffer接口允許按照預定義的次序刪除集合中的對象,刪除次序可以是LIFO(Last In First Out,后進先出),或FIFO(First In First Out,先進先出),另外還可以是自定義的次序。下面來看看如何實現一個Buffer,按照自然次序刪除元素。
BinaryHeap類實現了Buffer接口,能夠按照自然次序刪除元素。如果要顛倒次序,則必須傳入一個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));
//…
// 刪除一個元素
heap.remove(); |
調用該Heap的remove,按照自然次序,元素集合中的-10將被刪除。如果我們要求按照逆序排序,則被刪除的將是5。
FastArrayList、FastHashMap和FastTreeMap類能夠按照兩種模式操作,超越了與它們對應的標準Collection。第一種模式是"慢模式",類的修改操作(添加、刪除元素)是同步的。與此相對,另一種模式是"快模式",對這些類的訪問假定為只讀操作,因此不需要同步,速度較快。在快模式中,結構性的改動通過下列方式完成:首先克隆現有的類,修改克隆得到的類,最后用克隆得到的類替換原有的類。FastArrayList、FastHashMap和FastTreeMap類特別適合于那種初始化之后大部分操作都是只讀操作的多線程環境。
iterators包為各種集合和對象提供標準Java Collection包沒有提供的迭代器。本文的示例應用示范了ArrayIterator,通過迭代方式訪問Array的內容。iterators包里面各種迭代器的用法基本上與標準Java迭代器一樣。
最后,comparators包提供了一些實用的比較符。所謂比較符其實也是一個類,它定義的是如何比較兩個屬于同一類的對象,決定它們的排序次序。例如,在前面提到的Buffer類中,我們可以定義自己的比較符,用自定義的比較符來決定元素的排序次序,而不是采用元素的自然排序次序。下面來看看具體的實現經過。
// …
// ① 創建一個BinaryHeap類,但這一次參數中
// 指定NullComparator。NullComparator比較
// null與其他對象,根據nullsAreHigh標記來
// 判斷null值比其他對象大還是小:如果
// nullsAreHigh的值是false,則認為null要比
// 其他對象小。
BinaryHeap heap2 = new BinaryHeap
(new NullComparator(false));
// …
// ② 將一些數據(包括幾個null值)加入heap:
heap2.add(null);
heap2.add(new Integer("6"));
heap2.add(new Integer("-6"));
heap2.add(null);
// …
// ③ 最后刪除一個元素,Bag包含的null將減少
// 一個,因為null要比其他對象小。
heap2.remove(); |
有關其他類Commons組件的介紹就到這里結束。如果你想了解更多細節信息,請參見API文檔,最好再看看這些包的源代碼。
三、Web類
Web類的組件用來執行與Web相關的任務。
3.1 FileUpload
■ 概況:一個可以直接使用的文件上載組件。
■ 官方資源:主頁。由于這個組件尚未正式發布,今年二月發布的Beta版又有許多BUG,所以建議從nightly builds下載最新的版本。
■ 何時適用:當你想要在Java服務器環境中加入一個易用、高性能的文件上載組件之時。
■ 示例應用:fileuploaddemo.jsp,fileuploaddemo.htm,和msg.jsp。要求服務器端應用目錄的WEB-INF/lib下面有commons-fileupload-1.0-dev.jar。
■ 說明:
FileUpload組件解決了常見的文件上載問題。它提供了一個易用的接口來管理上載到服務器的文件,可用于JSP和Servlet之中。FileUpload組件遵從RFC1867,它分析輸入請求,向應用程序提供一系列上載到服務器的文件。上載的文件可以保留在內存中,也可以放入一個臨時位置(允許配置一個表示文件大小的參數,如果上載的文件超過了該參數指定的大小,則把文件寫入一個臨時位置)。另外還有一些參數可供配置,包括可接受的最大文件、臨時文件的位置等。
下面介紹一下使用FileUpload組件的步驟。
首先創建一個HTML頁面。注意,凡是要上載文件的表單都必須設置enctype屬性,且屬性的值必須是multipart/form-data,同時請求方法必須是POST。下面的表單除了上載兩個文件,另外還有一個普通的文本輸入框:
<form name="myform" action="fileuploaddemo.jsp"
method="post" enctype="multipart/form-data">
輸入你的名字:<br />
<input type="text" name="name" size="15"/><br />
圖形:<br />
<input type="file" name="myimage"><br/>
文件:<br />
<input type="file" name="myfile"><br /><br />
<input type="submit" name="Submit"
value="Submit your files"/> |
接下來創建JSP頁面。
// …
// ① 檢查輸入請求是否為multipart的表單數據。
boolean isMultipart = FileUpload.
isMultipartContent(request);
// …
// ② 為該請求創建一個句柄,通過它來解析請求。執行
// 解析后,所有的表單項目都保存在一個List中。
DiskFileUpload upload = new DiskFileUpload();
// 通過句柄解析請求,解析得到的項目保存在一個List中
List items = upload.parseRequest(request);
// …
// ③ 通過循環依次獲得List里面的文件項目。要區分表示
// 文件的項目和普通的表單輸入項目,使用isFormField()
// 方法。根據處理請求的要求,我們可以保存上載的文
// 件,或者一個字節一個字節地處理文件內容,或者打
// 開文件的輸入流。
Iterator itr = items.iterator();
while(itr.hasNext()) {
FileItem item = (FileItem) itr.next();
// 檢查當前的項目是普通的表單元素,還是一個上載的文件
if(item.isFormField()) {
// 獲得表單域的名字
String fieldName = item.getFieldName();
// 如果表單域的名字是name…
if(fieldName.equals("name"))
request.setAttribute("msg",
"Thank You: " + item.getString());
} else {
// 該項目是一個上載的文件,把它保存到磁盤。
// 注意item.getName()
// 會返回上載文件在客戶端的完整路徑名稱,這似乎是一個BUG。
// 為解決這個問題,這里使用了fullFile.getName()。
File fullFile = new File(item.getName());
File savedFile = new File
(getServletContext().getRealPath("/"),
fullFile.getName());
item.write(savedFile);
}
} |
我們可以通過上載句柄的upload.setSizeMax來限制上載文件的大小。當上載文件的大小超過允許的值時,程序將遇到異常。在上面的例子中,文件大小的限制值是-1,表示允許上載任意大小的文件。
還有其他一些略有變化的使用形式,正如前面所指出的,我們可以在上載的文件上打開一個輸入流,或者讓它們駐留在內存中直至空間占用達到一定的限制值,或者在判斷文件類型的基礎上,以String或Byte數組的形式獲取其內容,或者直接刪除文件。這一切都只要使用FileItem類提供的方法就可以方便地做到(DefaultFileItem是FileItem的一個實現)。
3.2 HttpClient
■ 概況:這個API擴展了java.net包,提供了模擬瀏覽器的功能。
■ 官方資源:主頁,二進制,源代碼。
■ 何時適用:當你要構造Web瀏覽器的功能;當你的應用需要一種高效的辦法進行HTTP/HTTPS通信時。
■ 示例應用:HttpClientDemo.java。要求CLASSPATH中有commons-httpclient.jar,common-logging.jar。要求使用JDK 1.4或更高版本。
■ 說明:
HttpClient擴展和增強了標準java.net包,是一個內容廣泛的代碼庫,功能極其豐富,能夠構造出各種使用HTTP協議的分布式應用,或者也可以嵌入到現有應用,為應用增加訪問HTTP協議的能力。在Commons穩定版中,HttpClient的文檔似乎要比其他包更完善一些,而且還帶有幾個實例。下面我們通過一個簡單的例子來了解如何提取一個Web頁面,HttpClient文檔中也有一個類似的例子,我們將擴充那個例子使其支持SSL。注意本例需要JDK 1.4支持,因為它要用到Java Secure Socket Connection庫,而這個庫只有JDK 1.4及更高的版本才提供。
① 首先確定一個可以通過HTTPS下載的頁面,本例使用的是https://www.paypal.com/。同時確保%JAVA_HOME%/jre/lib/security/java.security文件包含了下面這行代碼:security.provider.2=com.sun.net.ssl.internal.ssl.Provider。
除了這些設置之外,HTTPS連接的處理方式沒有其他特別的地方--至少對于本例來說如此。不過,如果遠程網站使用的根證書不被你使用的Java認可,則首先必須導入它的證書。
② 創建一個HttpClient的實例。HttpClient類可以看成是應用的主驅動程序,所有針對網絡的功能都依賴于它。HttpClient類需要一個Connection Manager來管理連接。HttpConnectionManager允許我們創建自己的連接管理器,或者,我們也可以直接使用內建的SimpleHttpConnectionManager或MultiThreadedHttpConnectionManager類。如果在創建HttpClient時沒有指定連接管理器,HttpClient默認使用SimpleHttpConnectionManager。
// 創建一個HttpClient的實例
HttpClient client = new HttpClient(); |
③ 創建一個HttpMethod的實例,即確定與遠程服務器的通信要采用哪種傳輸方式,HTTP允許采用的傳輸方式包括:GET,POST,PUT,DELETE,HEAD,OPTIONS,以及TRACE。這些傳輸方式分別作為一個獨立的類實現,但所有這些類都實現HttpMethod接口。在本例中,我們使用的是GetMethod,創建GetMethod實例時在參數中指定我們想要GET的URL。
// 創建一個HttpMethod的實例
HttpMethod method = new GetMethod(url); |
④ 執行HttpMethod定義的提取操作。執行完畢后,executeMethod方法將返回遠程服務器報告的狀態代碼。注意executeMethod屬于HttpClient,而不是HttpMethod。
// 執行HttpMethod定義的提取操作
statusCode = client.executeMethod(method); |
⑤ 讀取服務器返回的應答。如果前面的連接操作失敗,程序將遇到HttpException或IOException,其中IOException一般意味著網絡出錯,繼續嘗試也不太可能獲得成功。服務器返回的應答可以按照多種方式讀取,例如作為一個字節數組,作為一個輸入流,或者作為一個String。獲得服務器返回的應答后,我們就可以按照自己的需要任意處置它了。
byte[] responseBody = method.getResponseBody(); |
⑥ 最后要做的就是釋放連接。
method.releaseConnection(); |
以上只是非常簡單地介紹了一下HttpClient庫,HttpClient實際的功能要比本文介紹的豐富得多,不僅健壯而且高效,請參閱API文檔了解詳情。
3.3 Net
■ 概況:一個用于操作Internet基礎協議的底層API。
■ 官方資源:主頁,二進制,源代碼。
■ 何時適用:當你想要訪問各種Internet底層協議之時(Finger,Whois,TFTP,Telnet,POP3,FTP,NNTP,以及SMTP)。
■ 示例應用:NetDemo.java。要求CLASSPATH中包含commons-net-1.0.0.jar。
■ 說明:
Net包是一個強大、專業的類庫,類庫里的類最初屬于一個叫做NetComponents的商業產品。
Net包不僅支持對各種低層次協議的訪問,而且還提供了一個高層的抽象。大多數情況下,Net包提供的抽象已能滿足一般需要,它使得開發者不再需要直接面對各種協議的Socket級的低層命令。使用高層抽象并不減少任何功能,Net API在這方面做得很出色,既提供了足夠的功能,又不至于在特色方面作過多的妥協。
SocketClient是支持所有協議的基礎類,它是一個抽象類,聚合了各種協議都需要的公用功能。各種不同協議的使用過程其實很相似,首先利用connect方法建立一個指向遠程服務器的連接,執行必要的操作,最后終止與服務器的連接。下面通過實例介紹具體的使用步驟。
// …
// ① 創建一個客戶端。我們將用NNTPClient
// 從新聞服務器下載新聞組清單。
client = new NNTPClient();
// …
// ② 利用前面創建的客戶端連接到新聞服務器。
// 這里選用的是一個新聞組較少的服務器。
client.connect("aurelia.deine.net");
// …
// ③ 提取新聞組清單。下面的命令將返回一個
// NewsGroupInfo對象的數組。如果指定的服
// 務器上不包含新聞組,返回的數組將是空的,
// 如果遇到了錯誤,則返回值是null。
list = client.listNewsgroups();
//...
// ④ 最后終止與服務器的連接。
if (client.isConnected())
client.disconnect(); |
必須說明的是,listNewsgroups命令可能需要較長的時間才能返回,一方面是因為網絡速度的影響,另外也可能是由于新聞組清單往往是很龐大的。NewsGroupInfo對象包含有關新聞組的詳細信息,并提供了一些操作新聞組的命令,比如提取文章總數、最后發布的文章、發布文章的權限,等等。
其他客戶端,例如FingerClient、POP3Client、TelnetClient等,用法也差不多。
結束語:有關Web相關類和其他類的介紹就到此結束。在下一篇文章中,我們將探討XML類和包裝類,最后一篇文章則介紹工具類。
希望讀者有興趣試試本文提供的程序實例。很多時候Jakarta Commons給人以混亂的感覺,希望本文使你加深了對Jakarta Commons了解,或者至少引起了你對Commons子項目以及它提供的各種實用API和庫的興趣。