Velocity java開發指南

目    錄
1.開始入門. 3
1.Getting Started3
2.Dependencies 依賴資源. 3
2.參考資源:. 4
3.它是如何工作的?. 4
1.基本使用模式. 4
4.單實例還是多實例(To Singleton Or Not To Singleton...)?6
1.Singleton Model6
2.Separate Instance6
5. The Context7
1.The Basics7
2.在模板中用#foreach指令支持迭代對象. 8
3.Context Chaining9
4.模板中的己創建對象. 10
5.Context對象的其它用法. 10
6.Using Velocity In Servlets11
1.Servlet Programming11
2.Deployment13
7. Using Velocity In General Applications13
1.The Velocity Helper Class14
2.Exceptions16
3.其它細節. 16
8.Application Attributes17
9.EventCartridge and Event Handlers(事件分發和處理)17
1.Event Handlers17
2.Using the EventCartridge使用事件分發器. 18
10.Velocity Configuration Keys and Values(配置參數名字和值說明)20
1.Runtime Log20
2.字符集編碼問題. 21
3.#foreach() Directive21
4.#include() and #parse() Directive21
5.資源管理. 21
6.Velocimacro(宏配置). 22
7.語義更改. 23
8.運行時配置. 23
11.Configuring the Log System(日誌記錄配置)23
1.一般的可選日誌功能:23
2.Simple Example of a Custom Logger25
12.Configuring Resource Loaders(資源裝載器配置)26
1.Resource Loaders26
2.Configuration Examples27
3.插入定製資源管理器和Cache實現. 29
13.Template Encoding for Internationalization(字符編碼和國際化)29
14.Velocity and XML30
15.FAQ (Frequently Asked Questions)32
1.Why Can't I Access Class Members and Constants from VTL?32
2.Where does Velocity look for Templates?33
16.Summary33
17.Appendix 1 : Deploying the Example Servlet33
 

 

 
1.開始入門
Velocity是一基於java語言的模板引擎,使用這個簡單、功能強大的開發工具,可以很容易的將數據對象靈活的與格式化文檔組裝到一起;希望本文能指引使用velocity在開發基於servlet或一般java應用程序的應用上快速起步。
1.Getting Started
取得Velocity並在你的機器上開始運行很容易,以下是全部詳細的說明:
取得Velocity發佈版本,go here。
目錄及文件說明:
Velocity-X.jar 完整的velocity jar包一般命名格式爲velocity-X.jar,其中X是當前版本號。注意這個jar包不包含Velocity所必須依賴的其它jar包(具體見後)。
SRC:完整的源文件代碼目錄
Examples. 完整的aplication或web App例子。
docs :Veocity文檔目錄
build: 使用ant編譯源碼時所需的lib.
OK,現在就可以開始使用了.請將Velocity-x.jar放到你的classpath中或webapp的lib下。
當然,我們強烈建議你先運行其中的例子,以感受Velocity的優異之處.
2.Dependencies 依賴資源
Velocity可運行於JDK1.4或JRE1.4及其以上版本.
Velocity也依賴於其它一些jar包,在分發版本的 build/lib 有,如果你下載的是二進制分發版本,需要到以下地址下載其它依賴包.
Jakarta Commons Collections – 必須.
Jakarta Avalon Logkit – 可選,但強列建議加上,以便輸出日誌信息.
Jakarta ORO – 可選,僅當用到org.apache.velocity.convert.WebMacro template 這個模板轉換工具時.
2.參考資源:
一些優秀的資源和例程列表如下:
開發者郵件列表 mail-lists.
郵件檔案表 : http://www.mail-archive.com是很好的一個資源庫.可以以’Velocity’爲關鍵字進行搜索。
源代碼(源碼分發版本) : src/java/... : 含有Velocity project的所有源碼
應用程序例程1 : examples/app_example1 : 一個很簡單的示例如何在一般應用程序中使用Velocity.
應用程序例程1 2 : examples/app_example2 : 如何在應用程序中使用Velocity工具類.
servlet example : examples/servlet_example1 :示例如何在servlet中用Velocity 輸出模板.
logger example : examples/logger_example : 如何定製Velocity的日誌工具.
XML example : examples/xmlapp_example : 使用 JDOM 從 Velocity 模板讀取內容. 還包含一個遞歸調用宏的示例.
event example : examples/event_example : 在Velocity 1.1 中使用事件處理API。
Anakia application : examples/anakia : 示例用stylesheet 美化 xml 數據。
Forumdemo web app : examples/forumdemo : 一個基於servlet的論壇功能實現示例.
templates : test/templates :全面展示VTL(Velocity Template Lanauage)功能的模板集合。
context example : examples/context_example : 兩個示例如何重寫(繼承) Velocity context 功能的例子(針對高級用戶).
 
3.它是如何工作的?
1.基本使用模式
在application program或servlet中使用Velocity中,一般通過如下步驟:
對於所有應用,第一步是要初始化Velocity, 一般使用唯一實例模式(Singleton),如Velocity.init().
創建一個Context object.
將你的數據對象加入到Context對象中.
使用Velocity選擇一個模板.
合併模板和數據導出到輸出流.
下面的代碼,通過使用org.apache.velocity.app.Velocity的單實例模式,合併輸出:
 
import java.io.StringWriter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.MethodInvocationException;
 
//初始化
Velocity.init();
//取得VelocityContext對象
VelocityContext context = new VelocityContext();
//向context中放入要在模板中用到的數據對象
context.put( "name", new String("Velocity") );
Template template = null;
//選擇要用到的模板
try
{
   template = Velocity.getTemplate("mytemplate.vm");
}
catch( ResourceNotFoundException rnfe )
{
   // couldn't find the template
}
catch( ParseErrorException pee )
{
 // syntax error : problem parsing the template
}
catch( MethodInvocationException mie )
{
 // something invoked in the template
 // threw an exception
}
catch( Exception e )
{}
 
StringWriter sw = new StringWriter();
//合併輸出
template.merge( context, sw );


 
以上是基本的使用模式,看起來非常簡潔!這些都是一般情況下使用Velocity所必須的步驟. 但你可能不想這樣按部就班的編寫代碼 –Velocity提供了一些工具以更容易的方式在servlet或應用程序中使用。在這個指南的後面, 我們將討論在servlet和普通應用程序中更好的用法.
 
4.單實例還是多實例(To Singleton Or Not To Singleton...)?
1.Singleton Model
這是系統默認的模式, 這樣在jvm(應用程序)或web aplication(一個web程序)中只存在一個Velocity engine實例共享使用。. 這對於配置和共享資源來說非常方便. 比如, 這非常適合用於支持 Servlet 2.2+ 的web application中,每一個web app持有它自己的唯一Velocity實例, 它們可以共享templates, a logger等資源. Singleton可以直接通過使用org.apache.velocity.app.Velocity 類, 如下例子:
import org.apache.velocity.app.Velocity;
import org.apache.velocity.Template;
 
