用Velocity進行配置文件信息的集中管理

Apache從他誕生的那天起就改變着我們的生活方式。而Velocity的出現也不是個例外。Velocity是一個基於java的模板引擎(template engine)。它允許任何人僅僅簡單的使用模板語言(template language)來引用由java代碼定義的對象。 當Velocity應用於web開發時,界面設計人員可以和java程序開發人員同步開發一個遵循MVC架構的web站點,也就是說,頁面設計人員可以只關注頁面的顯示效果,而由java程序開發人員關注業務邏輯編碼。Velocity將java代碼從web頁面中分離出來,這樣爲web站點的長期維護提供了便利,同時也爲我們在JSP之外又提供了一種可選的方案。

曾幾何時,還記得自己每次對JSP頁面做一點小小的改動,就需要痛苦的幾秒鐘等待時間,好讓JSP容器按部就班的把JSP頁面先生成爲Java文件,然後又將該Java文件編譯成class文件,最後再將結果返回。然後又可能由於是自己的一時疏忽導致的一個小bug,使得你不得不再次去重複同樣的工作。現在,當我們有了 Velocity 之後,頁面的修改不再變成一件讓人痛苦的事情。它可以讓你徹底體驗頁面改動帶來的飛速回報。這也是 Velocity 值得稱道的地方之一:他拯救了我們的WEB程序員們。於是,你Google一下,隨便就可以在網上找到成千上萬的關於 Velocity 如何進行Web開發的相關文章。

Velocity之所以如此famous、如此優秀,是因爲Velocity的能力遠不止web表現層開發這個領域,Velocity的誕生也爲開發界帶出了另一個話題——模板化(至少是使得模板化更加簡單易行),而web表現層的應用僅僅只是“模板化”話題中的一個分支而已,我今天想聊一聊關於 Velocity 爲大多數程序員所不夠關注但是又非常重要的應用——配置文件模板化。
今天的軟件開發界是一個開源插件滿天飛的世界。什麼Hibernate.cfg.xml、Hibernate.hbm.xml、struts-config.xml、spring.xml、web.xml甚至是tomcat、JBoss的一些配置都需要我們在發佈產品的時候一併進行配置。其實,一個通常的工程其配置文件遠遠不止這些,在工程應用中,我們爲了提高系統的靈活性,在開發階段會引入大量的配置文件,而這些配置文件都會由於客戶需求的變化、工程運行環境的不同出現不同的差異。同時又與操作系統(windows、Linux)、數據庫、網絡環境的參數有密切的關係。常態下,需要正確配置這些信息必須首先是一個對系統非常熟悉的Senior Engneer。但是,事實上是我們不可能爲了解決這些系統配置的信息去每次找幾個Senior Engneer去處理這些得不償失的事情。那麼問題就來了,既然不是由Senior Engneer來處理這些事情,那麼那些其他的Junior Engneer有沒有足夠的能力去處理這些事情。有什麼辦法可以在這兩者之間做出權衡呢。

一種可行的解決方案就是將這些配置成可替換的參數,然後找一個文件對這些需要配置的數據進行集中管理,這樣當我們需要修改某些配置信息時,我們只需要在該文件中集中處理然後執行一個簡單的替換操作所有的事情就全部OK了。於是我們想到了Velocity,這個看起來處理模板數據本該是天性使然的傢伙,能否給我們一個預料之中的驚喜呢。其實我們的問題就轉移到了,Velocity是否有能力將我們的參數一一進行提換的問題了。

小實驗馬上展開:
根據提供的接口我們很快寫出了上面的這段代碼,其中createFile() 方法是參數替換的具體實施者。
其中用到的兩個配置文件內容分別如下:

