輕鬆學習Velocity - Velocity基本用法和常用的用法

前言:

        1. 不少人看過或瞭解過Velocity,Velocity字面翻譯爲:速度、速率、迅速。在Web開發裏,用過的人可能不多,大都基本知道和在使用Struts,到底Velocity和Struts是如何聯繫,怎麼看待Velocity呢?讓我們來嘗試一下,瞭解Velocity的概念,通過在這裏的介紹,強調在技術選擇上的問題,讓大家在選擇項目開發時,可以考慮Velocity,另外也讓大家瞭解它的思想,畢竟它提供了一個很好的思維方式,給大家換換筋骨,換一種思考的方式。 

2. 本文基於你對Java開發有一定基礎,知道MVC,Struts等開發模式。 

 

一、什麼叫Velocity? Velocity是一種Java模版引擎技術,該項目由Apache提出,由另外一種引擎技術Webmacro引深而來。那什麼是官方的Velocity定義呢?  Apache對它的定義是:一種基於Java的模板引擎,允許任何人使用簡單而強大的模板語言來引用定義在Java代碼中的對象。可以在http://jakarta.apache.org/velocity/index.html查找更多信息。

       

        其實說白了Velocity也就是MVC架構的一種實現,但它更多的是關注在Model和View之間,作爲它們的橋樑。對於MVC的最流行架構Struts來說,相信大家都不陌生,很多開發人員已經大量在使用Struts架構,包括IBM的Websphere 5以上的管理平臺版本,Struts技術很好的實踐了MVC,它有效的減少Java代碼在View(Jsp)中的出現,但在Model和View之間還是依靠Struts的Taglib技術來實現,試想如果前臺開發的網頁設計師對Struts乃至Taglib不熟(相信也挺難熟的,包括後期的維護人員也一樣),將會對網頁設計師和前臺開發工程師的相互協作開發帶來很大的難度,現實開發中也還是存在這樣事實,網頁設計師和前臺開發之間的工作或多或少還是存在一定的耦合,怎樣最大限度的解決這個難題呢?還是讓我們來看看Velocity或者說這個概念吧。

 

二、具體實例:

先做一個最簡單的Velocity開發例子,讓大家看看Velocity是怎樣工作的: 

 

1、創建1個文件,文件名爲:hello-velocity.vm,即velocity模版(其實和html一樣),內容: 

 

<html> 

 

<title>Hello Velocity</title> 

 

       <body> 

 

         Welcome $name to Josh_Persistence.blog! 

 

         today is $date. 

 

       </body> 

 

</html> 

   

2、創建1個java文件,HelloVelocity.java,內容:   

package com.wsheng.velocity; 

 

import java.io.StringWriter; 

import java.util.*; 

import org.apache.velocity.app.VelocityEngine; 

import org.apache.velocity.Template; 

import org.apache.velocity.VelocityContext; 

 

public class HelloVelocity { 

 

public static void main(String[] args) throws Exception { 

 

       // 初始化並取得Velocity引擎 

       VelocityEngine ve = new VelocityEngine(); 

       ve.init(); 

 

      // 取得velocity的模版 

      Template t = ve.getTemplate("hello-velocity.vm"); 

 

      // 取得velocity的上下文context 

      VelocityContext context = new VelocityContext(); 

 

     // 把數據填入上下文 

     context.put("name", "sheng"); 

     context.put("date", (new Date()).toString()); 

 

     // 爲演示後面的例子,提前輸入List數值 

     List temp = new ArrayList(); 

     temp.add("1"); 

     temp.add("2"); 

 

    context.put("list", temp); 

 

    // 輸出流 

   StringWriter writer = new StringWriter(); 

 

   // 轉換輸出 

   t.merge(context, writer); 

 

  System.out.println(writer.toString()); 

 

 

 

3、下載運行需要依賴的包:在http://jakarta.apache.org/site/binindex.cgi上下載最新的VelocityXXX.zip,

在下載後的velocityXXX.zip中的lib中解壓出velocityXX.jar,commons-collections.jar、logkit-XXX.jar

 

4、 運行後的輸出結果:

 

<html> 

 

      <title>Hello Velocity</title> 

 

<body> 

 

     Welcome Sheng to Josh_Persistence.blog! 

 

     today is Tue June 18 19:26:37 CST 2013. 

 

</body> 

 

</html> 

 

         以上是最簡單的運行結果,怎麼樣,知道個大概吧,模版hello-velocity.vm裏的2個定義變量$name和$date分別被context.put("name", "sheng")和context.put("date", (new Date()).toString())所設的值替代了。 

         由此看來業務流程處理包括業務結果基本在model這層全部解決,而view這一層基本只用使用簡單的VTL(Velocity Template Language)來展示。這樣,Jsp豈不是不用了麼?是的,這樣的使用模式有點象早前的CGI方式:)由Velocity自動輸出代碼,並且Velocity在這方面的能力也很強,Turbine裏就採用了Velocity來產生很多代碼。 

在Velocity中,變量的定義都是使用“$”開頭的,$作爲Velocity的標識符。字母、數字、中劃和下劃線都可以作爲Velocity的定義變量。