/*
 * Configure the engine - as an example, we are using
 * ourselves as the logger - see logging examples
 */
 
Velocity.setProperty( Velocity.RUNTIME_LOG_LOGSYSTEM, this);
 
/*
 * now initialize the engine
 */
 
Velocity.init();
 
 
Template t = Velocity.getTemplate("foo.vm");


2.Separate Instance
在1.2版本以後, 可以在 JVM (or web application.)創建,配置,使用多個Velocity實例;當你希望在同一程序中,對每個實例獨立配置時它們的 template directories, loggers等資源時,這是非常方便的.  多實例化時,我們要用到 org.apache.velocity.app.VelocityEngine類. 下面是一個例子,請注意和上面singleton example同法時的不同:
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.Template;
 
...
 
/*
 * create a new instance of the engine
 */
 
VelocityEngine ve = new VelocityEngine();
 
/*
 * configure the engine. In this case, we are using
 * ourselves as a logger (see logging examples..)
 */
 
ve.setProperty( VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this);
 
/*
 * initialize the engine
 */
 
ve.init();
 
...
 
Template t = ve.getTemplate("foo.vm");


可以看到,這是非常簡單的直接使用就行了.無論用singleton 或 separate instances都不需要改變你程序的上層結構及模板內容.
對於開發人員而言, 你應在以下兩個類中二者擇一的使用
org.apache.velocity.app.Velocity 應用於 singleton model, org.apache.velocity.app.VelocityEngine一般用於non-singleton model ('separate instance').
 
 
5. The Context
1.The Basics
'context' 是Velocity中的一個核心概念, 這是一個從系統的”數據容器(a container of data)”引出的一個常見概念. 這裏的context在java程序層和模板視圖層(template layer ( or the designer ))之間扮演着一個”數據對象傳送者”'(carrier')的角色. 做爲程序員,你可以將你程序生成的不同類型的數據對象放入context中,對於視圖設計來說,這些對象(包含它們的數據域和命令)將在模板元素中被引用到(references)。一般來說,你將和視圖設計者一起決定應用需要哪些數據,可以說,你放入context中的數據對象在這裏成爲一種”API”,由視圖設計者在模板中來訪問.因此,在向context中決定放放哪些數據對象時,程序的設計者需要仔細分析視圖表現所需的數據內容。
雖然Velocity中你可以創建自己的Context類來支持一些個性化的應用(比如,一個訪問,保存LDAP Server服務的context),你可以實現VelocityContext這個己封裝較爲完務的基類。
VelocityContext對象基本上可滿足大多的應用, 我們強烈建議你除非在特別的情況下,否則不要創建自己的Context實現!
VelocityContext用法十分簡單,類似於Hashtable class.下面是這個接口提供的兩個基本用法:
public Object put(String key, Object value);
public Object get(String key);
很像Hashtable吧,這裏的value必須是一個java.lang.Object類(不能是原始類型,像int,boolean), 也不能是null值. 原始類型(Fundamental types like int or float)必須被包裝爲一個適當對應的Object型.
OK,以上就是context 對象的用法概念,很簡單我們卻哆嗦這麼:). 關於其更多的介紹,請見API documentation.
2.在模板中用#foreach指令支持迭代對象
在放入context前,你對對象有着全面的操作自由. 但就像所有的自由一樣, 你必須遵守一些規則,承擔一些責任,因此,你必須理解Velocity是如何使用對象的,Velocity的VTL支持多種類型的集合類型(collection types) 使用#foreach().
Object [] 一般對象數組. Velocity將內功能會將它包裝成功之爲一個實現Iterator interface對象, 這個轉換是不需要程序員或視圖設計者參與.
java.util.Collection :Velocity會使用他們的標準iterator() 得到一個可以迭代中使用的 Iterator對象,如果你使用自己的實現了Collection interface的對象,要確保它的iterator() 命令返回一個可用的Iterator.
java.util.Map接口對象,Velocity 使用其頂層接口的values() 命令得到一個實現 Collection interface的對象, 應用其iterator()再返回一個Iterator.
java.util.Iterator使用特別注意 : 如果一個Iterator對象被放置到context中,當在模板中有多個 #foreach()指令中,這些#foreach() 將順序執行,如果第一個調用失敗,後面的將阻塞且不能重置.
java.util.Enumeration USE WITH CAUTION : 如同java.util.Iterator一樣的道理,Velocity將使用的是一個不能重置('non-resettablity')或者說一個final型的對象.
因此,僅當在不得己的情況下,Iterator and Enumeration 對象纔有必要放入context中---也許你有更好的辦法不使用他們.
例如,你可以將如下代碼:
Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");
 
context.put("words", v.iterator() );
 
替換爲:
context.put("words", v );


 
3.Context Chaining
另外一個新引入的概念是context chaining.有時也叫做context wrapping(有點類似與servlet中的chain), 這個高級特性讓你可以連結多個獨立的Velocity的contexts,以便在template中使用.
以下是這種用法的代碼示例 :
VelocityContext context1 = new VelocityContext();
 
context1.put("name","Velocity");
context1.put("project", "Jakarta");
context1.put("duplicate", "I am in context1");
 
VelocityContext context2 = new VelocityContext( context1 );
 
context2.put("lang", "Java" );
context2.put("duplicate", "I am in context2");
 
template.merge( context2, writer );