java 代碼
  1. package org.danlley.util.samples;   
  2.   
  3. import java.io.BufferedWriter;   
  4. import java.io.FileInputStream;   
  5. import java.io.FileWriter;   
  6. import java.util.Enumeration;   
  7. import java.util.Properties;   
  8.   
  9. import org.apache.velocity.Template;   
  10. import org.apache.velocity.VelocityContext;   
  11. import org.apache.velocity.app.Velocity;   
  12.   
  13. public class VelocityFirstStep{   
  14.     public static void main(String[] args){   
  15.         String resourceFileName="first_step.properties";   
  16.         String destPath="./target/classes/";   
  17.         String destFileName="generator.properties";   
  18.         try{   
  19.             createFile(resourceFileName,destPath,destFileName);   
  20.         }catch(Exception e){   
  21.             e.printStackTrace();   
  22.         }   
  23.     }   
  24.   
  25.     /**  
  26.      * <p>comments : danlley 【伏羲狂徒】  
  27.      *              mailto: [email protected]  
  28.      *              Blog: http://danlley.iteye.com  
  29.      *                    http://danlley.cublog.cn  
  30.      *          </p>  
  31.      * author  danlley 【伏羲狂徒】  
  32.      * coding date  2007-7-24  
  33.      * @param resourceFileName  
  34.      * @param path  
  35.      * @param destFileName  
  36.      * @throws Exception  
  37.      */  
  38.     public static void createFile(String resourceFileName,String path,String destFileName) throws Exception{   
  39.         Properties p=new Properties();   
  40.         p.setProperty(Velocity.INPUT_ENCODING,"GBK");   
  41.         p.setProperty(Velocity.OUTPUT_ENCODING,"GBK");   
  42.         Velocity.init(p);   
  43.         Template template=Velocity.getTemplate(path+destFileName);   
  44.         VelocityContext context=new VelocityContext();   
  45.         p.load(new FileInputStream(path+resourceFileName));   
  46.         Enumeration enu=p.keys();   
  47.         String key,value;   
  48.         while(enu.hasMoreElements()){   
  49.             key=enu.nextElement().toString();   
  50.             value=p.get(key).toString();   
  51.             context.put(key,new String(value.getBytes("ISO-8859-1"),"GBK"));   
  52.         }   
  53.         BufferedWriter writer=new BufferedWriter(new FileWriter(path+destFileName+".txt"));   
  54.         template.merge(context,writer);   
  55.         writer.flush();   
  56.         writer.close();   
  57.     }   
  58. }   


 

first_step.properties內容如下:

username=伏羲狂徒
passport=welcome to danlley's home page
messages=hello velocity

generator.properties中我們暫時只配置一條模板數據:

第三方第三方第三個大股東范甘迪說個======$username======改動熱管熱個人股熱管熱管大商股份第三個
passport=$passport
messages=$messages

運行程序得到生成文件generator.properties.txt

 

永遠都不要忘了,老外的東西對我們中國的漢字從來都是照顧不周的。因此,我們在寫程序的時候永遠都應該對我們的漢字懷着悲天憫人之心,多加照顧(誰讓我們不爭氣呢)。Velocity也理當如此,打開Velocity的源碼,看看他在處理模板時是怎樣設置編碼格式的,當然程序員都是比較“懶惰”的,所以你也可以下面的代碼僅僅是看看就行了:

java 代碼
  1. System.out.println(template.getEncoding());//--默認是ISO-8859-1  


但是如果你真的對Velocity的編碼設置感興趣org.apache.velocity.runtime.resource包下的Resource類可能會對你有一定的參考價值。


運行程序後得到的generator.properties.txt內容如下:


第三方第三方第三個大股東范甘迪說個======伏羲狂徒======改動熱管熱個人股熱管熱管大商股份第三個
passport=welcome to danlley's home page
messages=hello velocity


這樣,一個簡單的模板管理的雛形就已經呈現在我們的面前了。其中first_step.properties在這裏可以作爲一個集中管理者,而generator.properties則是代替換的參數模板文件,最後generator.properties.txt則是我們需要的“熊掌、魚翅”。思路已經有了,實現的可行性也已經驗證了。那要想把他真正用在工程中,剩下的就只是對其進行擴充了。

看似好像沒什麼問題了,但是好像又不是很完美。爲什麼!用起來不方便,如果是在Ant和Maven中,我可以把整個參數替換過程放置在某個測試類中,然後運行一下,但是保證這個測試類的運行要先於其他測試類的運行就是一個令人頭疼的事情,而且,參數替換過程本來就不屬於工程代碼的一部分,他應該是一個獨立的組件纔對。所以我們就把它開發成一個組件。不要拖動滾動條,因爲下面沒了,呵呵呵呵。我打算在下一個專題中來專門闡述一下基於Velocity的Ant和Maven插件開發過程。關注我的博客吧,^_^

 

參考資料:
http://ahuaxuan.iteye.com/blog/71430
http://www.open-open.com/open2821.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章