      此外我們還需要注意的是Velocity特色的變量定義,如:$student.No、$student.Address,

它有2層含義:

      第1種是如果student是hashtable,則將從hashtable中提取key爲No和Address的值,

      第2種就是它有可能是調用方法,即上面2個變量將被轉換爲student.getNo()和student.getAddress()。

Velocity可以處理servlet中的java code返回的值可以是對象,還可以調用對象的方法,如$student.getAddress()等等,在此就不一一舉例和深入了。 

     上面的例子只是簡單的舉例,現在當然不少人已經不滿足這樣的例子了,實際的應用中我們還常常需要作些選擇性展示和列舉一些迭代數據,如List列表,當然Velocity(具體來說應該是VTL模版語言)也支持這項功能,此外還支持其他一些常用的展示,如模版內部的變量如Jsp內的變量),還有強大一些的如創建宏以實現自動化,讓我們繼續接着往下看吧。 

 

1. Velocity中使用#set定義變量

我們還是使用上面的例子,把模版hello-velocity.vm中的內容改爲: 

 

#set( $iAmVariable = "good!" ) 

Welcome $name to Josh_Persistence.blog! 

 

today is $date. 

 

$iAmVariable 

 

重新執行上面的運行命令,結果: 

 

Welcome Sheng to Josh_Persistence.blog! 

 

today is Tue June 18 19:26:37 CST 2013. 

 

good! 

 

    可以看出模版中的變量定義爲#set開頭的語句,不是很難理解,執行後模版中的變量$iAmVariable都轉換成定義的值:good! 

 

2. If, else, end的使用。

再來看看簡單的選擇,把模版hello-velocity.vm中的內容改爲: 

#set ($admin = "admin") 

#set ($user = "user") 

 

#if ($admin == $user) 

Welcome admin! 

#else 

Welcome user! 

#end 

 

執行運行命令,結果: 

 

Welcome user! 

 

可以看到判斷語句只是簡單的#if ()、#else、#end,不是很複雜。

 

3. List的迭代,把模版hello-velocity.vm中的內容改爲: 

#foreach($product in $list ) 

<li>$product</li> 

#end 

 

執行運行命令,結果: 

<li>1</li> 

<li>2</li> 

 

把在例子中預先保存在VelocityContext的List中的值列舉了出來,是不是很方便啊?僅僅只是用了#foreach($variable in xx而已。

 

4. hashtable的迭代:

如果上面的List換成Hashtable,則可以用下面的語法: 

 

#foreach($key in $hashVariable.keySet() ) 

 

<li> $key ‘s value: $ hashVariable.get($key) </li> 

 

 

#end 

 

5.velocity處理java bean,我們增加一個bean: 

 

package com.wsheng.velocity; 

 