在上面的代碼中, context2 做爲context1的chains. 這意味着你在模板中可以使用放入這兩個context中的任何一個對象, 當兩個context中有相同的key中,在模板中輸出時,將會輸出最後一個key的值,如上例key爲duplicate的值將輸出爲 "I am in context2".
其實,在上例中不存在duplication, 或'covering', context1中的string "I am in context1" 依然可以通過context1.get("duplicate")方法得到. 但在上例中,模板中引用 '$duplicate' 將會返回 'I am in context2', 而且模板不能再訪問到context1中的'I am in context1'.
另外要注意的是,當你嘗試在模板中加入信息,比如使用#set()聲明,這將對所己輸出的模板產生影響.
如前所述, Velocity context類也是或擴展的, 但在這份指南中沒有述及. 如果你有興趣,可以查看org.apache.velocity.context 中的代碼以瞭解contexts 是如何生成,java數據對象以何機制傳出的. 例程 examples/context_example有一些示例展現.
4.模板中的己創建對象
Java代碼中的數據對象與模板交互有兩種常見方式:
模板設計者從模板中執行程序員放入到context中的java對象的命令:
#set($myarr = ["a","b","c"] )
$foo.bar( $myarr )
當模板加入一個對象到context中,模板合併輸出後,java代碼將可以訪問這些對象.
#set($myarr = ["a","b","c"] )
#set( $foo = 1 )
#set( $bar = "bar")
這裏述及這些技巧有些過早,但現在必須理解以下概念:
The VTL通過context或method所傳的 [ 1..10 ] and ObjectArray ["a","b"] 是java.util.ArrayList對象. 因此你的對象的命令設計時,要具有兼容性.
Numbers在context中將被包裝爲Integers, strings,當然就是Strings了.
Velocity會適當的根據調用的參數類型適配對象的調用命令, setFoo( int i )將一個 int 放入context 和 #set()是不會衝突的.
5.Context對象的其它用法
每一個VelocityContext(或任意源自AbstractContext)的對象,都是一個封裝好指定規則的的存儲節點,對於一般開發都來說,只需使用就是.但這裏還有一些你應知道的特性:
考慮以下情況:
你的模板重複使用VelocityContext object.
Template caching is off.
反覆調用getTemplate() 命令.
這都有可能引起 VelocityContext的內存泄露( 'leak' memory )---當它彙集過多的數據對象時,因此強烈建議你做到以下幾點 :
在每個模板渲染過種中(template render process)創建一個新的VelocityContext. 這會防止過多的cache data. 當需要重用一個 VelocityContext 因爲它內部己放置了數據對象, 你只需要像這樣簡單的包裝一下:VelocityContext useThis = new VelocityContext( populatedVC );具體可以參看 Context chaining 獲取更多信息.
打開模板的caching功能. 以防止重複解析模板,當然,這會要求服務器有更高的性能.
在迭代操作時,要重用模板對象. 這樣將不會對Velocity造成過大壓力, 如果緩存關閉, 就需要每次都讀取和解析模板, 導致 VelocityContext 中每次都要保存大量新的信息.
 
6.Using Velocity In Servlets
1.Servlet Programming
Velocity最通常用在servlet中做爲www服務. 有非常多的理由告訴你這項任務是最適合Velocity完成的,最重要的一個就是Velocity's可以分離視圖(表現層和)代碼層.在這裏可以看到更多的理由this.
在servlet中使用Velocity是非常簡單的. 你只需要extend 己有的 VelocityServlet class和一個必須實現的方法: handleRequest().
public Template handleRequest( HttpServletRequest, HttpServletResponse, Context )
這個方法直接傳送HttpServletRequest 和 HttpServletResponse objects,. 這個方法可以返回null值表示所有處理己經完成, 相對而言,指示velocity調用velocity requestCleanup()更爲常用. 如下代碼示例(在例程中有)
public class SampleServlet extends VelocityServlet
{
    public Template handleRequest( HttpServletRequest request,
                                   HttpServletResponse response,
                                   Context context )
    {
 
        String p1 = "Jakarta";
        String p2 = "Velocity";
 
        Vector vec = new Vector();
        vec.addElement( p1 );
        vec.addElement( p2 );
 
        context.put("list", vec );
 
        Template template = null;
 
        try
        {
            template = getTemplate("sample.vm");
        }
        catch( ResourceNotFoundException rnfe )
        {
         // couldn't find the template
        }
        catch( ParseErrorException pee )
        {
          // syntax error : problem parsing the template
        }
        catch( Exception e )
        {}
 
        return template;
    }
}


 
看起來好熟悉吧? 除過處理一些異常,基本的功能Velocity都己爲你準備好了, 就連在應用程序中要你寫的merge() 這一步,VelocityServlet自己也己處理,這就是基本的用法:取得context, 加入我們自己的對象最後返回模板 template.
默認的 Context是作爲 handleRequest() 傳入的. 可以使用以下常量直接訪問 request和response對象,VelocityServlet.REQUEST (value = 'req') and VelocityServlet.RESPONSE (value = 'res') ,如下是java例程 :
public Template handleRequest( Context context )
{
    HttpServletRequest request = (HttpServletRequest) context.get( REQUEST );
    HttpServletResponse response = (HttpServletResponse) context.get( RESPONSE );
 
   ...
}
可以在模板中如下訪問:
#set($name = $req.getParameter('name') )
 
一些更高級的用法,如VelocityServlet base class 可以在處理請求時重寫更多的簽名方法 : Properties loadConfiguration( ServletConfig )
這可以重寫常規的配置方法. 這常用在修改日誌路徑或運行時改寫webapp root的絕對路徑.
 
Context createContext(HttpServletRequest, HttpServletResponse )
你可以創建自己的Context object. 這可以使用更高級的技術, 如數據鏈或預載數據和工具類. 默認的實理僅返回一個己內置request and response 對象的VelocityContext.你直以在模板中直接訪問他們的命令。
 
void setContentType( HttpServletRequest,HttpServletResponse )
你可以自己定義contentType, 或提取client定義的. 默認的contentType類型在velocity.properties文件中配置, 一般來說,默認的"text/html" 類型是不夠詳細的.
 
void mergeTemplate( Template, Context, HttpServletResponse )
你可以生成輸出流(output stream). VelocityServlet使用含有多種輸出對象的池, 在特定情形下,重寫這個命令是有用的.
 
void requestCleanup( HttpServletRequest, HttpServletResponse , Context )
這個調用一般在處理完後做資源的清理工作,如有需要,在這個命令的重寫內容中加上你的代碼.
 
protected void error( HttpServletRequest, HttpServletResponse, Exception )
在處理中,當錯誤發生時,這個方法會被調用. 默認的實現是將發送一個簡單的HTML格式的錯誤內容到客戶端. 你可以重寫以定製錯誤處理.
更多的信息,請參考 API documentation.
 
 
2.Deployment
發佈基於Velocity的servlets 時,需要參數來配置 Velocity runtime. 在Tomcat上, 一個簡單的方法是將velocity.properties文件放到你的webApp root目錄下 (webapps/appname ) 然後在 WEB-INF/web.xml 文件中加上以下幾行 :
<servlet>
  <servlet-name>MyServlet</servlet-name>
 <servlet-class>com.foo.bar.MyServlet</servlet-class>
 <init-param>
      <param-name>properties</param-name>
      <param-value>/velocity.properties</param-value>
 </init-param>
</servlet>
 
