引自:
http://www.tkk7.com/flyingis/archive/2005/11/09/18957.html(文章轉(zhuǎn)自CSDN)
如果你不熟悉Jakarta Commons話,那么很有可能你已經(jīng)重新發(fā)明了好幾個(gè)輪子。在你編寫更多的普通的框架或工具之前,體驗(yàn)一下Commons吧。它將會(huì)大大地節(jié)約你的時(shí)間。太多的人自己寫一個(gè),其實(shí)是與Commons Lang中的StringUtils重復(fù)的StringUtils類,或者,開發(fā)者不知道從Commons Collections中重新創(chuàng)建工具,哪怕commons-collections.jar已經(jīng)在classpath中可用了。
真的,請(qǐng)停一下。看看Commons Collections API,然后再回到你的任務(wù)中;我發(fā)誓你會(huì)發(fā)現(xiàn)一些簡(jiǎn)單有用的東西可以幫你在明年節(jié)省一周的時(shí)間。如果大家花一點(diǎn)時(shí)間看看Jakarta Commons,我們將會(huì)得到更少的重復(fù)代碼—我們將在重用的宗旨下真正做一些有用的事情。
我確實(shí)看到這樣的情況發(fā)生過:一些人研究了一下Commons BeanUtils或者Commons Collections,然后總是有“啊,如果我那時(shí)知道這個(gè)的話,我就不會(huì)寫那一萬行的代碼了”這樣的時(shí)刻。Jakarta Commons仍有一部分保持相當(dāng)?shù)纳衩?比如,許多人還沒有聽說過Commons CLI和Commons Configuration,并且大多數(shù)人還沒有注意到Commons Collections中的functors(算子)包的價(jià)值。在這一系列中,我會(huì)專門強(qiáng)調(diào)一些Jakarta Commons中較少得到重視的工具和功能。
在這一系列的第一部分,我將探索定義在Commons Digester中的XML規(guī)則,Commons Collections中的功能,和使用一個(gè)有趣的應(yīng)用,Commons JXPath,來查詢一個(gè)對(duì)象的List。Jakarta Commons包含的功能目的在于幫助你解決低層次的編程問題:遍歷集合,解析XML和從List中檢出對(duì)象。我建議你花一些時(shí)間在這些小功能上,學(xué)習(xí)Jakarta Commons真的會(huì)為你節(jié)省不少時(shí)間。
并不簡(jiǎn)單地是學(xué)習(xí)使用Commons Digester來解析XML或者使用CollectionUtils的Predicate來過濾一個(gè)集合,而是當(dāng)你一旦意識(shí)到如何將這些功能組合起來使用并且如何將Commons集成到你的項(xiàng)目中去的時(shí)候,你才會(huì)真正地看到它的好處。如果你這樣做地話,你將會(huì)把commons-lang.jar, commons-beanutils.jar,和 commons-digester.jar當(dāng)成JVM本身來看待。
如果你對(duì)Jakarta Commons更深的內(nèi)容感興趣的話,可以看一下Jakarta Commons Cookbook。這本書給你很多方法來更好的使用Commons,并告訴你如何將Jakarta Commons與其它的小的開源組件集成,如Velocity, FreeMarker, Lucene, 和 Jakarta Slide。這本書,我介紹了一組廣泛的工具從Commons Lang中的簡(jiǎn)單工具到組合了Commons Digester, Commons Collections, 和Jakarta Lucene來搜索威廉.莎士比亞的著作。我希望這一系列和Jakarta Commons Cookbook這本書能夠提供給你一些有趣的低層次的編程問題的解決方案。
1. 用于Commons Digester的基于XML的規(guī)則集Commons Digester 1.6提供了將XML轉(zhuǎn)化為對(duì)象的最簡(jiǎn)單的方法。Digester已經(jīng)由O'Reilly網(wǎng)站上的兩篇文章介紹過了:“學(xué)習(xí)和使用Jakarta Digester”,作者是Philipp K. Janert,和“使用Jakarta Commons, 第二部分”,作者是Vikram Goyal。兩篇文章都演示了XML規(guī)則集的使用,但如何在XML中定義規(guī)則集并沒有理解。大多所見到的Digester的使用是程序化地定義規(guī)則集,以已編譯的形式。你應(yīng)該避免硬編碼的Digester規(guī)則,特別是當(dāng)你可以將映射信息存儲(chǔ)在外部文件中或一個(gè)類路徑資源中時(shí)。外部化一個(gè)Digester規(guī)則可以更好地適應(yīng)一個(gè)演化中的XML文檔結(jié)構(gòu)或者說一個(gè)演化中的對(duì)象模型。
為了演示在XML中定義規(guī)則集與硬編碼的規(guī)則集之間的區(qū)別,考慮系統(tǒng)解析XML給一個(gè)Person bean,包括在下面定義的屬性—id, name和age。
package org.test;
public class Person {
??public String id;
??public String name;
??public int age;
????????????????
??public Person() {}
??public String getId() { return id; }
??public void setId(String id) {
????this.id = id;
??}
??public String getName() { return name; }
??public void setName(String name) {
????this.name = name;
??}
??public int getAge() { return age; }
??public void setAge(int age) {
????this.age = age;
??}
}
確認(rèn)你的應(yīng)用需要解析一個(gè)包含了多個(gè)person元素的XML文件。下面的XML文件,data.xml,包含了兩個(gè)person元素,你想要把它們解析到Person對(duì)象中:
??
????Tom Higgins
????25
??
??
????Barney Smith
????75
??
??
????Susan Shields
????53
??
你希望如果結(jié)構(gòu)和XML文件的內(nèi)容在未來幾個(gè)月中變化,你不需要在已編譯的Java代碼中硬編碼XML文件的結(jié)構(gòu)。為了做到這一點(diǎn),你需要在一個(gè)XML文件中定義Digester的規(guī)則,并且它可以作為一種資源從類路徑中裝入。下面的XML文檔,person-rules.xml,映射person元素到Person bean:
??
????
????
??????????????????????paramtype="java.lang.Object"/>
????
????
????
??
上述所做的是指示Digester創(chuàng)建一個(gè)新的Person實(shí)例,當(dāng)它遇到一個(gè)person元素時(shí),調(diào)用add()來將Person對(duì)象加入到一個(gè)ArrayList中,設(shè)置person元素中相匹配的屬性,并從下一級(jí)元素name和age中設(shè)置name和age的屬性。
現(xiàn)在你已經(jīng)看到了Person類,會(huì)被解析的文檔,和以XML的形式定義的Digester規(guī)則。現(xiàn)在你需要?jiǎng)?chuàng)建一個(gè)由person-rules.xml定義了規(guī)則的Digester的實(shí)例。下面的代碼創(chuàng)建 了一個(gè)Digester,通過將person-rules.xml的URL傳遞給DigesterLoader
既然person-rules.xml文件是與解析它的類在同一個(gè)包內(nèi)的類路徑資源,URL可以通過getClass().getResource()來得到。DigesterLoader然后解析規(guī)則并將它加到新創(chuàng)建的Digester上:
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
// 從XML規(guī)則集中配置Digester
URL rules = getClass().getResource("./person-rules.xml");
Digester digester =
????DigesterLoader.createDigester(rules);
// 將空的List推入到Digester的堆棧
List people = new ArrayList();
digester.push( people );
// 解析XML文檔
InputStream input = new FileInputStream( "data.xml" );
digester.parse( input );
一旦Digester完成對(duì)data.xml的解析,三個(gè)Person對(duì)象將會(huì)在ArrayList people中。
與將規(guī)則定義在XML不同的方法是使用簡(jiǎn)便的方法將它們加入到一個(gè)Digester實(shí)例中。大多數(shù)文章和例子都用這種方法,使用addObjectCreate() 和 addBeanPropertySetter()這樣的方法來將規(guī)則加入中Digester上。下面的代碼加入了與定義在person-rules.xml中相同的規(guī)則:
digester.addObjectCreate("people/person", Person.class);
digester.addSetNext("people/person", "add", "java.lang.Object");
digester.addBeanPropertySetter("people/person", "name");
digester.addBeanPropertySetter("people/person", "age");
如果你曾經(jīng)發(fā)現(xiàn)自己正在用一個(gè)有著2500行代碼的類,用SAX來解析一個(gè)巨大的XML文檔,或者使用DOM或JDOM的完整的一個(gè)集合類,你就會(huì)理解XML的解析比它應(yīng)該做的要復(fù)雜的多,就大多數(shù)情況來說。如果你正在建一個(gè)有著嚴(yán)格的速度和內(nèi)存要求的高效的系統(tǒng),你會(huì)需要SAX解析器的速度。如果你需要DOM級(jí)別3的復(fù)雜度,你會(huì)需要像Apache Xerces的解析器。但如果你只是簡(jiǎn)單的試圖將幾個(gè)XML文檔解析到對(duì)象中去的話,看一下Commons Digester, 并把你的規(guī)則定義在一個(gè)XML文件中。
任何時(shí)候你都應(yīng)該將配置信息從硬編碼中移出來。我會(huì)建議你在一個(gè)XML文件中定義規(guī)則并從文件系統(tǒng)或類路徑中裝入它。這樣可以使你的程序更好地適應(yīng)XML文檔以及對(duì)象模型的變化。有關(guān)在XML文件中定義Digester規(guī)則的更多的資料,參看Jakarta Commons Cookbook一書的6.2節(jié),“將XML文檔轉(zhuǎn)換為對(duì)象”