Velocity官方指南-使用Velocity
如果你使用的是VelocityViewServlet或者其他的web框架,你不會直接調(diào)用到Velocity。但是,如果在非web的應(yīng)用中或者自己編寫的web框架時,你將會像上面說的基本流程一樣直接調(diào)用到Velocity 引擎。另外一個需要記住的重點(diǎn)是,必須在使用Velocity合并模版之前,初始化Velocity引擎。
Velocity輔助類
Velocity中包含一個叫做Velocity( org.apache.velocity.app.Velocity )的應(yīng)用工具類。這個類的主要是提供一些初始化Velocity時必須的方法,以及簡化Velocity使用的一些常規(guī)方法。這個在工程的javadoc中有描述,可通過閱讀javadoc來獲取更詳細(xì)的說明。本篇文檔只是教程;所以,如果需要了解完整的API信息,javadoc是你***的選擇。
Velocity運(yùn)行時引擎是為在同一個jvm中的其他使用者提供資源獲取,日志記錄等其他服務(wù)的單個實(shí)例。因此,運(yùn)行時引擎只會初始化一次。你可以嘗試初始化多次,但是只有***次是有效的,后面的初始化操作都會被忽略。Velocity工具類提供了五個用來配置運(yùn)行時引擎的方法。
這五個配置方法如下:
- setProperty( String key, Object o )
設(shè)置屬性鍵key對應(yīng)屬性值為o。值通常為字符串,在特殊情況下也可以是逗號分隔的一串值(如”foo,bar,woogie”),當(dāng)然也可以其他值。 - Object getProperty( String key )
獲取屬性鍵key對應(yīng)的值。需要注意的是返回值的類型,不僅僅只是字符串類型 - init()
使用jar包中的默認(rèn)properties文件中配置的屬性初始化運(yùn)行時引擎 - init(Properties p)
使用類型為java.util.Properties參數(shù)出入的屬性來初始化運(yùn)行時引擎 - init( String filename )
使用文件名為filename的properties文件中的屬性值初始化運(yùn)行時引擎
需要注意的是,在上面的這五個方法中,默認(rèn)的properties是基礎(chǔ)的配置,額外的properties是用來替換默認(rèn)配置中對應(yīng)的屬性。沒有被替換的默認(rèn)屬性還將繼續(xù)發(fā)揮作用。這有利于你只需替換你感興趣的,而不需要整個都替換掉。
另外需要注意的是,init() 方法可以在應(yīng)用中被調(diào)用多次,這并不會帶來其他影響。但是只有在***調(diào)用時的引擎配置才會生效,后面調(diào)用的init()使用的配置都會被忽略。
最常見的初始化Velocity的方式,通常如下:
1 按照org/apache/velocity/runtime/defaults/velocity.properties 文件中的格式配置你需要替換的屬性,放在文件中或者放到j(luò)ava.util.Properties中,然后調(diào)用init(filename) 或者 init(Properties)
2 通過setProperty() 方法設(shè)置單個的配置項(xiàng),然后調(diào)用initial()。 這種方法通常在擁有自己的配置管理系統(tǒng)的高層應(yīng)用中。例如,允許應(yīng)用基于運(yùn)行時產(chǎn)生的值來配置Velocity
一旦運(yùn)行時引擎初始化完成,你就可以進(jìn)行任何你想做的了。當(dāng)然,主要還是圍繞著渲染模板輸出內(nèi)容到輸出流中,Velocity輔助類中的一些方法可以幫你輕松搞定,下面是這些方法以及他們做的事情的簡要描述:
- evaluate( Context context, Writer out, String logTag, String instring )
- evaluate( Context context, Writer writer, String logTag, InputStream instream )這些方法使用傳入的contexxt對象渲染一個輸入,輸出到Writer中;輸入的內(nèi)容可以是一個字符串或者一個InputStram。這個方法經(jīng)常用在替換字符串中的標(biāo)記、渲染模板內(nèi)容保存在數(shù)據(jù)庫中或其他的非文具的存儲中,或者動態(tài)生成內(nèi)容時。
- invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer )
通過這個方法可以直接調(diào)用到Velocity宏,也可以通過上面的evalutae()方法調(diào)用。你只需要給你的vm模板取一個名字,創(chuàng)建一個提供給vm使用的數(shù)組,一個包含數(shù)據(jù)的context,以及用于輸出內(nèi)容的Writer。需要注意的是這里說的提供給vm使用的數(shù)組中的元素只能是context中有的key,而不是其他用作參數(shù)傳入vm的字符串。這點(diǎn)在后面的版本有可能修改。
- mergeTemplate( String templateName, Context context, Writer writer )通過這個方法可以非常方便的調(diào)用到Velocity提供的模板出來和渲染的功能。這個方法會讀取和渲染模板。文件加載器會根據(jù)你設(shè)置的properties的設(shè)置來加載模板內(nèi)容,所以可以Velocity提供的文件處理的優(yōu)勢以及預(yù)解析模板緩存的優(yōu)勢。
- boolean templateExists( String name )判斷當(dāng)前配置的資源加載起能否都讓渠道名為name的模板文件。
通過上面的文檔,我們已經(jīng)清楚了這些基礎(chǔ)的輔助方法,現(xiàn)在就可以地編寫使用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[] )
- {
- /* 首先,初始化運(yùn)行時引擎,使用默認(rèn)的配置 */
- Velocity.init();
- /* 創(chuàng)建Context對象,然后把數(shù)據(jù)放進(jìn)去 */
- 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 );
- }
- }
在運(yùn)行程序之前,我們需要把模板文件testtemplate.vm放到與程序相同的目錄下(因?yàn)槲覀兪褂媚J(rèn)配置,默認(rèn)配置中指定的模板加載路徑就是程序的當(dāng)前目錄)。運(yùn)行上面代碼后,將會輸出:
template : Hi! This Velocity from the Jakarta project.
string : We are using Jakarta Velocity to render this.
模板文件testtemplate.vm文件的內(nèi)容是:
Hi! This $name from the $project project.
好了,上面就是我們使用Velocity渲染模板需要做的事情了。在代碼中沒有必要既調(diào)用mergeTemplate()又調(diào)用evaluate(),這里只是為了演示才同時使用了。你一般只需要使用其中一個方法就夠了。但是到底調(diào)用一個還是兩個,需要根據(jù)你程序的具體要求確定。
這里看起來與文章最開始描述的 基本流程 有一些差別,但實(shí)際是他們是相同的。首先,你還是需要先創(chuàng)建一個context,放進(jìn)你需要的數(shù)據(jù)。上面描述的例子中不同的是使用了mergeTemplate()方法,mergeTemplate()方法調(diào)用了底層的Runtime類中的方法加載了模板,然后合并內(nèi)容。在上面的第二個例子中,通過字符串動態(tài)創(chuàng)建模板,這個操作就類同于基本模式中的選擇模板的操作;后面的merge()方法就調(diào)用了底層的方法來合并模板內(nèi)容。
所以上面的例子跟文章開始描述的 基本流程 是一樣,只不過這里的一些工具方法做了那些重復(fù)的苦力活;同時也演示了除了從模板文件中獲取模板內(nèi)容外,你也可以動態(tài)的創(chuàng)建模板內(nèi)容。
異常
Velocity在解析和合并模板的過程中可能會拋出異常。這些異常都繼承RuntimeException,所以沒有顯式捕獲的必要,每一種異常都包含了特定的屬性以提供給***的調(diào)用者來獲知異常的具體信息。這些異常類都放在了org.apache.velocity.exception包下,有如下幾種:
1. ResourceNotFoundException
當(dāng)資源管理系統(tǒng)找不到請求的相應(yīng)資源時拋出。
2. ParseErrorException
在解析Velocity模板語法是出現(xiàn)錯誤時拋出
3.TemplateInitException
在模板解析的***個階段拋出,提示Velocity宏或者指令初始化時出現(xiàn)的錯誤
4.MethodInvocationException
在渲染模板時調(diào)用Context中某個對象的方法是出現(xiàn)錯誤時拋出。該異常包裝了調(diào)用對象的方法拋出的異常并傳遞給應(yīng)用,讓你能夠在運(yùn)行時處理這些對象中的問題。
在每次拋出上面的這些異常時都會記入到運(yùn)行日志中??赏ㄟ^閱讀javadoc api 文檔了解更多詳細(xì)信息。
其他細(xì)節(jié)
雖然上面的代碼中使用的是默認(rèn)屬性,但是設(shè)置自定義的屬性也是非常簡單的。你需要做的就是創(chuàng)建一個properties文件,在文件中添加你需要自定義的屬性,然后傳遞文件的路徑給Velocity工具類中的init(String)方法;或者創(chuàng)建一個java.util.Poperties 對象,往這個對象中自定義的屬性,然后傳遞給Velocity工具類的init(Properties)方法。后一種方式顯得靈活些,因?yàn)槟憧梢酝≒roperties的load()方法加載一個properties文件,更好的是你應(yīng)用或框架中動態(tài)傳入運(yùn)行時設(shè)置的屬性。你可以方便的將應(yīng)用用到的所有屬性組合放到一個properties文件中。
如果你想從其他目錄而非當(dāng)前目錄中加載模板文件,我們可以通過下面這種方式來完成
- ...
- import java.util.Properties;
- ...
- public static void main( String args[] )
- {
- /* 首先,我們還是初始化運(yùn)行時引擎 */
- Properties p = new Properties();
- p.setProperty("file.resource.loader.path", "/opt/templates");
- Velocity.init( p );
- ...
為了能順利運(yùn)行上面的代碼,你需要有一個 /opt/templates 目錄,并且把文件testtemplate.vm放到該目錄下。如果你按照上面的做了,還是出現(xiàn)問題,可以查看velocity.log文件確定具體原因,畢竟閱讀錯誤日志是你定位問題的不二選擇。
- ...
- VelocityEngine velocityEngine = new VelocityEngine();
- ExtendedProperties eprops = null;
- if (props==null) {
- eprops = new ExtendedProperties();
- } else {
- eprops = ExtendedProperties.convertProperties(props);
- }
- // 現(xiàn)在,我們用一個對象實(shí)例來設(shè)置屬性
- eprops.setProperty("name", object);
- ...
- velocityEngine.setExtendedProperties(eprops);
- velocityEngine.init();
- ...
你可以考慮嘗試使用下面章節(jié)描述的[應(yīng)用屬性]特性。