以上配置將確保MyServlet 可以被載入,Velocity也將會使velocity.properties來初始化.
注意: Velocity 在運行時使用的是單實例模式, 因此將 velocity-XX.jar放到YourWebAPP/WEB-INF/lib目錄即可. 但當多個webApp要使用時,放入CLASSPATH 或Servlet容器的頂層 lib是最好的選擇.
7. Using Velocity In General Applications
Velocity被設計爲一個通用的功具包,它也常用於一般的應用程序中. 如這篇指南開始所討論的那樣, 另外,這裏還有一些對一般應用程序來說很有用的工具類:
1.The Velocity Helper Class
Velocity 提供一個 utility class ( org.apache.velocity.app.Velocity ). 這個類中提共一個初始化Velocity所必需的方法, 具體的細節可以到文檔中查看.
Velocity runtime engine在運行時是單實便模式,它可以給 Velocity的用戶通過同一個jvm提供日誌,資源訪問方法. 這個engine運行時僅初始化一次. 當然,你可以嘗初對init()進行多次調用, 但只有第一次有效. The Velocity utility class 目前提供5個命令來配置運行時engine:
這5個配置方法是 :
setProperty( String key, Object o ) 這麼簡單,不用解釋了吧.
Object getProperty( String key ) 嗯,也不說了
init() 用默認的參數文件初始化
init( Properties p ) 用一個特定的java.util.Properties對象初始化.
init( String filename ) 用指定名字的參數文件初始化
注意:除非你指定了,否則初始時會使用默認參數. 僅當在調用init()時的配置會對系統生效。
通用的 initializing Velocity 一般步驟如下:
設置你指定的配置參數值在文件org/apache/velocity/runtime/defaults/velocity.properties中,或放入java.util.Properties, 在第一次調用init( filename )或 init( Properties ) .
單獨設置每個配置參數通過調用 setProperty(),最後調用init(). 這適合一些一有自己的CMS系統(configuration management system )程序。
運行時一但初始化, 你就可以開始工作了.. 只需要考慮組裝什麼樣的數據對象到你的輸出模板上, Velocity utility class 可以幫你更容易做到這些.這裏有一些命令摘要描述如下 :
evaluate( Context context, Writer out, String logTag, String instring ) evaluate( Context context, Writer writer, String logTag, InputStream instream ) 這個命令用來修飾輸入流,你可以將包含TVL的模板文件從內置的String對象、DB、或非文件系統的數據源輸入,.
invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer ) 你可以直接訪問Velocimacros. 也可以通過evaluate()命令來完成,這裏你只需簡單的傳入VM文件名(模板文件), 創建一組VM參數放到Context,然後輸出. 注意放入Context的參數必須是鍵-值對出現的.
mergeTemplate( String templateName, Context context, Writer writer ) 這個命令用來執行Velocity的模板合併和渲染功能. 它將應用context中的數據對象到指定文件名的模板中.將結果輸出的指定的Writer. 當然,如果沒有特別的需要,不建議這麼做.
boolean templateExists( String name ) 檢測當前配置的資源中,是否存在name的模板名.
這樣,我們就更容易編寫使用Velocity的java代碼了. Here it is
import java.io.StringWriter;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
 
