Velocity官方指南-使用Velocity
原文地址 譯者:冷風 校對:方騰飛
如果你使用的是VelocityViewServlet或者其他的web框架,你不會直接呼叫到Velocity。但是,如果在非web的應用中或者自己編寫的web框架時,你將會像上面說的基本流程一樣直接呼叫到Velocity 引擎。另外一個需要記住的重點是,必須在使用Velocity合併模版之前,初始化Velocity引擎。
Velocity輔助類
Velocity中包含一個叫做Velocity( org.apache.velocity.app.Velocity )的應用工具類。這個類的主要是提供一些初始化Velocity時必須的方法,以及簡化Velocity使用的一些常規方法。這個在工程的javadoc中有描述,可通過閱讀javadoc來獲取更詳細的說明。本篇文件只是教程;所以,如果需要了解完整的API資訊,javadoc是你最好的選擇。
Velocity執行時引擎是為在同一個jvm中的其他使用者提供資源獲取,日誌記錄等其他服務的單個例項。因此,執行時引擎只會初始化一次。你可以嘗試初始化多次,但是隻有第一次是有效的,後面的初始化操作都會被忽略。Velocity工具類提供了五個用來配置執行時引擎的方法。
這五個配置方法如下:
- setProperty( String key, Object o )
設定屬性鍵key對應屬性值為o。值通常為字串,在特殊情況下也可以是逗號分隔的一串值(如”foo,bar,woogie”),當然也可以其他值。 - Object getProperty( String key )
獲取屬性鍵key對應的值。需要注意的是返回值的型別,不僅僅只是字串型別 - init()
使用jar包中的預設properties檔案中配置的屬性初始化執行時引擎 - init(Properties p)
使用型別為java.util.Properties引數出入的屬性來初始化執行時引擎 - init( String filename )
使用檔名為filename的properties檔案中的屬性值初始化執行時引擎
需要注意的是,在上面的這五個方法中,預設的properties是基礎的配置,額外的properties是用來替換預設配置中對應的屬性。沒有被替換的預設屬性還將繼續發揮作用。這有利於你只需替換你感興趣的,而不需要整個都替換掉。
另外需要注意的是,init() 方法可以在應用中被呼叫多次,這並不會帶來其他影響。但是隻有在第一呼叫時的引擎配置才會生效,後面呼叫的init()使用的配置都會被忽略。
最常見的初始化Velocity的方式,通常如下:
1 按照org/apache/velocity/runtime/defaults/velocity.properties 檔案中的格式配置你需要替換的屬性,放在檔案中或者放到java.util.Properties中,然後呼叫init(filename) 或者 init(Properties)
2 通過setProperty() 方法設定單個的配置項,然後呼叫initial()。 這種方法通常在擁有自己的配置管理系統的高層應用中。例如,允許應用基於執行時產生的值來配置Velocity
一旦執行時引擎初始化完成,你就可以進行任何你想做的了。當然,主要還是圍繞著渲染模板輸出內容到輸出流中,Velocity輔助類中的一些方法可以幫你輕鬆搞定,下面是這些方法以及他們做的事情的簡要描述:
- evaluate( Context context, Writer out, String logTag, String instring )
- evaluate( Context context, Writer writer, String logTag, InputStream instream )這些方法使用傳入的contexxt物件渲染一個輸入,輸出到Writer中;輸入的內容可以是一個字串或者一個InputStram。這個方法經常用在替換字串中的標記、渲染模板內容儲存在資料庫中或其他的非文具的儲存中,或者動態生成內容時。
- invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer )
通過這個方法可以直接呼叫到Velocity巨集,也可以通過上面的evalutae()方法呼叫。你只需要給你的vm模板取一個名字,建立一個提供給vm使用的陣列,一個包含資料的context,以及用於輸出內容的Writer。需要注意的是這裡說的提供給vm使用的陣列中的元素只能是context中有的key,而不是其他用作引數傳入vm的字串。這點在後面的版本有可能修改。
- mergeTemplate( String templateName, Context context, Writer writer )通過這個方法可以非常方便的呼叫到Velocity提供的模板出來和渲染的功能。這個方法會讀取和渲染模板。檔案載入器會根據你設定的properties的設定來載入模板內容,所以可以Velocity提供的檔案處理的優勢以及預解析模板快取的優勢。
- boolean templateExists( String name )判斷當前配置的資源載入起能否都讓渠道名為name的模板檔案。
通過上面的文件,我們已經清楚了這些基礎的輔助方法,現在就可以地編寫使用Velocity的java程式了:
import java.io.StringWriter; import org.apache.velocity.app.Velocity; import org.apache.velocity.VelocityContext; public class Example2 { public static void main( String args[] ) { /* 首先,初始化執行時引擎,使用預設的配置 */ Velocity.init(); /* 建立Context物件,然後把資料放進去 */ VelocityContext context = new VelocityContext(); context.put("name", "Velocity"); context.put("project", "Jakarta"); /* 渲染模板 */ StringWriter w = new StringWriter(); Velocity.mergeTemplate("testtemplate.vm", context, w ); System.out.println(" template : " + w ); /* 渲染字串 */ String s = "We are using $project $name to render this."; w = new StringWriter(); Velocity.evaluate( context, w, "mystring", s ); System.out.println(" string : " + w ); } }
在執行程式之前,我們需要把模板檔案testtemplate.vm放到與程式相同的目錄下(因為我們使用預設配置,預設配置中指定的模板載入路徑就是程式的當前目錄)。執行上面程式碼後,將會輸出:
template : Hi! This Velocity from the Jakarta project.
string : We are using Jakarta Velocity to render this.
模板檔案testtemplate.vm檔案的內容是:
Hi! This $name from the $project project.
好了,上面就是我們使用Velocity渲染模板需要做的事情了。在程式碼中沒有必要既呼叫mergeTemplate()又呼叫evaluate(),這裡只是為了演示才同時使用了。你一般只需要使用其中一個方法就夠了。但是到底呼叫一個還是兩個,需要根據你程式的具體要求確定。
這裡看起來與文章最開始描述的 基本流程 有一些差別,但實際是他們是相同的。首先,你還是需要先建立一個context,放進你需要的資料。上面描述的例子中不同的是使用了mergeTemplate()方法,mergeTemplate()方法呼叫了底層的Runtime類中的方法載入了模板,然後合併內容。在上面的第二個例子中,通過字串動態建立模板,這個操作就類同於基本模式中的選擇模板的操作;後面的merge()方法就呼叫了底層的方法來合併模板內容。
所以上面的例子跟文章開始描述的 基本流程 是一樣,只不過這裡的一些工具方法做了那些重複的苦力活;同時也演示了除了從模板檔案中獲取模板內容外,你也可以動態的建立模板內容。
異常
Velocity在解析和合並模板的過程中可能會丟擲異常。這些異常都繼承RuntimeException,所以沒有顯式捕獲的必要,每一種異常都包含了特定的屬性以提供給最後的呼叫者來獲知異常的具體資訊。這些異常類都放在了org.apache.velocity.exception包下,有如下幾種:
1. ResourceNotFoundException
當資源管理系統找不到請求的相應資源時丟擲。
2. ParseErrorException
在解析Velocity模板語法是出現錯誤時丟擲
3.TemplateInitException
在模板解析的第一個階段丟擲,提示Velocity巨集或者指令初始化時出現的錯誤
4.MethodInvocationException
在渲染模板時呼叫Context中某個物件的方法是出現錯誤時丟擲。該異常包裝了呼叫物件的方法丟擲的異常並傳遞給應用,讓你能夠在執行時處理這些物件中的問題。
在每次丟擲上面的這些異常時都會記入到執行日誌中。可通過閱讀javadoc api 文件瞭解更多詳細資訊。
其他細節
雖然上面的程式碼中使用的是預設屬性,但是設定自定義的屬性也是非常簡單的。你需要做的就是建立一個properties檔案,在檔案中新增你需要自定義的屬性,然後傳遞檔案的路徑給Velocity工具類中的init(String)方法;或者建立一個java.util.Poperties 物件,往這個物件中自定義的屬性,然後傳遞給Velocity工具類的init(Properties)方法。後一種方式顯得靈活些,因為你可以通Properties的load()方法載入一個properties檔案,更好的是你應用或框架中動態傳入執行時設定的屬性。你可以方便的將應用用到的所有屬性組合放到一個properties檔案中。
如果你想從其他目錄而非當前目錄中載入模板檔案,我們可以通過下面這種方式來完成
... import java.util.Properties; ... public static void main( String args[] ) { /* 首先,我們還是初始化執行時引擎 */ Properties p = new Properties(); p.setProperty("file.resource.loader.path", "/opt/templates"); Velocity.init( p ); ...
為了能順利執行上面的程式碼,你需要有一個 /opt/templates 目錄,並且把檔案testtemplate.vm放到該目錄下。如果你按照上面的做了,還是出現問題,可以檢視velocity.log檔案確定具體原因,畢竟閱讀錯誤日誌是你定位問題的不二選擇。
... VelocityEngine velocityEngine = new VelocityEngine(); ExtendedProperties eprops = null; if (props==null) { eprops = new ExtendedProperties(); } else { eprops = ExtendedProperties.convertProperties(props); } // 現在,我們用一個物件例項來設定屬性 eprops.setProperty("name", object); ... velocityEngine.setExtendedProperties(eprops); velocityEngine.init(); ...
你可以考慮嘗試使用下面章節描述的[應用屬性]特性。