public class Student { 

 

// 注意class的屬性是public的 

public String no = ""; 

public String address = ""; 

 

public Student(String _no, String _address) { 

no = _no; 

address = _address; 

 

public String getAddress() { 

return address; 

 

public void setAddress(String address) { 

this.address = address; 

 

public String getNo() { 

return no; 

 

public void setNo(String no) { 

this.no = no; 

這個Student是十足的javabean,或者說是data bean,常見的用來裝載數據的類,然後我們修改HelloVelocity.java,把: 

 

temp.add("1"); 

 

temp.add("2"); 

 替換成: 

 temp.add(new Student("123", "Guangzhou")); 

 temp.add(new Student("456", "Zhuhai")); 


再把hello-velocity.vm的內容改爲: 

#foreach ($s in $students) 

 <$velocityCount> Address: $s.address 

#end 


重新編譯和執行運行命令,結果如下: 

<1> Address: Guangzhou 

<2> Address: Zhuhai 

 

這樣把list中Student的數據打印了出來,大功告成!這裏用了Velocity的內建變量$velocityCount,指的是默認的列舉序號,從1開始,也可以改成0開始,但需要在Velocity.properties中更改,Velocity.properties位於velocity-XX.jar包內的目錄org\\apache\\velocity\\runtime\\defaults 下。 

 

6. Velocity處理嵌套的迭代的處理,我們看看下面的模版例子就清楚了: 

 

#foreach ($element in $list) 

 

-- inner foreach -- 

 

#foreach ($element in $list) 

 

This is $element. 

 

$velocityCount 

 

#end 

-- inner foreach -- 

 

-- outer foreach -- 

 

This is $element. 

 

$velocityCount 

 

-- outer foreach -- 

 

#end 

 

       看出來了吧,Velocity是支持標籤嵌套的,這個可是很強大的功能,這裏就不深入演示了,如果有興趣,自己試試吧。 

 

其實,稍爲深入思考剛剛我們舉的例子,就已經可以看出來,Velocity的用處在哪裏?即Servlet + Velocity的模式,另外,還記得我們早期Jsp開發的模式Jsp+JavaBean嗎?在這裏,我們更改爲Servlet+JavaBean+Velocity,想想,是不是已經替代了Jsp+JavaBean,並更徹底的把Java代碼去除在Jsp(vm)外,如果光使用Struts(Servlet+Jsp),那麼帶來的代價是Java代碼總或多或少出現在Jsp上,即使可以做到不出現Java代碼,但做過複雜架構系統的開發者都知道,代價也是很昂貴的,並且在可維護性、和網頁設計師的集成開發上存在一定的困難,所以我們在這裏能感覺到,Servlet+JavaBean+Velocity的模式較好的實現了OOD的概念。而在效率上,大家也不用擔心,此種結合方式比Servlet+Jsp的方式要高效一些。 

願意瞭解Velocity的人應該不少,但真正實用到項目的,也許不多(還是有些項目在使用,如Jute),畢竟和Jsp比起來,Jsp更標準、更廣泛使用和有不少開發工具已經支持Jsp開發。但Velocity的功能不會僅僅侷限在和Jsp競爭的局面,由上可看出它在自動代碼輸出方面功能很強,前面提到Turbine就是採用Velocity來生成很多代碼,你也可以稍加改動就可以做成代碼生成器,或其他模版生成上,都是很不錯的想法。 

 

7. Velocity與國際化 

 

Velocity本身支持模版的國際化編碼轉換,看看Velocity提供的方法: 

 

Public Template getTemplate (Stirng template, String encoding), 

 

由此推測這樣做其實不能徹底的做到國際化。 

 

最簡單的在Struts中國際化的概念,即在Jsp上使用國際化語言標籤的方式來做到,而每種語言採用不同的語言標籤庫的方式,

引申到這裏,其實手工來做一樣可以做到,只不過需要稍加手工處理而已。 

 

好在已經有人處理了上面所說問題,做成了Velocity的tools: MessageTool,提供了變量text包含國際化標籤,

這樣只需要簡單的編寫標籤代碼即可,如:$text.get(‘title’),

更多具體的內容還可在http://jakarta.apache.org/velocity/tools/struts/MessageTool.html 中瞭解。 

 

8. Velocity返回null的情況:

jobLocation="#if($!candidate.job.location.title)$!StringEscapeUtils.escapeXml($!candidate.job.location.title)#end"

如果只是$!candidate.job,則不會有任何信息返回。candidate.job.location也不會有信息返回。即使它們都不爲空,不返回的原因是他們都是類對象,而不是具體的屬性。

 

      好了,基於Velocity的介紹就說這麼多,再說說其他引伸方面的內容吧。有人評論Velocity不是標準的MVC結構,沒錯,剛開始就說過Velocity只是Model和View之間的良好結合,只是個好的模版引擎,畢竟還沒有形成MVC三者良好的結合。好在Apache又基於Struts和Velocity的結合,推出了VelocityStruts,這裏簡單介紹它的概念,它是在Struts的結構上,在業務邏輯處理的Action後,把業務流程轉向基於Velocity的顯示層,從而代替Jsp作爲View層。以上我們也看到了所舉的例子基本上只是基於原理和演示,沒有和Web開發緊密結合起來,這方面內容也許我以後會在另一篇博客中講述VelocityStruts的內容時再來結合吧。 談到Velocity,在這裏要順便提提FreeMarker,FreeMarker也是一種模版引擎,和Velocity功能基本類似,都是簡單和輕量級的工具,但功能上較Velocity有不少增強的地方,我也會另外寫一篇的博客來深入瞭解吧。

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