public class Example2
{
    public static void main( String args[] )
    {
        /* first, we init the runtime engine. Defaults are fine. */
 
        Velocity.init();
 
        /* lets make a Context and put data into it */
 
        VelocityContext context = new VelocityContext();
 
        context.put("name", "Velocity");
        context.put("project", "Jakarta");
 
        /* lets render a template */
 
        StringWriter w = new StringWriter();
 
        Velocity.mergeTemplate("testtemplate.vm", context, w );
        System.out.println(" template : " + w );
 
        /* lets make our own string to render */
 
        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.
 
where the template we used, testtemplate.vm, is
Hi! This $name from the $project project.
在這裏,我們不得不使用 mergeTemplate() and evaluate() in our program. 這主要是爲了示例. 在一般應用中,這是很少使用到的,但我們提供了根據具體需要自由使用的途徑.
這有點不和我們這篇文張本意的“基礎功能指南”這一意圖, 但我想這是必須知道的. 首先, 你得到一個放置了數據對象的context對象, 不用的是使用了命令 mergeTemplate(), mergeTemplate() 所做的工作是合併模板, 在運行時調用低層功能(lower-level). 接下來,通過evaluate()方法使用一個String動態生成模板.
這是同樣簡單的使用Velocity engine的方式,這些可選功能也許可以幫你做一些重複的工作,比如生成模板的模板:)
2.Exceptions
There are three exceptions that Velocity will throw during the parse / merge cycle在解析/合併(parse/merge)模板週期中,Velocity或能出現三個Velocity異常.另外,還可能會有 IO problems, etc. Velocity自定義的異常可以在package org.apache.velocity.exception:
ResourceNotFoundException 當velocity的資源管理器無法找到系統請求的資源時出現.
ParseErrorException 當parse模板文件中的 VTL 語法出錯時出現.
MethodInvocationException Thrown when a method of object in the context thrown an exception during render time,當處理模板中,context中的對象的命令調用出錯時.
當然,每一次出錯時,相關的消息內容會保存到運行時的日誌文件中,獲取更多資料,請查看API文檔。
3.其它細節
在以上的一些例程中,使用默認的properties配置你的程序非常方便. 但你可以根據自己的需要,用自己的配置文件通過在Velocity中調用init(String yourFileName)命令傳入你的配置文件名, 或創建一個保存了你的配置參數的 java.util.Properties對象,通過調用 init(Properties)命令來實現. 這其中後一個方式是很便捷的, 你可以直接將一個獨立的參數文件通過load()調用,將其中的配置參數置入Properties對象中. 你還可以做得列好---你可以在運行時運態的從你的程序框架中加入參數. 這樣,你應可以將Velocity的配置參數和你原來應用的配置在不做大的更改情況下共用。
當需要從一個指定的目錄提取模板文件時(默認爲當前目錄),你可以這樣做 :
import java.util.Properties;
 ...
 
public static void main( String args[] )
{
    /* first, we init the runtime engine. */
 
    Properties p = new Properties();
    p.setProperty("file.resource.loader.path", "/opt/templates");
    Velocity.init( p );
 
    /* lets make a Context and put data into it */
 
 ...


這樣,Velocity在需要時,將自動到/opt/templates目錄下查找模板文件,如果有問題可以查看velocity.log中所記錄的出詳細出錯信息。它會幫你有效的消息錯誤.
 
8.Application Attributes
Application Attributes (應用程序屬性)是和VelocityEngine 的運行時實例(Runtimeinstance)相關聯的,名-值對(name-value pairs)格式的參數,可用來存運RuntimeInstance時的信息.
設計這個功能的目標是Velocity程序需要與應用層或用戶定製部分(如日誌,資源,裝載器等)通信.
The Application Attribute API is very simple. From the application layer,在 VelocityEngine 和 Velocity classes 中都有如下命令:
public void setApplicationAttribute( Object key, Object value );
這裏的key與value的設置沒有任何限制,可以在程序運行中設置,這是不同與Velocity的init()調用的.
內部程序可以通過接口 RuntimeServices 如下的命令來取得這些參數:
public Object getApplicationAttribute( Object key ):
9.EventCartridge and Event Handlers(事件分發和處理)
1.Event Handlers
從Velocity1.1版本起,加入了良好的事件處理機制. 你可將自己的事件處理器類註冊給事件分發器(EventCartridge) , 事件分發器實際上扮演着Velocity engine在運行時訪問事件處理器(event handlers)的一個代理的角色。目前,有3種Velocity系統定義的事件可以被處理,它們都位與包org.apache.velocity.app.event 中.
org.apache.velocity.app.event.NullSetEventHandler
當模板中#set() 指令關聯的是一個空值時, 這是很常見的一個問題. The NullSetEventHandler 事件處理器可以讓你決定如何處理,其接口代碼如下.
public interface NullSetEventHandler extends EventHandler
{
    public boolean shouldLogOnNullSet( String lhs, String rhs );
}
 
org.apache.velocity.app.event.ReferenceInsertionEventHandler
 
A ReferenceInsertionEventHandler 這個事件處理器可以讓開發者在引用對象值如($foo)輸出到模板之前截取修改.
public interface ReferenceInsertionEventHandler extends EventHandler
{
    public Object referenceInsert( String reference, Object value );
}
 
org.apache.velocity.app.event.MethodExceptionEventHandler


 
當用戶數據對象中的某個命令出錯時, 實現了 MethodExceptionEventHandler接口的事件處理器將被調用以獲得具體的命令名字和Exception對象. 事件處理器也可以重組一個有效的對象返回(一般用於統一的異常處理), 或向它的父類throws一個new Exception, MethodInvocationException接口如下:
public interface MethodExceptionEventHandler extends EventHandler
{
    public Object methodException( Class claz, String method, Exception e )
         throws Exception;
}


2.Using the EventCartridge使用事件分發器
可以直接使用一個事件分發器(EventCartridge),如下例程在org.apache.velocity.test.misc.Test中:
...
 
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.ReferenceInsertionEventHandler;
import org.apache.velocity.app.event.MethodExceptionEventHandler;
import org.apache.velocity.app.event.NullSetEventHandler;
 
 ...
 
public class Test implements ReferenceInsertionEventHandler,
                             NullSetEventHandler,
                             MethodExceptionEventHandler
{
    public void myTest()
    {
        ....
 
        /*
         * now, it's assumed that Test implements the correct methods to
         * support the event handler interfaces. So to use them, first
         * make a new cartridge
         */
        EventCartridge ec = new EventCartridge();
 
        /*
         * then register this class as it contains the handlers
         */
        ec.addEventHandler(this);
 
        /*
         * and then finally let it attach itself to the context
         */
        ec.attachToContext( context );
 
        /*
         * now merge your template with the context as you normally
         * do
         */
 
        ....
    }
 
    /*
     * and now the implementations of the event handlers
     */
    public Object referenceInsert( String reference, Object value )
    {
        /* do something with it */
        return value;
    }
 
    public boolean shouldLogOnNullSet( String lhs, String rhs )
    {
        if ( /* whatever rule */ )
            return false;
 
        return true;
    }
 
    public Object methodException( Class claz, String method, Exception e )
         throws Exception
    {
        if ( /* whatever rule */ )
           return "I should have thrown";
 
        throw e;
    }
}
 
 
10.Velocity Configuration Keys and Values(配置參數名字和值說明)
Velocity's runtime configuration is controlled by a set of configuration keys listed below Velocity的運行時配置由一個key-value列表控制.
Velocity中有一些默認的值在以下位置可以找到:
 /src/java/org/apache/velocity/runtime/defaults/velocity.defaults,Velocity基礎配置,它會確保Velocity總是有一個“正常的”配置以便運行.但它不一定是你想要的配置.
任何配置必須在 init()調用前發生纔會在運行時替換掉默認的配置。這意味着你只需改變你需要的而不是所有的配置都要動.
這一節: Using Velocity In General Applications 有關於configuration API的進一步說明.
以下,是默認配置的說明:
1.Runtime Log
runtime.log = velocity.log 用以指定Velocity運行時日誌文件的路勁和日誌文件名,如不是全限定的絕對路徑,系統會認爲想對於當前目錄.
runtime.log.logsystem 這個參數沒有默認值,它可指定一個實現了interface org.apache.velocity.runtime.log.LogSystem.的自定義日誌處理對象給Velocity。這就方便將Velocity與你己有系統的日誌機制統一起來.具體可見Configuring the Log System 這一節.
runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem 上面這行,是一個示例來指定一個日誌記錄器.
runtime.log.error.stacktrace = false runtime.log.warn.stacktrace = false runtime.log.info.stacktrace = false 這些是錯誤消息跟蹤的開關.將會生成大量、詳細的日誌內容輸出.
runtime.log.invalid.references = true 當一個引用無效時,打開日誌輸出. 在生產系統運行中,這很有效,也是很有用的調試工具.
2.字符集編碼問題
input.encoding = ISO-8859-1 輸出模板的編碼方式 (templates). 你可選擇對你模板的編碼方式,如UTF-8.GBK.
output.encoding = ISO-8859-1 VelocityServlet 對輸出流(output streams)的編碼方式.
3.#foreach() Directive
directive.foreach.counter.name = velocityCount 在模板中使用#foreach() 指令時,這裏設定的字符串名字將做爲context key 代表循環中的計數器名,如以上設定,在模板中可以通過 $velocityCount來訪問.
directive.foreach.counter.initial.value = 1 #foreach() 中計數器的起始值.
4.#include() and #parse() Directive
directive.include.output.errormsg.start = directive.include.output.errormsg.end = 使用#include()時,定義內部流中開始和結束的錯誤消息標記,如果兩者都設這屯,錯誤消息將被輸出到流中'.但必須是兩都定義.
directive.parse.maxdepth = 10 定義模板的解析深度,當在一個模板中用#parse()指示解析另外一個模板時,這個值可以防止解析時出現recursion解析.
5.資源管理
resource.manager.logwhenfound = true 定義日誌中的 'found' 務目開關.當打開時,如Resource Manager第一次發現某個資源時, the first time, the resource name and classname of the loader that found it will be noted in the runtime log.
resource.loader = <name> (default = File) Multi-valued key. Will accept CSV for value. (可以有多個以.號分開的值),可以理解爲指定資源文件的擴展名.
<name>.loader.description = Velocity File Resource Loader 描述資源裝載器名字.
<name>.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader 實現的資源裝載器的類名. 默認的是文件裝載器.
<name>.resource.loader.path = . Multi-valued key. Will accept CSV for value. 資源位置的根目錄. 當前配置會使用FileResourceLoader and JarResourceLoader 遍歷目錄下的所有文件以查找資源.
<name>.resource.loader.cache = false 控制裝載器是否對文件進行緩存.默認不存是爲了方便開發和調試. 在生產環境佈署(production deployment)時可設爲true以提高性能, 這裏參數 modificationCheckInterval應設爲一個有效值—以決定多久reload一次.
<name>.resource.loader.modificationCheckInterval = 2 當模把caching打開時,這個以秒爲單位的值指示系統多久檢測一次模板是否己修改以決定是否需要,如果設爲 <= 0, Velocity將不做檢測.
FileResourceLoader 的默認參數完整示例:
resource.loader = file
 
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2
 
6.Velocimacro(宏配置)
velocimacro.library = VM_global_library.vm Multi-valued key. Will accept CSV for value.當Velocity engine運行時,要被載入的含有宏代碼庫的文件名. 所有模板都可訪問宏(Velocimacros ). 這個文件位置在相對於資源文件的根目錄下.
velocimacro.permissions.allow.inline = true Determines of the definition of new Velocimacros via the #macro() directive in templates is allowed,定義在模板中是否可用#macro()指令定義一個新的宏. 默認爲true,意味所有模板都可定義new Velocimacros. 注意,這個設定,如模板中的有可能替換掉全局的宏定義.
velocimacro.permissions.allow.inline.to.replace.global = false 控制用戶定義的宏是否可以可以替換Velocity的宏庫.
velocimacro.permissions.allow.inline.local.scope = false 控制模板中的宏的專有命名空間.When true, 一個模板中的 #macro() directive 只能被定義它的模板訪問. 這意味者所有的宏都不能共想了,當然也不會互想擾亂、替換了.
velocimacro.context.localscope = false控制Velocimacro 的引用訪問(set/get)是涉及到Context範圍還是僅在當前的Velocimacro中.
velocimacro.library.autoreload = false 控制宏庫是否自動載入. 設爲true時,源始的Velocimacro 將根據是否修改過而決定是否需要reLoad,可在調試時很方便,不需重啓你的服務器,如用參數 file.resource.loader.cache = false的設置一樣,主要是爲方便開發調試用.
7.語義更改
runtime.interpolate.string.literals = true Controls interpolation mechanism of VTL String Literals. Note that a VTL StringLiteral is specifically a string using double quotes that is used in a #set() statement, a method call of a reference, a parameter to a VM, or as an argument to a VTL directive in general. See the VTL reference for further information.
8.運行時配置
parser.pool.size = 20 控制Velocity啓動是需要創建並放到池中預備使用的模板解析器的個數----這只是預裝. 默認的20個對一般用戶來說足夠了. 即使這個值小了,Velocity也會運行時根據系統需要動態增加(但增加的不會裝入池中). 新增時會在日誌中輸出信息
 
11.Configuring the Log System(日誌記錄配置)
Velocity有很容易擴展的日誌系統.即使不做任何設置,velocity也會將日誌輸出到當前目錄下的 velocity.log文件中. 對一些高級用戶, 可以很方便的將你當前系統的日誌和它整合起來.
從1.3開始, Velocity 默認使用 Jakarta Avalon Logkit logger做爲日誌記錄器,也可以用 Jakarta Log4j logger.首先它會在classpath中查找Logkit. 找不到,會再嘗試Log4j.
1.一般的可選日誌功能:
Default Configuration 默認在當前目錄下創建日誌文件.
Existing Log4j Category 從1.3開始, Velocity 可以將日誌輸出到Log4j配置中. 但你必須:
1.       確認Log4j jar is in your classpath. (你應一直這樣做,自從使用Velocity.)
2.       配置Velocit使用SimpleLog4JLogSystem class.
3.       通過 'runtime.log.logsystem.log4j.category' 參數指定日誌條目名字.
這裏不建議使用老的Log4JLogSystem class. 可以在隨後看到示例.
Custom Standalone Logger 你可以創建定製的日誌類 – 你只需簡單的實現接口org.apache.velocity.runtime.log.LogSystem然後將你的實現類名配置到運行時參數 runtime.log.logsystem.class的值, Velocity在init()時將創建你的日誌實例. 更多相關信息可以看 Velocity helper class 和 configuration keys and values. 要注意的是, 接口org.apache.velocity.runtime.log.LogSystem 在1.2後才支持這一功能.
Integrated Logging 你可以將Velocity的日誌和你現存系統的日誌整合到一起.
Using Log4j With Existing Category
這裏是一個使用Log4j做爲Velocity日誌的例子.
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
 
import org.apache.log4j.Category;
import org.apache.log4j.BasicConfigurator;
 
public class Log4jCategoryExample
{
    public static String CATEGORY_NAME = "velexample";
 
    public static void main( String args[] )
        throws Exception
    {
        /*
         * configure log4j to log to console
         */
 
        BasicConfigurator.configure();
 
        Category log = Category.getInstance( CATEGORY_NAME );
 
        log.info("Hello from Log4jCategoryExample - ready to start velocity");
 
        /*
         * now create a new VelocityEngine instance, and
         * configure it to use the category
         */
 
        VelocityEngine ve = new VelocityEngine();
 
        ve.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
            "org.apache.velocity.runtime.log.SimpleLog4JLogSystem" );
 
        ve.setProperty("runtime.log.logsystem.log4j.category", CATEGORY_NAME);
 
        ve.init();
 
        log.info("this should follow the initialization output from velocity");
    }
}


上面的例子可以在examples/logger_example.下找到.
2.Simple Example of a Custom Logger
這是一個定製實現你自己的日誌記錄器,並將其加入到Velocity的日誌系統中. LogSystem interface—只需要支持這個接口.
import org.apache.velocity.runtime.log.LogSystem;
import org.apache.velocity.runtime.RuntimeServices;
...
 
public class MyClass implements LogSystem
{
 
...
 
