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(); ...
你可以考慮嚐試使用下麵章節描述的[應用屬性]特性。
最後更新:2017-05-22 14:33:40