    public MyClass()
    {
        ...
 
        try
        {
            /*
             * register this class as a logger
             */
            Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, this );
            Velocity.init();
        }
        catch (Exception e)
        {
            /*
             * do something
             */
        }
    }
 
    /**
     * This init() will be invoked once by the LogManager
     * to give you current RuntimeServices intance
     */
    public void init( RuntimeServices rsvc )
    {
        // do nothing
    }
 
    /**
     * This is the method that you implement for Velocity to call
     * with log messages.
     */
    public void logVelocityMessage(int level, String message)
    {
        /* do something useful */
    }
...
}


 
12.Configuring Resource Loaders(資源裝載器配置)
1.Resource Loaders
Velocity一個非常重要的基礎功能是資源管理和裝載. 這裏資源 'resources' 不僅包括了模板('templates'),RMS也可以處理非模板文件, 特別是在使用 #include() 指令時.
resource loader system (資源裝載系統)很容易擴展,可以同時執行多個資源裝載器的操作. 這極大的方便了資源管理, --你可以根據需要,定製自己的資源裝載器.
Velocity當前包含4種資源管理器, 說明如下:(注意例程中的配置參數有一個loader配置名 (ex.'file' in file.resource.loader.path).這個 'common name' 配置不一定會在你的系統中工作. 具體可見 resource configuration properties 理解系統如何工作. 這每一個loader都在包 org.apache.velocity.runtime.resource.loader. 中
FileResourceLoader : 這個loader從文件系統取得資源,其配置參數如下:
file.resource.loader.path = <path to root of templates>
file.resource.loader.cache = true/false
file.resource.loader.modificationCheckInterval = <seconds between checks>
這是己配置的默認裝載器, 默認從當前目錄('current directory'). 但當你不想將模板入到servlet容器的啓動目錄下時,這個loader就無能爲力了。請參看 developing servlets with Velocity.
JarResourceLoader : 這個loader可以從jar文件包中取得資源,在你把你的模板文件全部打包成 jar包時,系統會用這個loader來提取. 配置基本一樣除過jar.resource.loader.path, 這裏或以使用標準的JAR URL syntax of java.net.JarURLConnection.
ClasspathResourceLoader : 從classloader中取得資源. 一般來說,這意味着ClasspathResourceLoader將從classpath中load templates.這是在Servlet類型應用常見的一種設置。支持Servlet 2.2 (或更新)規範的容器Tomcat就是這樣一個例子. 這種裝載方式很有效, 因此你必須將你的模板打成jar包放到你的web應用的WEB-INF/lib 目錄下.就不再存在絕對、相對路徑的問題了,與以上兩個裝載器相比 ClasspathResourceLoader不僅在servlet container中用也,幾乎所有應用的上下文(context)都有用.
DataSourceResourceLoader : 這個loader可以從數據庫載入資源. 這個loader不是標準j2EE的一部分,因此需要取得J2EE 發行庫,將j2ee.jar加入到build/lib目錄下,然後編譯新的Velocity.jar設置ant target爲jar-j2ee,更細說明請見文檔中對類 org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader的介紹.
2.Configuration Examples
己配置的loader,可以參看 resource configuration section, for further reference.
第一就是要配置loader的名字. 參數resource.loader的值可以是你喜歡的用來關聯指定loader的名字.
resource.loader = file
下一步就是設置這個名字對應的class了,這是最重要的一步 :
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
 
這個例子中,我們告訴Velocity我們設置的loader名字叫file,指定的類是org.apache.velocity.runtime.resource.loader.FileResourceLoader.下一步就是設置這個loader的一些重要參數.
file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2
 
這裏,我們設置了查找模板的路徑是 /opt/templates. 然後打開caching,最後,設置檢測週期爲2秒,以便Velocity檢測新的或己更改過的模板來load.
上示是一些基本配置,隨後,還會再有一些示例.
Do-nothing Default Configuration : 你也可以什麼都不改動,就用默認的配置. 這是默認的loader配置:
resource.loader = file
 
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0
 
Multiple Template Path Configuration :多模板路徑配置如下所示,只要用逗號分開就是 :
resource.loader = file
 
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = /opt/directory1, /opt/directory2
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 10
 
Multiple Loader Configuration : 多個loader配置,嗯,也很簡單,不說了,看例子就是.
#
# specify three resource loaders to use
#
resource.loader = file, class, jar
 
#
# for the loader we call 'file', set the FileResourceLoader as the
# class to use, turn off caching, and use 3 directories for templates
#
file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = templatedirectory1, anotherdirectory, foo/bar
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 0
 
#
# for the loader we call 'class', use the ClasspathResourceLoader
#
class.resource.loader.description = Velocity Classpath Resource Loader
class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
 
#
# and finally, for the loader we call 'jar', use the JarResourceLoader
# and specify two jars to load from
#
jar.resource.loader.description = Velocity Jar Resource Loader
jar.resource.loader.class = org.apache.velocity.runtime.resource.loader.JarResourceLoader
jar.resource.loader.path = jar:file:/myjarplace/myjar.jar, jar:file:/myjarplace/myjar2.jar
 
只是注意: 'file', 'class', and 'jar' 這三個名字不是固定是,可以根據你的喜好來設定. 但只要保持上面的對應關係就是.
3.插入定製資源管理器和Cache實現
資源管理器是相關資源 (template and static content)管理系統的核心部分, 它爲應用程序取得請求模板,查找他們的有效資源loaders,操作caching.對於高級用戶,可以用自定製的caching系統取代這個默認的實現.
資源管理器必須實現 org.apache.velocity.runtime.resource.ResourceManager interface. 具體描述請看api文檔. 儘量使用默認實現,除非你認爲有必要在以下參數中換成你自己的 :
resource.manager.class
 
這個參數也可通過RuntimeConstants.RESOURCE_MANAGER_CLASS 設定。
資源的caching必須實現 org.apache.velocity.runtime.resource.ResourceCache interface 接口,配置到參數中是 :
resource.manager.cache.class
這個參數也可通過 RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS 設定
 
13.Template Encoding for Internationalization(字符編碼和國際化)
從版本1.1開始, 可以設定資源的編解碼類型. 在API中也可以傳入解碼的方式 :
org.apache.velocity.servlet.VelocityServlet :
public Template getTemplate( String template, String encoding )
org.apache.velocity.app.Velocity :
public static Template getTemplate(String name, String encoding) public static boolean mergeTemplate( String templateName, String encoding, Context context, Writer writer )
encoding 參數可以設定爲JVM支持的某個值 "UTF-8" or "ISO-8859-1".關於字符集正式的名字, see here.
注意,這僅僅是編碼了模板自己 – 輸出的編碼由應用程序指定.
 
14.Velocity and XML
 
Velocity's的VTL( velocity template language)處理XML數據很方便. Anakia是一個用XSL從XML中輸出視圖的例子. Velocity站點,文檔包括 Jakarta site is also rendered using Anakia.
一般來說,處理XML會用到 JDOM 這樣的東東將XML轉成java數據結構 ,如下例示是一個XML文檔 :
<?xml version="1.0"?>
 
<document>
 <properties>
 <title>Developer's Guide</title>
 <author email="[email protected]">Velocity Documentation Team</author>
 </properties>
</document>
 
一小段處理的讀取XML的java程序如下:
...
 
SAXBuilder builder;
Document root = null;
 
try
{
    builder = new SAXBuilder( "org.apache.xerces.parsers.SAXParser" );
    root = builder.build("test.xml");
}
catch( Exception ee)
{}
 
VelocityContext vc = new VelocityContext();
vc.put("root", root );
 
...
 
(See the Anakia source for details on how to do this, or the Anakia example in the examples directory in the distribution.) 現在,在模板中應用 :
<html>
 <body>
    The document title is
    $root.getChild("document").getChild("properties").getChild("title").getText()
 </body>
</html>
 
就像渲染一般模板那樣, 使用 Context 中的JDOM tree. 雖然這個例子看起來不漂亮, 但它展示了這樣做是多麼容易.
One real advantage of styling XML data in Velocity is that you have access to any other object or data that the application provides. You aren't limited to just using the data present in the XML document. You may add anything you want to the context to provide additional information for your output, or provide tools to help make working with the XML data easier. Bob McWhirter's Werken Xpath is one such useful tool - an example of how it is used in Anakia can be found in org.apache.velocity.anakia.XPathTool.
One issue that arises with XML and Velocity is how to deal with XML entities. One technique is to combine the use of Velocimacros when you need to render an entity into the output stream :
## first, define the Velocimacro somewhere
 
#macro( xenc $sometext )$tools.escapeEntities($sometext)#end
 
## and use it as
 
#set( $sometext = " < " )
<text>#xenc($sometext)</text>
where the escapeEntities() is a method that does the escaping for you. Another trick would be to create an encoding utility that takes the context as a constructor parameter and only implements a method:
public String get(String key)
{
    Object obj = context.get(key)
    return (obj != null) ? Escape.getText( obj.toString() ) : "";
}
 
Put it into the context as "xenc". Then you can use it as :
<text>$xenc.sometext</text>
 
This takes advantage of Velocity's introspection process - it will try to call get("sometext") on the $xenc object in the Context - then the xenc object can then get the value from the Context, encode it, and return it.
Alternatively, since Velocity makes it easy to implement custom Context objects, you could implement your own context which always applies the encoding to any string returned. Be careful to avoid rendering the output of method calls directly, as they could return objects or strings (which might need encoding). Place them first into the context with a #set() directive and the use that, for example :
#set( $sometext = $jdomElement.getText() )
<text>$sometext</text>
 
The previous suggestions for dealing with XML entities came from Christoph Reck, an active participant in the Velocity community. We are very grateful for his [unknowing] contribution to this document, and hope his ideas weren't mangled too badly :)
 
15.FAQ (Frequently Asked Questions)
開發中常見的問題解答.
1.Why Can't I Access Class Members and Constants from VTL?
在VTL中無法訪問到類的數據域
最簡單的原因是我們無法反射/內省(introspect )這個對象.因爲就OOP來說,對象中要隱藏自己沒有必要外露的數據或命令.解決方法:包狀成publicly 命令反回它,保證它是公開訪問的. 當然,你要保證能改動源文件, 否則,就要用工具來解析它. org.apache.velocity.app.FieldMethodizer是用來解析你的類的, 如下示例如何將一個public static fields 導出到模板中.假設你的類是 :
public class Foo
    {
        public static String PATH_ROOT = "/foo/bar";
 
        ....
    }
 
 
你可這樣將它放入context中:
context.put("myfoo", new FieldMethodizer( new Foo() ) );
 
然後在模板中就可以java代碼的風格來訪問 :
 $myfoo.PATH_ROOT
 
如果你需要訪問public的非靜態域時(public non-static members)甚止是私有成員!那你就必須擴展或重寫 FieldMethodizer 這個類----但你爲什麼要搞得這麼複雜呢?
2.Where does Velocity look for Templates?
Velocity到哪裏提取模板文件?
默認的,不做任何配置更改的情況下,Velocity會在當前目錄下或相對與當前目錄(如'foo/bar.vm')下查找.
Velocity對這些都是自動處理的. Velocity只記住它自己的一個root目錄,這個概念不同與多根目錄的文件系統(like - "C:\", "D:\", etc).
 
16.Summary
希望這個指南能幫助您出色的將velocity應用到項目中. 請將您的意見反饋發送到mail lists.
 
 
17.Appendix 1 : Deploying the Example Servlet
佈署本文中的Servlet例程
Servlet開發者經常受到的一個打擊是將servlet放錯了地方---一切都是好的除此之外. 使用Tomcat 、 Resin i這樣的Servlet容器都可以運行起我們的SampleServlet . SampleServlet.java 在目錄 examples/servlet_example 下. 雖然有些servlet engines (Resin, for example) 會自動將它編譯,但是爲了學習,還是你親自動手先將它編譯過.
Jakarta Tomcat
Jakarta Tomcat 的安裝就不多說了. 'webapp' 目錄是tomcat默認的查找它的web應用的root.所以,以下是我們要做的:
首先,創建一個新的 'webapp' 暫時名叫 velexample 放到Tomcat的webapps 目錄下, 這個新的目錄結構如下 :
velexample velexample/WEB-INF velexample/WEB-INF/lib velexample/WEB-INF/classes
將Velocity jar 放到velexample/WEB-INF/lib下. (從1.2版本後,所有相關依賴包都打包在. velocity-dep-1.2.jar中),當然,相關的依賴包也必須放到WEB-INF/lib下. 具體可以看 "Getting Started" and "Dependencies", 這兩節的介紹.
將編譯過的SampleServlet.class放到 velexample/WEB-INF/classes 下.
將sample.vm 放到目錄velexample 下.
現在就可以啓動servlet來訪問servlet了.
在Browser中輸出如下 :
http://localhost:8080/velexample/servlet/SampleServlet
如不能工作,則試下 :
http://<your computer's ip address>:8080/velexample/servlet/SampleServlet
看到輸出結果了嗎?.
Caucho Technology's Resin
Setting up the example servlet under Caucho Technology's Resin servlet engine is also very simple. The following instructions were tested with the version 1.2.5 release. The following assume that you have unzip-ed or untar-ed the distribution, know how to start the servlet engine (something like bin/httpd.sh under unix...), and know where the doc directory is (in the root of the distribution).
Copy the SampleServlet.class file into the doc/WEB-INF/classes directory.
Copy the sample.vm template file into the doc/ directory
Copy the Velocity jar (and any required dependencies - see note above in Tomcat setup section) into the doc/WEB-INF/lib directory.
Start resin.
To access the servlet, point your web browser at :
http://localhost:8080/servlet/SampleServlet
or if that doesn't work :
http://<your computer's ip address>:8080/servlet/SampleServlet
and you should see the output.
Note that this appeared to be a simpler configuration - with the Tomcat example, you set up a complete, new, separate webapp, whereas the Resin instructions don't, although both should provide a sufficient setup to let you play with Velocity.
Note that while we wish we could, we can't answer questions about the servlet engines. Please use the resources provided by the servlet engine provider.
BEA WebLogic
Paw Dybdahl <[email protected]> contributed this description of using Velocity with WebLogic, as well as some good general suggestions and examples for working with servlets
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章