- 概述和入门Introduction and Getting Started
- 资源Resources
- Velocity怎样工作How Velocity Works
- 基本的格式The Fundamental Pattern
- 使用Singleton还是不使用To Singleton Or Not To Singleton...
- Singleton模式Singleton Model
- Separate Instance
- 上下文The Context
- 基础原则The Basics
- 对使用#foreach()遍历对象的支持Support for Iterative Objects for #foreach()
- 上下文链Context Chaining
- 模版创建的对象Objects Created by the Template
- 其他问题Other Context Issues
- 在Servlets里使用VelocityUsing Velocity in Servlets
- Servlet编程Servlet Programming
- 部署Deployment
- 在一般的应用中使用VelocityUsing Velocity in General Applications
- Velocity Helper对象The Velocity Helper Class
- 异常Exceptions
- 更多的细节Miscellaneous Details
- 应用的属性Application Attributes
- EventCartridge 和 Event Handlers
- Velocity的配置Velocity Configuration Keys and Values
- 配置日志系统Configuring the Log System
- 使用现有的Log4jUsing Log4j With Existing Category
- 一个自定义日志的例子Simple Example of a Custom Logger
- 配置资源加载器(模版加载器)Configuring the Resource Loaders (template loaders)
- 资源加载器Resource Loaders
- 配置示例Configuration Examples
- 插拔式的资源管理器和资源缓存Pluggable Resource Manager and Resource Cache
- 模版的编码和国际化Template Encoding for Internationalization
- Velocity 和 XML
- FAQ (Frequently Asked Questions)
- 总结Summary
- 附录1:部署示例ServletAppendix 1 : Deploying the Example Servlet
- Jakarta Tomcat
- Caucho Technology's Resin
- BEA
概述
Velocity是一个基于Java技术的模版引擎,是一个简单但强大的使你能轻松的创建和合成具有一定格式,用于展现数据的文档的工具。在本指南中,我们希望能使你对使用Velocity能有一个比较全面的认识。主要关注两个主要的使用Velocity的领域:Velocity is a Java-based template engine, a simple and powerful development tool that allows you to easily create and render documents that format and present your data. In this guide, we hope to give an overview of the basics of development using Velocity, focusing on the two main areas for Velocity usage :
- 基于servlet的web应用。servlet-based WWW development
- 普通的应用。general application use
你将会发现其实两者之间的差别很小。当使用我们提供的VelocityServlet作为基于servlet的web应用的基础,加上我们提供的一些工具类,构建一个web应用会及其的简单。You will see that there is no real difference between these, other than we make servlet development with Velocity very easy if you use our provided class VelocityServlet as a base class for your servlet, and offer a utility class to help with application development.
入门Getting Started
即使在Velocity官方网站还是在Velocity的文档中,都能找到下面的信息,但是为了完整这里还是再提下。要使Velocity在你的电脑上开始工作是很简单的事情。注意下面提到的文件夹都是从你的Velocity发布文件的根目录开始的。While this information is found elsewhere on the Velocity site and in the documentation, it is included here for completeness. Getting Velocity running on your computer is very easy. Note that all directory references are relative the root of the Velocity distribution tree.
- 得到Velocity的发布文件。Get the Velocity distribution. This is available as a release, nightly snapshot or directly from the CVS code repository. Any are fine, although for the latest features, the nightly snapshot is most likely the best way. For more information, go here.
- 如果你还没有安装Jakarta Ant这个构建工具,请安装好它。需要Ant是为了构建Velocity,而不是为了使用Velocity。If you don't have Jakarta Ant, the Java build tool already installed, please do so. It is required for building Velocity, although not required for using Velocity.
- 切换到发布文件的build文件夹下。Go to the build directory in the distribution.
- 输入 ant <build target>,其中,<build target>将会是下面之一:Type ant <build target> where <build target> is one of:
- jar 在bin文件夹下构建完整的Velocity jar文件。这个jar文件会命名为Velocity-X.jar,其中X是当前Velocity的版本号。注意这个jar文件没有包括Velocity必需的库文件。如果你使用了这个任务,你需要从JAakarta Commons上得到Collections组件,并且将该jar文件添加到你的CLASSPATH中(或者放到WEB-INF/lib)。如果你希望使用日志或其他功能,你也需要把相关的jar文件添加到CLASSPATH或者WEB-INF/lib中。为了方便,你可以直接使用jar-dep任务来将需要的jar都打包到一起。builds the complete Velocity jar in the bin directory. This jar will be called 'velocity-X.jar', where 'X' is the current version number. This jar does not include necessary dependencies for Velocity. If you use this target, you must get the Collections component jar from Jakarta Commons and add to your CLASSPATH (or WEB-INF/lib). If you wish to use the built-in logging or template conversion, you must include the appropriate jars in your CLASSPATH or webapp's WEB-INF/lib. For convenience, you can use the jar-dep target to build a jar with ORO, Logkit and Commons Collections included.
- jar-dep 在bin文件夹下构建完整的Velocity jar文件,包括了Velocity所有依赖的库文件。builds the complete Velocity jar in the bin directory, including necessary support for logging from the Jakarta Avalon Logkit package, critical configuration support from the Jakarta Commons and the necesary support for WebMacro template conversion using the Jakarta ORO package.
- jar-core 在bin文件夹下构建一个小型的Velocity jar文件,该文件叫做velocity-core-X.jar。该jar中只包括了Velocity最核心的功能,不包括例子和工具,比如Anakia,Texen,VelocityServlet等。关于该jar文件的依赖组件和jar任务一样,也没有包括。builds a slimmer Velocity jar in the bin directory, called 'velocity-core-X.jar'. This jar contains the core Velocity functionality, and doesn't include example and utility things like Anakia, Texen or the VelocityServlet support baseclass. It has the same external dependency requirements as the regular jar target.
- jar-util 在bin文件夹中构建Velocity的工具jar,该文件叫做velocity-util-X.jar。该jar中只包含了Velocity提供的工具,Anakia,Texen和WebMacro模版转换工具。关于该jar文件的依赖组件和jar任务一样,也没有包括。builds a utility Velocity jar in the bin directory, called 'velocity-util-X.jar'. This jar contains utility code, specifically Anakia, Texen, and the WebMacro template conversion utility. It has the same external dependency requirements as the regular jar target.
- jar-servlet 在bin文件夹中构建Velocity的工具jia,该文件叫做velocity-servlet-X.jar。该jar包含了servlet相关的工具代码。关于该jar文件的依赖组件和jar任务一样,也没有包括。builds a utility Velocity jar in the bin directory, called 'velocity-servlet-X.jar'. This jar contains utility code for servlet programmers. It has the same external dependency requirements as the regular jar target.
- jar-J2EE 构建一个完整的jar文件。和jar任务相似,该jar文件包含了J2EE应用所需要的所有的组建。现在,多增加的文件就只有org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader。和其他任务一样,该jar文件也是放在bin文件夹下的,叫做velocity-j2ee-X.jar。注意,如果你希望使用该任务,你必须将j2ee.jar拷贝到build/lib文件夹中。我们没有在任何发布文件中提供该jar文件。在http://java.sun.com上能找到他。关于该jar文件的依赖组件和jar任务一样,也没有包括。builds a complete jar, like the 'jar' target, that includes any components that require J2EE support. Currently, this includes only org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader. As usual, it is placed in the bin directory, called 'velocity-j2ee-X.jar'. NOTE : if you wish to use this build target, you must place (or link) a copy of j2ee.jar into the build/lib directory. We do not provide it as part of the distribution. A good source is http://java.sun.com/. It has the same external dependency requirements as the regular jar target.
- jar-J2EE-dep build a complete jar with J2EE support and includes logging support from the Jakarta Avalon Logkit and regexp support fromt the Jakarta ORO package. See the notes on the jar-dep target, above.
- examples 构建在examples文件夹中的例子代码。该任务同样会构建论坛例子项目。builds the example code in the example programs found in the examples directory. This build target will also build the forumdemo example project.
- forumdemo 构建在examples/forumdemo文件夹中的web应用实例。builds the example webapplication in the examples/forumdemo directory.
- docs 在docs文件夹中使用Anakia XML转换工具构建文档。允许你在构建中使用Velocity模版作为样式表。注意,该任务需要把jakarta-site2项目放在jakarta-velocity发布文件夹中。关于更详细的内容请参看在build.xml文件中该任务的详细说明。builds these docs in the docs directory using Velocity's Anakia XML transformation tool. Allowing you to use Velocity templates in place of stylesheets - give it a try! Note: This target requires that the jakarta-site2 project is located as a peer directory to the jakarta-velocity distribution directory. Please see the note in the build.xml file for this target for further information.
- jar-src 将所有的Velocity代码放在一个jar里面,置于bin文件夹中。bundles all the Velocity source code into a single jar, placed in the bin directory.
- javadocs 在doc/api文件夹中构建API文档。builds the Javadoc class documentation in the docs/api directory
- test (after jar) will test Velocity against it's testbed suite of test routines
- help 列出所有可用的任务。lists the build targets that are available.
- 虽然不是必须的,但首先测试一下构建是一个不错的想法。使用test任务即可。While not required, testing the build is a good idea. Use the test target mentioned above.
- 所有的事情都OK了。Velocity已经能开始工作了。将合适的jar文件置于你的类路径中,或者放在合适的位置(比如web-inf/lib)That's it! Velocity is ready to be used. Put the jar into your classpath, or into other appropriate places (such as the lib directory of your webapp if using with servlets)
- 我们建议你先运行下例子来感受下Velocity。通过输入ant examples来构建。If you want to play with the examples, which is highly recommended when getting started, use build the examples via ant examples.
依赖包Dependencies
Velocity使用Java2 API。构建Velocity需要Java2 SDK。要运行Velocity,需要Java2 RTE。Velocity uses elements of the Java 2 API such as collections, and therefore building requires the Java 2 Standard Edition SDK (Software Development Kit). To run Velocity, the Java 2 Standard Edition RTE (Run Time Environment) is required (or you can use the SDK, of course).
Velocity为了完成一些通用的功能,需要一些额外的包。为了方便,他们都放在build/lib文件夹下,但是默认的构建任务并没有包含这些jar。如果你使用的是默认的任务构建Velocity,你必须要把这些jar文件放入你的classpath。Velocity also is dependent upon a few packages for general functionality. They are included in the build/lib directory for convenience, but the default build target (see above) does not include them. If you use the default build target, you must add the dependencies to your classpath.
- Jakarta Commons Collections - 必需的required.
- Jakarta Avalon Logkit - 可选的,但是很常用。如果需要使用Velocity默认的基于文件的日志功能。optional, but very common. Needed if using the default file-based logging in Velocity.
- Jakarta ORO - 可选的。如果要使用org.apache.velocity.convert.WebMacro 模版转换工具。optional. Needed when using the org.apache.velocity.convert.WebMacro template conversion utility. 资源Resources 下面有一些例子和资源。我们建议你能看看我们提供的例子,文档甚至源代码。下面是一些很好的资源。There are quite a few resources and examples available to the programmer, and we recommend that you look at our examples, documentation and even the source code. Some great sources are :
- 用户和开发者的交流社区:通过mail-lists加入我们。The user and developer community : join us via the mail-lists.
- Mail-list资料库: http://www.mail-archive.com 。在搜索框中输入velocity来查看user和dev的文档。Mail-list archives : http://www.mail-archive.com is a good one. Type 'velocity' into the search box to see both our -user and -dev archives.
- 源代码:在Velocity项目下的src/java文件夹中。source code : src/java/... : all the source code to the Velocity project
- 应用示例1:一个简单的用于演示怎样在一个应用程序中使用Velocity。application example 1 : examples/app_example1 : a simple example showing how to use Velocity in an application program.
- 应用示例2:一个简单的用于演示怎样通过使用Velocity应用程序工具包来在应用程序中使用Velocity。application example 2 : examples/app_example2 : a simple example showing how to use Velocity in an application program using the Velocity application utility class.
- servlet例子:一个简单的用于演示怎样在servlet中使用Velocity的例子。servlet example : examples/servlet_example1 : a simple example showing how to use Velocity in a servlet.
- 日志例子:一个简单的用于演示怎样自定义一个日志记录器并将它注册到velocity中来接收日志消息的例子。logger example : examples/logger_example : a simple example showing how to create a custom logging class and register it with Velocity to receive all log messages.
- XML例子:XML example : examples/xmlapp_example : a simple example showing how to use JDOM to read and access XML document data from within a Velocity template. It also includes a demonstration of a recursive Velocimacro that walks the document tree.
- event 例子:一个用来演示在Velocity1.1中出现的事件处理API的使用。example : examples/event_example : An example that demonstrates the use of the event handling API in Velocity 1.1
- Anakia 应用:application : 一个用来演示怎样使用Velocity来为XML数据创建样式表。 examples/anakia : example application showing how to use Velocity for creating stylesheet renderings of xml data
- 论坛Web演示应用Forumdemo web app :一个基于servlet的论坛演示应用。 examples/forumdemo : working example of a simple servlet-based forum application
- documentation : docs : all the generated documentation for the Velocity project in html
- API documentation : docs/api : the generated Javadoc documentation for the Velocity project
- 模版:大量的关于模版的示例,这些都是极好的VTL的例子。templates : test/templates : a large collection of template examples in our testbed directory, these are a great source of useage examples of VTL, the Velocity Template Language
- 上下文例子:两个关于怎样扩展上下文对象的例子,适用于高级用户。context example : examples/context_example : two examples showing how the Velocity context can be extended. For advanced users.
上面所有引用到的文件夹都是基于发布文件的根目录的。All directory references above are relative to the distribution root directory. Velocity怎样工作How Velocity Works 基本的格式'The Fundamental Pattern'
当你在一个应用程序中或者一个servlet中,你一般会按照下面的方式来做。When using Velocity in an application program or in a servlet (or anywhere, actually), you will generally do the following :
- 初始化Velocity:对于两种使用环境都适用------Singleton和separate rutime instance,并且该工作只需做一次。Initialize Velocity. This applies to both usage patterns for Velocity, the Singleton as well as the 'separate runtime instance' (see more on this below), and you only do this once.
- 创建一个上下文对象(后面将详细介绍)。Create a Context object (more on what that is later).
- 把你的数据对象放入上下文对象中。Add your data objects to the Context.
- 选择一个模版。Choose a template.
- 把模版和你的数据一起输出。'Merge' the template and your data to produce the ouput.
在代码中,通过类org.apache.velocity.app.Velocity使用Singleton模式,代码如下:In code, using the singleton pattern via the org.apache.velocity.app.Velocity class, this looks like 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 context = new VelocityContext();
context.put( "name", new String("Velocity") );
Template template = null;
try
{
template = Velocity.getTemplate("mytemplate.vm");
}
catch( ResourceNotFoundException rnfe )
{
}
catch( ParseErrorException pee )
{
}
catch( MethodInvocationException mie )
{
}
catch( Exception e )
{
}
StringWriter sw = new StringWriter();
template.merge( context, sw );
这就是基本的格式。很简单,不是吗?这基本上就是你使用Velocity来合成模版所需要的步骤。当然在实际的应用中你不会像这样书写代码,我们为servlet和普通应用提供了一些工具,让你能甚至比上面的代码更容易的使用Velocity。在本指南的后面,我们将介绍在servlet和普通应用中使用Velocity的更多细节,和那些不错的工具。在每一种情况下,当然,上面的运行的顺序是不变的,或者在幕后是这样的。That's the basic pattern. It is very simple, isn't it? This is generally what happens when you use Velocity to render a template. You probably won't be writing code exactly like this - we provide a few tools to help make it even easier than this for both servlet and application programmers. Later on in this guide, we will talk about using Velocity in both servlets as well as general applications, and we discuss the tools we provide to make things easier. In each case, though, the above sequence is what is happening either explicitly, or behind the scenes. 使用singleton或者不...To Singleton Or Not To Singleton... 在Velocity1.2之后,开发人员就有了两种使用Velocity引擎的选择------单例模式或者非单例模式。两中选择都使用的是相同的Velocity代码,让Velocity更简单的融入到你的Java应用中。As of Velocity 1.2 and later, developers now have two options for using the Velocity engine, the singleton model and the separate instance model. The same core Velocity code is used for both approaches, which are provided to make Velocity easier to integrate into your Java application.
单例模式Singleton Model
这是一种老的模式,即在JVM中只存在一个Velocity引擎的实例,整个应用共享这一个。这种方式对于配置文件的定位和共享资源都是很方便的。比如,该模式极其适合使用在Servlet2.2+标准下的web应用中------每个web应用都拥有其唯一的一个Velocity实例,允许web应用的servlet共享诸如模版,日志记录器等资源。这个单例的实例可以通过org.apache.velocity.app.Velocity.app.Velocity类创建。下面是一个使用单例模式的例子:This is the legacy pattern, where there is only one instance of the Velocity engine in the JVM (or web application, depending) that is shared by all. This is very convenient as it allows localized configuration and sharing of resources. For example, this is a very appropriate model for use in a Servlet 2.2+ compliant web application as each web application can have it's own instance of Velocity, allowing that web application's servlet to share resources like templates, a logger, etc. The singleton is accessable via the org.apache.velocity.app.Velocity class, and and example of use : import org.apache.velocity.app.Velocity;
import org.apache.velocity.Template;
...
/*Configure the engine - as an example, we are usingourselves 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");
请注意,在org.apache.velocity.servlet.VelocityServlet 基础类(一个用于使创建servlet更简单的工具类)中,使用的就是单例模式。通过继承该类创建使用Velocity的servlet是最简单和最方便的方式,当然,这不是必须的。serbletPlease note that the Singleton model is used in the org.apache.velocity.servlet.VelocityServlet base class, a utility class provided with the distribution to make writing servlets easier. While extending this class is the most common and convenient way to write servlets using Velocity, you are free to not use this class if you needs require something different.
分离的实例Separate Instance
在1.2中的新出现的分离的实例模式允许你在一个JVM中创建,配置和使用许多Velocity引擎的实例。如果你想在同一个应用中为不同的Velocity引擎配置不同的资源,模版,日志记录器等,这种方式特别有用。通过使用org.apache.velocity.app.VelocityEngine来创建分离实例模式。下面是一个例子,功能同上一个例子:New in version 1.2, the separate instance allows you to create, configure and use as many instances of Velocity as you wish in the same JVM (or web application.) This is useful when you wish to support separate configurations, such as template directories, loggers, etc in the same application. To use separate instances, use the org.apache.velocity.app.VelocityEngine class. An example, which parallels the above singleton example, looks like :
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 usingourselves as a logger (see logging examples..)*/
ve.setProperty( VelocityEngine.RUNTIME_LOG_LOGSYSTEM, this);
/*initialize the engine*/
ve.init();
...
Template t = ve.getTemplate("foo.vm");
如你所见,这是很简单并且很直接的。除了一些简单的形式上的改变,使用单例模式还是分离模式对于你应用的高层次的架构和模版是没有影响的。As you can see, this is very simple and straightforward. Except for some simple syntax changes, using Velocity as a singleton or as separate instances requires no changes to the high-level structure of your application or templates.
作为一个程序员,需要强调的是使用org.apache.velocity.app.Velocity类来应用单例模式,使用org.apache.velocity.app.VelocityEngine类来应用非单例模式(分离实例模式)。As a programmer, the classes you should use to interact with the Velocity internals are the org.apache.velocity.app.Velocity class if using the singleton model, or org.apache.velocity.app.VelocityEngine if using the non-singleton model ('separate instance').
另外,不要使用在org.apache.velocity.runtime包中的Runtime,RuntimeConstants,RuntimeSingleton或者RuntimeInstance类。这些类是用于框架内部的,并且在不断的变化中。正如上面提到的,你应该使用在org.apache.vleocity.app包中的类------Velocity和VelocityEngine。At no time should an application use the internal Runtime, RuntimeConstants, RuntimeSingleton or RuntimeInstance classes in the org.apache.velocity.runtime package, as these are intended for internal use only and may change over time. As mentioned above, the classes you should use are located in the org.apache.velocity.app package, and are the Velocity and VelocityEngine classes. If anything is missing or needed from those classes, do not hesitate to suggest changes - these classes are intended for the application developer. 上下文对象The Context 基础The Basics
Velocity是以上下文概念为中心的,并且这是一种普通的在系统的各个部分中传递数据容器的技术。可以这样认为,上下文是在Java层(程序员关注的)和模版层(设计人员关注的)之间数据的负载者。程序员会将所有应用需要的对象,无论什么类型都聚集在一起,放入上下文中。对于页面设计者,在上下文中的对象,和它们的属性及方法都通过叫做引用的模版元素来调用。一般来说,你需要和设计者一起设计在页面上需要显示的数据,这些会成为设计者在页面中需要使用的API。所以,在这个阶段的时间的投入和仔细的分析是很值得的。The concept of the 'context' is central to Velocity, and is a common technique for moving a container of data around between parts of a system. The idea is that the context is a 'carrier' of data between the Java layer (or you the programmer) and the template layer ( or the designer ). You as the programmer will gather objects of various types, whatever your application calls for, and place them in the context. To the designer, these objects, and their methods and properties, will become accessable via template elements called references. Generally, you will work with the designer to determine the data needs for the application. In a sense, this will become an 'API' as you produce a data set for the designer to access in the template. Therefore, in this phase of the development process it is worth devoting some time and careful analysis.
同时,Velocity允许你创建自己的上下文对象来支持特别的要求和技术(比如连接一个LDAP的上下文)。一个很好的扩展点是继承VelocityContext类。While Velocity allows you to create your own context classes to support special needs and techniques (like a context that accesses an LDAP server directly, for example), a good basic implementation class called VelocityContext is provided for you as part of the distribution.
VelocityContext满足一般的需要,并且我们强烈建议你使用它。只有在例外或者高级的情况下,你需要继承或者创建你自己的上下文对象。VelocityContext is suitable for all general purpose needs, and we strongly recommended that you use it. Only in exceptional and advanced cases will you need to extend or create your own context implementation.
使用VelocityContext和使用普通的Java Hashtable对象差不多。你需要的最主要的两个方法是:Using VelocityContext is as simple as using a normal Java Hashtable class. While the interface contains other useful methods, the two main methods you will use are public Object put(String key, Object value);
public Object get(String key);
请注意这和Hashtable相似,里面的值必须继承自java.lang.Object,并且不是null。基础类型,比如int或者float必须要用适当的包装类包装才能使用。Please note that like a Hashtable, the value must be derived from java.lang.Object, and must not be null. Fundamental types like int or float must be wrapped in the appropriate wrapper classes.
这就是context基础的操作。需要了解更多的信息 ,请参考发布文件中的API文档。That's really all there is to basic context operations. For more information, see the API documentation included in the distribution.
使用*#foreach()来遍历对象{*}Support for Iterative Objects for #foreach()
作为一个程序员,对于放入上下文中的对象你有很大的自由度。在最大范围的自由度里需要遵守一些规则,所以,理解Velocity支持什么,就不会有错误会发生了。Velocity支持几种适合在VTL使用#foreach()指示符的集合类型对象。As a programmer, you have great freedom in the objects that you put into the context. But as with most freedoms, this one comes with a little bit of responsibility, so understand what Velocity supports, and any issues that may arise. Velocity supports serveral types of collection types suitable for use in the VTL #foreach() directive.
- Object []正规的对象数组,在这里不需要再多说了。Velocity在框架内部用一个实现了Iterator接口的类来包装你的数组,具体的包装细节作为一个程序员或者模版设计者不需要过多的关注。Regular object array, not much needs to be said here. Velocity will internally wrap your array in a class that provides an Iterator interface, but that shouldn't concern you as the programmer, or the template author.
- java.util.Collection Velocity会使用iterator()方法来得到一个Iterator对象来执行遍历操作。所以,你需要使你的对象实现Collection接口,以使iterator()方法返回一个正常的Iterator对象。Velocity will use the iterator() method to get an Iterator to use in the loop, so if you are implementing a Collection interface on your object, please ensure that iterator() returns a working Iterator.
- java.util.Map这里,Velocity依靠values()方法来得到一个Collection接口,然后再调用iterator()方法来得到用来遍历的Iterator对象。Here, Velocity depends upon the values() method of the interface to get a Collection interface, on which iterator() is called to retrieve an Iterator for the loop.
- java.util.Iterator 小心使用:这是最近才支持的,不过最好是作为临时的使用,主要是因为Iterator的不可复位性决定的。如果一个Iterator直接被放入上下文,并且使用了多于一个的#foreach来遍历,那么第二个#foreach就会失败,因为Iterator并没有复位。USE WITH CAUTION : This is currently supported only provisionally - the issue of concern is the 'non-resettablity' of the Iterator. If a 'naked' Iterator is placed into the context, and used in more than one #foreach(), subsequent #foreach() blocks after the first will fail, as the Iterator doesn't reset.
- java.util.Enumeration 小心使用:和Iterator相似,这也是最近才支持的用于临时性的。原因也是Enumeration的不可复位性决定的。同样,如果一个Enumeration直接被放入上下文,并且使用了多于一个的#foreach来遍历,那么第二个#foreach就会失败,因为Enumeration并没有复位。USE WITH CAUTION : Like java.util.Iterator, this is currently supported only provisionally - the issue of concern is the 'non-resettablity' of the Enumeration. If a 'naked' Enumeration is placed into the context, and used in more than one #foreach(), subsequent #foreach() blocks after the first will fail, as the Enumeration doesn't reset.
我们建议,只有在必须的时候,才将Iterator 和Enumeration放入上下文中。In the case of the Iterator and Enumeration, it is recommended that they are placed in the context only when it cannot be avoided, and you should let Velocity find the appropriate reusable iterative interface when that is sufficient and possible.
尽管可能有充足理由直接在Context中使用Iterator(比如通过JDBC得到的大的数据集),但如果能够避免,最好还是使用其他的代替。这里直接使用是指象下面代码这样:There are good reasons to use the java.util.Iterator interface directly (large data sets via JDBC, for example), but if it can be avoided, it might be better to use something else. By 'directly' , we meant doing something like: Vector v = new Vector();
v.addElement("Hello");
v.addElement("There");
context.put("words", v.iterator() );
在上面的例子中,Iterator对象自己是放入了Context。作为代替,只需象这样:where the Iterator itself is placed into the context. Instead, if you simply did: context.put("words", v );
这样一切都能正常运行:Velocity将会发现Vector实现了Collection,并且会找到iterator()方法,并且在每一次调用#foreach之前刷新Iterator对象。如果使用的直接是Iterator对象,那么一旦velocity在其上使用了一次#foreach,Velocity没有办法再重新得到一个新的Iterator。这将导致所有在#foreach中使用该引用输出为空。then all would be fine: Velocity would figure out that Vector implement Collection (via List), and therefore will find the iterator() method, and use that to get a 'fresh' Iterator for its use each time it needs to. With just a plain Iterator (the first snippet above...), once velocity has used it in a #foreach(), Velocity has no way of getting a new one to use for the next #foreach() it is used in. The result is no output from any subsequent #foreach() blocks using that reference.
上面的介绍并不是说在Velocity中遍历对象是一件必须经过细致考虑的问题。不过,当你放入上下文中的是一个Iterator,确实需要小心谨慎。This above isn't meant to give the impression that iterating over collections in Velocity is something that requires great care and thought. Rather, the opposite is true, in general. Just be careful when you place an Iterator into the context.
上下文链Context Chaining
Velocity的上下文设计中的一个革命性的创新是加入了上下文链的概念,有时候也称为上下文包装。这种思想让你能将分散的上下文对象连接起来,并看作一个联合的上下文对象来使用。An innovative feature of Velocity's context design is the concept of context chaining. Also sometimes referred to as context wrapping, this advanced feature allows you to connect separate contexts together in a manner that makes it appear as one 'contiguous' context to the template.
最好使用一个例子来演示一下:This is best illustrated by an example : 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 );
在上面的例子中,我们建立连接context1的context2。这意味着在末拌种,你可以使用任何放在这两个上下文中的对象(但这时不能存在使用同样的key来放入对象)。如果这样做了(使用了重复的key来保存对象),在比较后面定义(外层)的上下文中的那个对象将有效。比如在上面的例子中,如果使用duplicate来引用,得到的将会是"I am in context2"In the code above, we have set up context2 such that it chains context1. This means that in the template, you can access any of the items that were put into either of the two VelocityContext objects, as long as there is no duplication of the keys used to add objects. If that is the case, as it is above for the key 'duplicate', the object stored in the nearest context in the chain will be available. In this example above, the object returned would be the string "I am in context2".
注意这种重复定义(或者叫做覆盖定义),对被覆盖了的对象没有任何害处或者改变。所以,在上面的例子中,字符串"I am in context1"仍然存在并状态良好,并且如果通过使用context1.get("duplicate")就能正确地得到。但在上面的例子中,在模版中使用$duplicate的引用会得到"I am in context2"的值,并且模版上的引用不可能得到"I am in context1"。Note that this duplication, or 'covering', of a context item does not in any way harm or alter the covered object. So in the example above, the string "I am in context1" is alive and well, still accessable via context1.get("duplicate"). But in the example above, the value of the reference '$duplicate' in the template would be 'I am in context2', and the template has no access to the covered string 'I am in context1'.
注意,如果你依赖从模版中向上下文添加一些在合成时需要检查的状态值,你需要小心。通过在模版中使用#set来改变上下文中的值得时候,只会影响最外层的上下文。所以,确保如果你不希望从模版中改变内层上下文的值得时候,不要丢弃外层的上下文。Note also that you have to be careful when you are relying on the template to add information to a context that you will examine later after the rendering. The changes to the context via #set() statements in a template will affect only the outer context. So make sure that you don't discard the outer context, expecting the data from the template to have been placed onto the inner one.
This feature has many uses, the most common so far is providing layered data access and toolsets.
如同前面所介绍的,Velocity的上下文机制也是能被扩展的,不过这超越了本指南的范围。如果你对这感兴趣,请参看在org.apache.velocity.context包中的类是怎样提供上下文对象并把它们联合起来的。同时,在examples/context_example目录下,也有一些例子演示了怎样扩展上下文,包括了使用数据库来作为上下文对象的例子(虽然这是个很愚蠢的想法)。As mentioned before, the Velocity context mechanism is also extendable, but beyond the current scope of this guide. If you are interested, please see the classes in the package org.apache.velocity.context to see how the provided contexts are put together. Futher, there are a few examples in the examples/context_example directory in the distribution which show alternate implementations, including [a goofy] one that uses a database as the backing storage.
请注意这些例子仅仅用于演示,而没有被验证实用价值。Please note that these examples are unsupported and are there for demonstration/educational purposes only.
在模版中创建的对象Objects Created in the Template
有两种情况下,Java代码需要处理在运行时从模版中创建的对象。There are two common situations where the Java code must deal with objects created at runtime in the template :
当一个模版的作者调用了一个放在上下文中的用Java编写的对象的方法的时候:When a template author calls a method of an object placed into the context by Java code. #set($myarr = "a","b","c" )
$foo.bar( $myarr )
当一个模版向上下文中添加了一些在模版合成之后,Java代码需要处理的对象时。When a template adds objects to the context, the Java code can access those objects after the merge process is complete. #set($myarr = "a","b","c" )
#set( $foo = 1 )
#set( $bar = "bar")
处理这些情况只需要了解一些事实:Dealing with these cases if very straighforward, as there are just a few things to know:
- 在VTL中当把一个范围操作[1..10]或者和对象数组["a","b"]放入上下文中是java.util.ArrayList对象。因此,当你设计的方法是需要接受一个数组的时候,请注意这一点。The VTL RangeOperator [ 1..10 ] and ObjectArray ["a","b"] are java.util.ArrayList objects when placed in the context or passed to methods. Therefore, your methods that are designed to accept arrays created in the template should be written with this in mind.
- 数字将作为Integer放入上下文中,字符串是String。Numbers will be Integers in the context, and strings will be, of course, Strings.
- 在方法调用的时候,Velocity也会接受原始值。比如通过#set放入上下文中的一个Integer也能调用setFoo(int i)方法。Velocity will properly 'narrow' args to method calls, so calling setFoo( int i ) with an int placed into the context via #set() will work fine.
关于上下文的其他问题Other Context Issues
One of the features provided by the VelocityContext (or any Context derived from AbstractContext) is node specific introspection caching. Generally, you as a the developer don't need to worry about this when using the VelocityContext as your context. However, there is currently one known usage pattern where you must be aware of this feature.
The VelocityContext will accumulate intropection information about the syntax nodes in a template as it visits those nodes. So, in the following situation:
- You are iterating over the same template using the same VelocityContext object.
- Template caching is off.
- You request the Template from getTemplate() on each iteration.
It is possible that your VelocityContext will appear to 'leak' memory (it is really just gathering more introspection information.) What happens is that it accumulates template node introspection information for each template it visits, and as template caching is off, it appears to the VelocityContext that it is visiting a new template each time. Hence it gathers more introspection information and grows. It is highly recommended that you do one or more of the following :
- Create a new VelocityContext for each excursion down through the template render process. This will prevent the accumulation of introspection cache data. For the case where you want to reuse the VelocityContext because it's populated with data or objects, you can simply wrap the populated VelocityContext in another, and the 'outer' one will accumulate the introspection information, which you will just discard. Ex. VelocityContext useThis = new VelocityContext( populatedVC ); This works because the outer context will store the introspection cache data, and get any requested data from the inner context (as it is empty.) Be careful though - if your template places data into the context and it's expected that it will be used in the subsequent iterations, you will need to do one of the other fixes, as any template #set() statements will be stored in the outermost context. See the discussion in Context chaining for more information.
- Turn on template caching. This will prevent the template from being re-parsed on each iteration, resulting the the VelocityContext being able to not only avoid adding to the introspection cache information, but be able to use it resulting in a performance improvement.
- Reuse the Template object for the duration of the loop iterations. Then you won't be forcing Velocity, if the cache is turned off, to reread and reparse the same template over and over, so the VelocityContext won't gather new introspection information each time. 在Servlets中使用Velocity
Using Velocity In Servlets
Servlet编程Servlet Programming
Velocity最常用的地方就是在Web应用中的Java Servlet编程了。有许多理由来解释为什么Velocity很适合这样工作,其中最主要的一个就是Velocity的强制性的将视图层和逻辑层分开了。有许多关于这方面的资料,包括这个。The most common use of Velocity is in the area of Java Servlet programming for the WWW. There are many reasons why Velocity is well suited for this task, one of the primary ones is Velocity's enforcement of the separation of the presentation (or view) layer from the code layer. There are many resources on this subject, including this.
把Velocity应用于servlet环境的基础技术是很简单的,所有你需要做的就是继承VelocityServlet基础类,并实现一个handleRequest()方法,这就是全部。The basic technique of using Velocity in a servlet environment is very simple. In a nutshell, all you must do is extend the provided VelocityServlet base class and implement a single method, handleRequest(). That's really all that is required to use Velocity in your servlet development.
对于Velocity1.1,有两个方法需要实现:As of Velocity 1.1, there are two handleRequest() methods :
public Template handleRequest( Context ) 这是比较老的一个方法,这个方法要求你返回一个合法的Template对象。如果该对象无效或者为null,则被认为是一个错误的状态,并使用error()错误处理方法来处理。如果需要,你可以覆盖error()方法。如果该方法返回null也是你希望的一个正确的返回值(比如你想重定向请求),建议你使用下面一个比较新的方法。This is the older of the two methods. This method requires that you return a valid Template object. If not valid, or null, this is considered an error condition, and will result in the error() error handling method being called. You may override the error() if you wish. If returning a null is something you expect to do (for example, you will want to redirect requests) it is recommended that you use the newer method, listed next.
public Template handleRequest( HttpServletRequest, HttpServletResponse, Context ) 这个方法比较新,在1.1中实现。这两者最大的区别在于在这个方法中,HttpServletReuqest和HttpServletResponse对象是作为参数传递给方法的。灵鸽一个不同的地方在于这个方法允许返回一个null来表明在该方法中所有的处理已经做完了,Velocity只能再调用requestCleanup()方法。这个方法在你需要重定向请求的时候特别有用。This is the newer of the two handleRequest() methods, implemented in version 1.1. The difference with this method is that the HttpServletRequest and HttpServletResponse objects are passed to you as arguments to the method, as well as in the Context. The other difference is that this method can return null to indicate that all processing has been handled by the method, and that Velocity should do nothing further than call requestCleanup(). This is extremely useful is you wish to redirect the request, for example. 同样,请参看Javadoc API文档来得到更多的信息。As always, please refer to the Javadoc API documentation for the definitive and latest notes.
下面这个例子和在发布文件中的SampleServlet.java文件(在example文件夹下)相似。The following code is similar to the SampleServlet.java class included in the distribution in the examples directory.
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 )
{
}
catch( ParseErrorException pee )
{
}
catch( Exception e )
{}return template;
}
}
很眼熟?创建上下文对象的错误处理在VelocityServlet中已经处理,并且merge()方法的调用也在Velocity基础类中处理了。总的来说,这和我们在介绍Velocity的使用的基本格式的时候是一致的。在该例子中,我们向context中放入了一些应用数据,然后返回了一个模版。Look familiar? With the exception of creating the context object, which is done for you by the VelocityServlet base class, and the merge() step which is also done for you by the VelocityServlet base class, it's identical to the basic code pattern we mentioned at the beginning of this guide. We take the context, add our application data, and return a template.
在传入方法(第一个方法)的Context对象中,保存了当前的HttpServletRequest和HttpServletResponse对象。他们使用VelocityServlet.REQUEST(value="req")和Velocity.RESPONSE(VALUE="RES")常量来引用。要在你的代码中使用这些对象,象下面这样做:The default Context object that is passed into the handleRequest() methods contains both the current HttpServletRequest and HttpServletResponse objects. They are placed in the context using the the constants VelocityServlet.REQUEST (value = 'req') and VelocityServlet.RESPONSE (value = 'res') respectively. To access and use these objects in your Java code : public Template handleRequest( Context context )
{
HttpServletRequest request = (HttpServletRequest) context.get( REQUEST );
HttpServletResponse response = (HttpServletResponse) context.get( RESPONSE );
...
或者在你的模版中这样引用:and in your templates: #set($name = $req.getParameter('name') )
如果需要更高级的使用,VelocityServlet基础类允许你覆盖请求处理的一些部分,下面的这些方法可能是一个扩展点:For more advanced uses, the VelocityServlet base class allows you to override parts of the handling of the request processing. The following methods may be overridden :
Properties loadConfiguration( ServletConfig ) 允许你覆盖普通的配置机制并且添加或者修改一些配置属性。覆盖这个方法用来覆盖或者参数化模版和日志的路径,该路径需要基于webapp root的绝对路径。Allows you to override the normal configuration mechanism and add or alter the configuation properties. This is useful for overriding or augmenting template and log paths, to set the absolute path into the webapp root at runtime.
Context createContext(HttpServletRequest, HttpServletResponse ) 与许你创建自己的Context对象。这在需要更高级的情况下使用,比如需要链化或者预加载一些工具或者数据。默认的该方法的实现简单的返回了一个包含了HttpServletRequest和HttpServletResponse的VelocityContext对象。请求和响应对象使用简单的包装类包装,以避免在一些servlet容器中自省时会发生的错误。但你可以象平常一样使用其中的request和response对象,或者从模版中引用其方法。只需要注意一点,就是他们不再是javax.servlet.XXXX类了,如果你需要使用类全名的时候,需要重视。Allows you to create the Context object yourself. This allows more advanced techniques, such as chaining or pre-loading with tools or data. The default implementation simply returns a VelocityContext object with the request and response objects placed inside. The request and response objects are wrapped in simple wrapper classes to avoid introspection problems that may occurr in some servlet container implementations. You can use the request and repsponse objects normally, accessing methods of either from the template. Just note that they aren't specifically javax.servlet.XXXX classes, if that is important to you.
void setContentType( HttpServletRequest,HttpServletResponse ) 允许你检查请求,并设置内容类型(content type)。默认的类型是根据Velocity.properties中规定的。如果没有在properties文件中设定,或者说在默认情况下,"text/html"将是内容类型。Allows you to examine the request and set the content type yourself, depending on the request or client. The default implementation sets the content type to be that either specified in the velocity.properties, if any, or the default, "text/html" if not specified in the properties.
void mergeTemplate( Template, Context, HttpServletResponse ) 允许你创建输出流。VelocityServlet使用了一个很有效的Writer类的缓存池,所以在一般情况下,该方法不会被覆盖。Allows you to produce the output stream. The VelocityServlet uses a pool of very efficient Writer classes, so this would usually be overridden in special situations.
void requestCleanup( HttpServletRequest, HttpServletResponse , Context ) 允许你在请求处理结束后做一些清理工作或者资源的回收工作。默认的方法没有做任何事情。Allows you to do any cleanup or resource reclamation at the end of the request processing. The default does nothing.
protected void error( HttpServletRequest, HttpServletResponse, Exception ) 如果在请求处理中出现异常,就将调用该方法来处理异常。默认的处理将会返回一个普通的带有栈信息和错误信息的HTML页面给用户。覆盖该方法提供更人性化的错误提示或者异常处理。Error handler that is called an exception occurrs in request processing. Default implementation will send a simple HTML message with stacktrace and exception information back to the user. Override for custom client messages and more advanced problem handling.
更多的信息请参见Javadoc API文档。For further information, please see the Javadoc API documentation.
部署Deployment
当你部署基于Velocity的servlet应用,你试图确定你的配置文件被用来配置了Velocity引擎。在Tomcat下,达到该目的的方法之一是将你的velocity.properties文件放在你的web应用的根目录下(webapps/appname),并在你的WEB-INF/web.xml文件后面加上:When you deploy your Velocity-based servlets, you will certainly want to ensure that your properties file is used to configure the Velocity runtime. Under Tomcat, one way to accomplish this is by placing your velocity.properties file into the root directory of your web app (webapps/appname ) and then add the following to your WEB-INF/web.xml file : <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.prooetries文件来初始化Velocity引擎。Assuming all is right, this will ensure that when MyServlet is loaded, it will use the velocity.properties file to initialize itself rather than relying on it's internal defaults.
注意Velocity在它的核心的Runtime类中使用的是单例模式,所以,把velocitypXX.jar放在WEB-INF/lib文件夹中会是一个更好的选择。Note that Velocity uses a singleton model for it's central core Runtime class, so it is a very good idea to put the velocity-XX.jar into the WEB-INF/lib directory in all web applications that use Velocity to ensure that the web app classloader is managing your Runtime instance, rather than putting it in the CLASSPATH or the top level lib directory of the servlet runner.
这种部署方式能确保在不同的web应用中使用的Velocity配置不会冲突。This deployment method will ensure that different web applications will not be subject to Velocity configuration conflicts. 在普通的应用中使用Velocity
Using Velocity In General Applications
Velocity被设计为一个通用的工具,在一般的应用中,Velocity也很有用。概括地说,在一般的应用中,使用Velocity的基本结构和在本指南开始介绍的那个结构一致,和VelocityServlet提供给了编写Servlet的便利性一样,Velocity也为一般的应用提供了一些工具类。作为一个一般应用的程序员,你的一个新的责任就是初始化Velocity运行时引擎(Velocity runtime engine),但这也很简单。As Velocity was designed to be a general-use tool, it is just as useful in general application programs as it is servlets. In general, you can use the same programming pattern discussed at the beginning of this guide, but there are a few utility methods provided for application use, just like we provide the VelocityServlet base class for ease of use in servlet programming. The only new responsibility you have as the application programmer is to initialize the Velocity runtime engine, but that is easy.
The Velocity Helper Class
Velocity包含了一个为一般应用准备的工具类,叫做Velocity(org.apache.velocity.Velocity)。提供该类的目的在于提供一些初始化Velocity必须的方法和一些有用的日常工具方法,让使用Velocity更加方便。这个类在Javadoc中有详细记录,如有需要,请参考该文档。在这里,该文档只是作为一个指南,而Javadoc则提供了最完整的API的信息。Velocity contains an application utility class called Velocity ( org.apache.velocity.app.Velocity ). The purpose of this class is to provide the necessary methods required to initialize Velocity, as well as useful utility routines to make life easier in using Velocity. This class is documented in the project's javadoc, so please look there for definitive details. This documentation is intended to be of a tutorial nature; therefore for compete API information, the Javadoc is the definitive source.
Velocity运行时引擎是一个单例的实例,在一个JVM中为所有的Velocity用户提供资源,日志记录,和其他的服务。不过,运行时引擎只需要初始化一次即可。你可能会尝试多次初始化该引擎,但只有第一次的初始化操作是成功的,之后的尝试会直接被忽略。现在的Velocity工具类提供了5个方法来配置运行时引擎。The Velocity runtime engine is a singleton instance that provides resource, logging and other services to all Velocity users running in the same JVM. Therefore, the runtime engine is initialized only once. You can attempt to initialize Velocity more than once, but only the first initialization will apply. The rest of the attempts will be ignored. The Velocity utility class currently provides five methods used in configuration of the runtime engine.
这5个方法分别为:The five configuration methods are :
- setProperty( String key, Object o )
给属性key赋值o。该值一般为一个String,但在特殊的情况下,可以是用逗号分隔了的列表值(在一个String中,比如:"foo,bar,woogie")或者其他的一些东西。Sets the property key with the value o. The value is typically a String, but in special cases can also be a comma-separated list of values (in a single String, ex."foo, bar, woogie") as well as other things that will arise.
- Object getProperty( String key )
返回属性key的值。注意你必须强制的转化类型,不然,返回的总是String。Returns the value of the property key. Note that you must be aware of the type of the return value, as they can be things other than Strings.
- init()
使用分发包中的属性初始化运行时状态。(这些值在下面的关于属性小节中列出)Initializes the runtime with the default properties provided in the distribution.(These are listed below in the section pertaining to properties.)
- init( Properties p )
使用参数中传入的java.util.Properties对象中包含的属性来初始化运行时状态。Initialize the runtime with the properties contained in the java.util.Properties object passed as an argument.
- init( String filename )
使用参数中传入的文件路径对应的属性文件来初始化运行时状态。initilizes the runtime using the properties found in the properties file filename
注意,不论使用哪种方法,默认的属性都会作为基础的配置,所有增加的或者修改了的属性都会覆盖对应的默认的配置。没有被覆盖的属性仍然起作用。这样的好处是只有你关注的属性才被指定,而不需要把所有的属性都指定出来。Note that in each case, the default properties will be used as a base configuration, and any additional properties specified by the application will replace individual defaults. Any default properties not overwritten will remain in effect. This has the benefit that only the properties you are interested in changing need to be specified, rather than a complete set.
另一个需要注意的是init()方法可以被多次调用但并不会出现错误。但是,只有第一次调用init()方法才将使用配置属性集来配置引擎,而其后对配置属性的更改或者重新调用init()方法都会被忽略。Another thing to note is that the init() calls may be called more than once without harm in an application. However, the first call to any of the init() functions will configure the engine with the configuration properties set at that point, and any further configuration changes or init() calls will be ignored.
最普通的初始化Velocity的方法会像是这样:The most common approaches to initializing Velocity will be something like :
- 用类似于org/apache/velocity/runtime/defaults/velocity.properties文件的格式那样将自己的需要的配置属性的值写入一个文件,或者放入一个java.util.Properties中,并且调用init(filename)或者init(Properties)方法。Setup the configuration values you wish to set in a file in the same format as org/apache/velocity/runtime/defaults/velocity.properties (the default set), or in a java.util.Properties, and then call either init( filename ) or init( Properties )
- 使用setProperty()方法独立的设置配置属性,并且调用init()方法。这个方法一般在比较高级的情况下------应用拥有自己的配置管理系统,比如应用使用它自己生成的配置文件在运行时配置Velocity。Set the configuration values individually using setProperty() and then call init(). This method is generally used by more advanced applications that already have their own configuration management system - this allows the application so configure Velocity based upon values it generates at runtime, for example.
一旦运行时被初始化,你可以做你想做的任何事情了,比如把模版合成并放入一个输出流中,Velocity提供的工具类能帮你很简单的完成这些任务。下面是一些该工具类的主要的方法的描述。Once the runtime is initialized, you can do with it what you wish.. This mostly revolves around rendering templates into an output stream, and the Velocity utility class allows you to do this easily. Currently, here are the methods and a brief description of what they do :
- evaluate( Context context, Writer out, String logTag, String instring )
evaluate( Context context, Writer writer, String logTag, InputStream instream )
这些方法将使用你提供的上下文来解释输入流---以String或InputStream对象存在,并放入一个输出Writer中。这是一个很方便的用字符串替换标识的方法,如果你坚持使用VTL'模版'-----即使这些'模版'是保存在数据库中的,或者非文件形式的甚至直接是应用生成的。These methods will render the input, in either the form of String or InputStream to an output Writer, using a Context that you provide. This is a very convenienient method to use for token replacement of strings, or if you keep 'templates' of VTL-containing content in a place like a database or other non-file storage, or simply generate such dynamically.
- invokeVelocimacro( String vmName, String namespace, String params[], Context context, Writer writer )
允许直接使用Velocity宏。这也能通过上面介绍的evaluate()方法达到。这里,你需要指定你想要执行的宏的名字,创建一个传递给VM的参数的数组,一个带有数据的上下文对象和一个输出Writer。注意传递给VM的参数必须是在上下文中对应的值得key值,而不是该宏真正要使用的参数值。就是说,宏真正得到的参数是通过传入的key来从上下文中得到的值。这一个特性可能会在以后改变。Allows direct access to Velocimacros. This can also be accomplished via the evaluate() method above if you wish. Here you simply name the vm you wish to be called, create an array of args to the VM, a Context of data, and Writer for the output. Note that the VM args must be the 'keys' of the data objects in the Context, rather than literal data to be used as the arg. This will probably change.
- mergeTemplate( String templateName, Context context, Writer writer )
方便的调用Velocity的模版处理和合成服务的方法。该方法会处理并合成模版。更进一步的,该方法也会通过对文件资源加载器设置的属性来加载模版,并且提供Velocity的文件和模版的缓存器。这是最有效的访问模版的方法,除非你有特殊的需求,我们建议你使用该方法。Convenient access to the normal template handling and rendering services of Velocity. This method will take care of getting and rendering the template. It will take advantage of loading the template according to the properties setting for the file resource loader, and therefore provides the advantage of file and parsed template caching that Velocity offers. This is the most efficient way to access templates, and is recommended unless you have special needs.
- boolean templateExists( String name )
测试一个名字为name的模版文件是否能在当前配置的资源加载器中找到。Determines if a template name is able to be found by the currently configured resource loaders.
一旦我们了解了这些基本的助手方法,我们就能很容易的使用Velocity写出Java程序了,如下面所示:Once we know about these basic helpers, it is easy to write Java program that uses Velocity. 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也在应用的同一个目录下(因为我们这里使用的是默认的资源加载器,会在当前目录下加载模版文件),我们的输出应该是:When we run this program, and have the template testtemplate.vm in the same directory as our program (because we used the default configuration properties, and the defaul place to load templates from is the current directory...), our output should be : template :
Hi! This Velocity from the Jakarta project.
string : We are using Jakarta Velocity to render this.
testtemplate.vm的内容是:where the template we used, testtemplate.vm, is
Hi! This $name from the $project project.
这就是在普通应用中使用Velocity~注意我们没有必要在一个应用中同时mergeTemplate()和evaluate()方法。在这里同时使用它们是为了演示的需要。你可能只需要其中一个,但也要看你应用的需求来选择。That's all there is to it! Note that we didn't have to use both mergeTemplate() and evaluate() in our program. They are both included there for demonstration purposes. You will probably use only one of the methods, but depending on you application requirements, you are free to do what you wish.
这段代码和我们在指南开始时提到的基础结构有一些区别。第一,你创建了一个上下文对象并使用需要的数据填充,但在这个例子中,mergeTemlate()方法被使用了,mergeTemplate()方法为你处理了模版并且合成了输出------使用的正是对底层的Runtime类的调用。在第二个例子中,你是通过一个String对象作为模版的,所以,代码忽略了寻找模版的步骤,并且evaluate()调用底层方法为你合成了输出。This appears to be a little different from the 'fundamental pattern' that was mentioned at the beginning of this guide, but it really is the same thing. First, you are making a context and filling it with the data needed. Where this examples differs is that in the part of the above example where mergeTemplate() is used, mergeTemplate() is doing the work of getting the template and merging it for you, using the lower-level calls in the Runtime class. In the second example, you are making your template dynamically via the String, so that is analgous to the 'choose template' part of the process, and the evaluate() method does the merging for you using lower level calls.
So the example above sticks to the same simply pattern of using the Velocity template engine, but the utility functions do some of the repeated drudge work, or allow you other options for your template content other than template files.
异常Exceptions
在解析和合成的过程中,会有三种异常可能被抛出。这些是除了IO错误之外的错误,在org.apache.vleocity.exception包中可以找到它们:There are three exceptions that Velocity will throw during the parse / merge cycle. This are additional to the exceptions that will come from IO problems, etc. They are found in the package org.apache.velocity.exception and are:
- ResourceNotFoundException
当资源管理系统不能找到一个请求的资源(模版)的时候抛出。Thrown when the resource managment system cannot find a resource (template) that was requested.
- ParseErrorException
当在解析一个资源(模版)发现语法错误的时候抛出。Thrown when a VTL syntax error is found when parsing a resource (template).
- MethodInvocationException
当在合成时期,上下文中一个对象的方法执行期间抛出异常时抛出。该出错方法抛出的错误将会被包装并传递给应用。这要求你在运行时处理自己的对象抛出的错误。Thrown when a method of object in the context thrown an exception during render time. This exception wraps the thrown exception and propogates it to the application. This allows you to handle problems in your own objects at runtime.
一旦以上的情况发生,一个错误信息就会被放入运行时日志中。更多信息请参见Javadoc API文档。In each case, a message is put into the runtime log. For more information, see the Javadoc API documentation.
其他细节Miscellaneous Details
尽管上面的例子使用的是默认的配置,但是要使用自定义的配置也是很容易的事情。你需要做的就是创建一个属性文件,并将该文件的路径名通过init(String)方法或者通过创建一个自定义属性名/值的java.util.Properties对象并调用init(Properties)方法既可以了。后者更为方便,因为你既可以通过使用load()方法从某个属性文件中加载属性,也可以在运行时动态的从你的应用或者框架的配置文件中得到。这给了你将关于应用的所有属性都配置在一个文件中的灵活性。While the above example used the default properties, setting your own properties is very simple. All you have to do is make a properties file somewhere and pass the name of that file to the init(String) method of the Velocity utility class, or make a java.util.Properties object, add the desired properties and values, and pass that to the init(Properties) method. The latter method is convenient, because you can either fill it directly from a separate properties file via the load() method, or even better, you can fill it dynamically from your own application / framework's property set at runtime. This gives you the freedom to combine all of the properties for your app into one properties file.
如果我们想使用一个不同的文件夹来存放模版文件,我们就可以象这样来加载它们:If we wanted to use a different directory than the current directory to load our template from, we could do something like this :
...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 */...
现在,假设你有一个/opt/templates文件夹,并且有一个叫做testtemplate.vm的模版文件在里面,那么一切都将正常工作。如果你这样做后发生了一些错误,那么请确认velocity.log中的记录来得到更多的信息------错误消息能很快地确定哪里出错了。And, assuming you have a directory /opt/templates and the template testtemplate.vm is in there, then things would work just fine. If you try this and have a problem, be sure to look at the velocity.log for information - the error messages are pretty good for figuring out what is wrong. 应用属性
Application Attributes
应用属性是名/值对,在RuntimeInstance中被访问。Application Attributes are name-value pairs that can be associated with a RuntimeInstance (either via the VelocityEngine or the Velocity singleton) and accessed from any part of the Velocity engine that has access to the RuntimeInstance.
这个特性是为了那些需要在应用层和自定义的Velocity引擎之间联系的情况而设计的,这些联系包括资源加载器,日志记录器和资源管理器等等。This feature was designed for applications that need to communicate between the application layer and custom parts of the Velocity engine, such as loggers, resource loaders, resource managers, etc.
应用属性API很简单,从应用层来看,在VelocityEngine和Velocity类中都有一个方法:The Application Attribute API is very simple. From the application layer, there is a method of the VelocityEngine and the Velocity classes : public void setApplicationAttribute( Object key, Object value );
through which an application can store on Object under an application (or internal component) specified key. There are no restrictions on the key or the value. The value for a key may be set at any time - it is not required that this be set before init() is called.
Internal components can access the key-value pairs if they have access to the object via the RuntimeServices interface, using the method public Object getApplicationAttribute( Object key );
Note that internal components cannot set the value of the key, just get it. if the internal component must communicate information to the application layer, it must do so via the Object passed as the value.
从Velocity1.1开始,一个结构良好的事件处理系统被添加到Velocity中。EventCartridge是一个你用来注册你的事件处理器的类,并且在需要的时候,这个类扮演了一个Velocity引擎将和事件处理器之间联系的中转代理角色。目前,有三个事件可以被处理,他们都在org.apache.velocity.app.event包中。Starting in version 1.1, a fine-grain event handling system was added to Velocity. The EventCartridge is a class in which you register your event handlers, and then the EventCartridge acts as the delivery agent from which the Velocity engine will access the event handlers at merge time if needed. Currently, there are 3 events that can be handled, and all are found in the org.apache.velocity.app.event package.
org.apache.velocity.app.event.NullSetEventHandler 当一个#set()导致了一个空的赋值,一般情况下这会被日志记录。
NullSetEventHandler允许你禁止在这种情况下记录日志。When a #set() results in a null assignment, this is normally logged.
The NullSetEventHandler allows you to 'veto' the logging of this condition.
public interface NullSetEventHandler extends EventHandler
{
public boolean shouldLogOnNullSet( String lhs, String rhs );
}
org.apache.velocity.app.event.ReferenceInsertionEventHandler
ReferenceInsertionEventHandler 允许程序员拦截每一个将要写入输出流中的的引用的值,并修改输出流。A ReferenceInsertionEventHandler allows the developer to intercept each write of a reference ($foo) value to the output stream and modify that output.
public interface ReferenceInsertionEventHandler extends EventHandler
{
public Object referenceInsert( String reference, Object value );
}
org.apache.velocity.app.event.MethodExceptionEventHandler 当一个用户定义的方法抛出了异常时,该事件处理器被触发,方法中带有抛出异常的类,抛出异常的方法名,和抛出的异常。该方法允许返回一个合法的对象,并且返回的对象将被合并到输出流中,同时,你也能将传入的异常重新抛出或者包装后抛出,这些方法将被包装成一个MethodInvocationException并且返回给用户。When a user-supplied method throws an exception, the MethodExceptionEventHandler is invoked with the Class, method name and thrown Exception. The handler can either return a valid Object to be used as the return value of the method call, or throw the passed-in or new Exception, which will be wrapped and propogated to the user as a MethodInvocationException
public interface MethodExceptionEventHandler extends EventHandler
{
public Object methodException( Class claz, String method, Exception e ) throws Exception;
}
使用EventCartridge也很直接。下面的这个简化了的例子是从org.apache.velocity.test.misc.Test中取出的。 the EventCartridge is fairly straightforward. The following abbreviated example was taken from 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 tosupport the event handler interfaces. So to use them, firstmake 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 normallydo
*/....
}/*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;
}
}
Velocity Configuration Keys and Values
Velocity运行时配置是被一组配置关键字控制的。一般来说,这些关键字都和一个String,或者一个逗号分隔的String值对应。Velocity's runtime configuration is controlled by a set of configuration keys listed below. Generally, these keys will have values that consist of either a String, or a comma-separated list of Strings, referred to as a CSV for comma-separated values.
在Velocity的jar文件中的/src/java/org/apache/runtime/defaults/velocity.defaults文件中,定义了一组默认值,Velocity把这组默认值作为基础配置。这样做确保了Velocity在启动的时候总是含有正确的配置值,虽然这些值不一定都是你希望的。There is a set of default values contained in Velocity's jar, found in /src/java/org/apache/velocity/runtime/defaults/velocity.defaults, that Velocity uses as it's configuration baseline. This ensures that Velocity will always have a 'correct' value for it's configuration keys at startup, although it may not be what you want.
在使用init()方法之前自定义的值都能代替默认值。因此你只需要使用你需要改变的关键字和值来配置Velocity,而不需要包含其他的。Any values specified before init() time will replace the default values. Therefore, you only have to configure velocity with the values for the keys that you need to change, and not worry about the rest. Further, as we add more features and configuration capability, you don't have to change your configuration files to suit - the Velocity engine will always have default values.
请参见Using Velocity In General Applications 小节,得到关于配置API的讨论。Please sees the section above Using Velocity In General Applications for discussion on the configuration API.
下面列出了控制Velocity行为的关键字,通过不同的种类来组织的,在每一个关键字介绍之后都给出了目前的默认值。Below are listed the configuration keys that control Velocity's behavior. Organized by category, each key is listed with it's current default value to the right of the '=' sign.
运行时日志Runtime Log
runtime.log = velocity.log
用于记录错误,警告,信息的日志文件的完整路径和名字。该路径不是绝对路径,则相对于当前路径。Full path and name of log file for error, warning, and informational messages. The location, if not absolute, is relative to the 'current directory'.
runtime.log.logsystem
该属性没有默认值。他是用来提供给Velocity一个实现了org.apache.velocity.runtime.log.LogSystem接口的日志记录类,该类允许Velocity日志信息和你的其他应用的日志信息结合起来。请参看Configuring the Log System 来得到更多信息。This property has no default value. It is used to give Velocity an instantiated instance of a logging class that supports the interface org.apache.velocity.runtime.log.LogSystem., which allows the combination of Velocity log messages with your other application log messages. Please see the section Configuring the Log System for more information.
runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem
用来作为Velocity日志系统的类。Class to be used for the Velocity-instantiated log system.
runtime.log.error.stacktrace = false
runtime.log.warn.stacktrace = false
runtime.log.info.stacktrace = false
为这三种种类的错误打开栈信息输出。这些信息会导致大量的日志记录工作。Turns on stacktracing for the three error categories. These produce a large amount of log output.
runtime.log.invalid.references = true
该属性关掉了当一个引用无效时的日志记录。在产品中因该关掉,而在调式的时候,这是很有用的信息。Property to turn off the log output when a reference isn't valid. Good thing to turn of in production, but very valuable for debugging.
runtime.log.logsystem.avalon.logger =name
允许用户自定义一个在Avalon系统中存在的日志记录器的名字而不需要用一个LogSystem接口包装。注意,你必须同时也定义好runtime.log.logsystem.class=org.apache.velocity.runtime.log.AvalonLogSystem作为默认的日志记录器也需要改变。因为这样并不保证Avalon日志系统仍然是默认的日志系统。Allows user to specify an existing logger name in the Avalon hierarchy without having to wrap with a LogSystem interface. Note: You must also specify runtime.log.logsystem.class = org.apache.velocity.runtime.log.AvalonLogSystem as the default logsystem may change. There is no guarantee that the Avalon log system will remain the default log system.
编码格式Character Encoding
input.encoding = ISO-8859-1
输入(模版)的编码格式。使用该属性,你能改变你模版中的字符编码,比如utf-8。Character encoding for input (templates). Using this, you can use alternative encoding for your templates, such as UTF-8.
output.encoding = ISO-8859-1
从VelocityServlet和Anakia中的输出流的编码格式。Character encoding for output streams from the VelocityServlet and Anakia.
#foreach() Directive
directive.foreach.counter.name = velocityCount
使用#foreach()指示符时,作为上下文中遍历计数器的对象的名字。在模版中可以使用象$velocityCount来引用计数器。Used in the #foreach() directive, defines the string to be used as the context key for the loop count. A template would access the loop count as $velocityCount.
directive.foreach.counter.initial.value = 1
在#foreach中遍历计数器的起始值。Default starting value for the loop counter reference in a #foreach() loop.
#include() and #parse() Directive
directive.include.output.errormsg.start =
directive.include.output.errormsg.end =
定义一个#include()指示符导致的输入流错误信息的开始标志和结束标志,如果开始和结束标志都定义了,比如starttag和endtag为对应的值,那么一个错误的信息将会以格式starttag msg endtag放入输出流中。只有开始和结束标志都定义了,消息才会被放入输出流中。Defines the beginning and ending tags for an in-stream error message in the case of a problem with the #include() directive. If both the .start and .end tags are defined, an error message will be output to the stream, of the form '.start msg .end' where .start and .end refer to the property values. Output to the render stream will only occur if both the .start and .end (next) tag are defined.
directive.parse.maxdepth = 10
定义一个模版允许的解析深度。一个模版可能会#parse另一个也有#parse的模版。该值防止了#parse的死循环。Defines the allowable parse depth for a template. A template may #parse() another template which itself may have a #parse() directive. This value prevents runaway #parse() recursion.
资源管理Resource Management
resource.manager.logwhenfound = true
用来控制是否在资源管理器中将"found"日志信息打开。当一个资源被第一次找到,该资源的名字和类名将被记录在日志文件中。Switch to control logging of 'found' messages from resource manager. When a resource is found for 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)
多值的关键字,允许使用CSV作为值。Multi-valued key. Will accept CSV for value. 配置要使用的资源加载器的名字。该被配置的名字会继续用来配置对应资源管理器的特定属性。注意,作为一个多值的关键字,你能传入一个了类似"file,class"(不需要引号),表明下面将要为两个加载器作配置。Pulic name of a resource loader to be used. This public name will then be used in the specification of the specific properties for that resource loader. Note that as a multi-valued key, it's possible to pass a value like "file, class" (sans quotes), indicating that following will be configuration values for two loaders.
<name>.loader.description = Velocity File Resource Loader
一个特定的资源加载器的描述。Description string for the given loader.
<name>.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
加载器实现类的名字。默认的加载器是文件加载器。Name of implementation class for the loader. The default loader is the file loader.
<name>.resource.loader.path = .
多值关键字,允许使用CSV作为值。Multi-valued key. Will accept CSV for value. 加载器加载模版的根目录。模版能放在该目录的任何子目录下。比如homesite/index.vm。该配置目前作用于FileResourceLoader和JarResourceLoader。Root(s) from which the loader loads templates. Templates may live in subdirectories of this root. ex. homesite/index.vm This configuration key applies currently to the FileResourceLoader and JarResourceLoader.
<name>.resource.loader.cache = false
在加载器中控制缓存。默认为false,为的是使开发和调试比较简单。该配置应该在产品中设置为true。当modifictionCheckInterval属性被设置,这允许相当有效的缓存。Controls caching of the templates in the loader. Default is false, to make life easy for development and debugging. This should be set to true for production deployment. When 'true', the modificationCheckInterval property applies. This allows for the efficiency of caching, with the convenience of controlled reloads - useful in a hosted or ISP environment where templates can be modifed frequently and bouncing the application or servlet engine is not desired or permitted.
<name>.resource.loader.modificationCheckInterval = 2
当缓存开启时,该选项确定了缓存中两次修改检查的间隔时间。当选项是一个大于0的数值时,该属性规定了两次检查模版是否被修改的间隔时间。如果模版在上一次检查之后被修改,该模版将会被重新加载并重新解析,否则没有任何动作。如果该值小于0,不会执行任何修改检查。假设属性cache 为true,一旦模版被加载并解析后,直到应用或者servlet引擎重起,模版的任何改动都不会被响应。This is the number of seconds between modification checks when caching is turned on. When this is an integer > 0, this represents the number of seconds between checks to see if the template was modified. If the template has been modified since last check, then it is reloaded and reparsed. Otherwise nothing is done. When <= 0, no modification checks will take place, and assuming that the property cache (above) is true, once a template is loaded and parsed the first time it is used, it will not be checked or reloaded after that until the application or servlet engine is restarted.
作为一个演示,这里是一个演示了怎样配置FileResourceLoader的例子:To illustrate, here is an example taken right from the default Velocity properties, showing how setting up the FileResourceLoader is managed 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
velocimacro.library = VM_global_library.vm
多值的关键字,允许使用CSV作为值。Multi-valued key. Will accept CSV for value. 当Velocity运行时引擎开始的时候,会加载这些宏的文件名到Velocity宏库中。所有的模版都能直接使用这些Velocity宏。这些文件路径都相对于文件加载器根路径。Filename(s) of Velocimacro library to be loaded when the Velocity Runtime engine starts. These Velocimacros are accessable to all templates. The file is assumed to be relative to the root of the file loader resource path.
velocimacro.permissions.allow.inline = true
通过在一个模版中使用#macro()指示符来定义宏是否允许的。默认值为true,意味着所有的模版都能定义并使用新的宏。注意,依赖于其他的属性,#macro()语句可以覆盖全局定义。Determines of the definition of new Velocimacros via the #macro() directive in templates is allowed. The default value is true, meaning any template can define and use new Velocimacros. Note that depending on other properties, those #macro() statements can replace global definitions.
velocimacro.permissions.allow.inline.to.replace.global = false
控制在模版中定义的宏是否能覆盖在启动时加载到Velocity宏库中的宏。Controls if a Velocimacro defind 'inline' in a template can replace a Velocimacro defined in a library loaded at startup.
velocimacro.permissions.allow.inline.local.scope = false
控制私有定义的宏的作用空间。当该值为true的时候,在一个模版中定义的宏只能在该模版中使用。这意味着Velocity只能通过在启动时把宏加入到宏库中来实现共享,同时也意味着模版之间的宏不会互相冲突。该属性允许了一种技巧,即可以在全局或本地的宏库中定义一组缺省的宏,各个模版能通过覆盖来实现自己的方法,因为当该属性为true,会在全局宏库之前先搜索在本模版中的宏,因此,实现了这种覆盖机制。Controls 'private' templates namespaces for Velocimacros. When true, a #macro() directive in a template creates a Velocimacro that is accessable only from the defining template. This means that Velocimacros cannot be shared unless they are in the global or local library loaded at startup. (See above.) It also means that templates cannot interfere with each other. This property also allows a technique where there is a 'default' Velocimacro definition in the global or local library, and a template can 'override' the implementation for use within that template. This occurrs because when this property is true, the template's namespace is searched for a Velocimacro before the global namespace, therefore allowing the override mechanism.
velocimacro.context.localscope = false
控制在宏中的引用是否能改变上下文,或者只能改变该宏所在的本地范围。Controls whether reference access (set/get) within a Velocimacro will change the context, or be of local scope in that Velocimacro.
velocimacro.library.autoreload = false
控制宏库的自动重加载。当该属性为true时,就会触发对宏库的代码的改变的检查,并在需要的时候重新加载宏库。这允许你修改和测试你的宏库而不需要每次都手动的重起应用或者servlet容器。该选项只有在缓存被关闭的时候才有用(比如设置file.resource.loader.cache=false)。该特性主要使用在开发阶段,不适合使用在产品中。Controls Velocimacro library autoloading. When set to true the source Velocimacro library for an invoked Velocimacro will be checked for changes, and reloaded if necessary. This allows you to change and test Velocimacro libraries without having to restart your application or servlet container, just like you can with regular templates. This mode only works when caching is off in the resource loaders (e.g. file.resource.loader.cache = false ). This feature is intended for development, not for production.
String Interpolation
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.
运行时配置Runtime Configuration
parser.pool.size = 20
该属性控制在Velocity启动时需要创建并放在缓存池中的解析器的个数。默认的20个应该能满足绝大多数的应用的需要了。当Velocity没有了足够的解析器的时候,将会在日志中记录,并动态的创建新的来使用。注意,这时候创建的解析器就不会再被放入缓存池中了,这时候的解析速度就比较常态慢了,但这中状态也应该被视为一个异常的状态,如果你在日志中发现了这种信息,请增加该值。This property sets the number of parsers that Velocity will create at startup and keep in a pool. The default of 20 parsers should be more than enough for most uses. In the event that Velocity does run out of parsers, it will indicate so in the log, and dynamically create them as needed. Note that they will not be added to the pool. This is a slow operation compared to the normal parser pooling, but this is considered an exceptional condition. If you see a log message, please increment this property.
配置日志系统Configuring the Log System
Velocity提供了几个优秀的日志特点来满足简单性和灵活性。不需要任何的配置,Velocity就会建立一个基于文本记录的日志记录器,并且将所有的日志信息记录到一个叫做velocity.log的文件中,该文件保存在当前目录下。更高级的用户,可以将你目前应用使用的日志记录设施和Velocity结合起来,使Velocity将日志信息发送到你目前的日志中。Velocity has a few nice logging features to allow both simplicity and flexibility. Without any extra configuration, Velocity will setup a file-based logger that will output all logging messages to a file called velocity.log in the 'current directory' where Velocity was initialized. For more advanced users, you may integrate your current logging facilities with Velocity to have all log messages sent to your logger.
从1.3版本开始,Velocity会自动地使用Jakarta Avalon Logkit 或者Jakarta Log4j 日志记录。在类路径下发现了这两个日志框架之一,它就使用哪个。他首先会尝试使用Logkit,如果没有发现Logkit,那么它在尝试使用Log4j。Starting with version 1.3, Velocity will automatically use either the Jakarta Avalon Logkit logger, or the Jakarta Log4j logger. It will do so by using whatever it finds in the current classpath, starting first with Logkit. If Logkit isn't found, it tries Log4j.
利用这个特点,只需要不包含任何依赖库的Velocity包,并将你需要的日志框架------logkit或者log4j放在类路径下就可以了。To utilize this feature, simply use the 'non-dependency' Velocity jar (because Logkit is baked into the jar with dependencies) and place either the logkit or log4j jar in your classpath.
总的来说,你有下面一个关于日志的选项。In general, you have the following logging options :
- 默认的配置Default Configuration
在缺省配置下,Velocity将会在当前目录下创建一个基于文本的日志记录器。By default, Velocity will create a file-based logger in the current directory. See the note above regarding automatic detection of Logkit or Log4j to use as the default logging system.
- 使用现存的Log4j。Existing Log4j Category
从1.3版本开始,Velocity将会把它的日志输出记录到应用中一个存在的Log4j框架中。要使用该特性,你需要:Starting with version 1.3, Velocity will log it's output to an existing Log4j Category setup elsewhere in the application. To use this feature you must
- 确定Log4j的jar文件在你的类路径下。Make sure that the Log4j jar is in your classpath. (You would do this anyway since you are using Log4j in the application using Velocity.)
- 配置Velocity使用SimpleLog4jLogSystem类。Configure Velocity to use the SimpleLog4jLogSystem class.
- 通过配置runtime.log.logsystem.log4j.category属性来确定一个存在的Category的名字。Specify the name of the existing Category to use via the 'runtime.log.logsystem.log4j.category' property.
这种方法不能在老版本中的Log4JLogSystem类中使用。如何用代码来做到这些,请参见下面的例子。This approach replaces and deprecates the older Log4JLogSystem class. To see how this is done in code, see the example below.
- 自定义的独立的日志记录器Custom Standalone Logger
你可以创建一个自定义的日志记录类,一般情况下,你必须实现org.apache.velocity.runtime.log.LogSystem接口,并配置runtime.log.logsystem.class属性来指向你自定义的类名,在初始化的时候Velocity将创建一个该类的实例。同样,你需要为该名称的日志记录器配置其他的属性。请参见 Velocity helper class 和configuration keys and values. 来得到更详细信息。请注意,由于疏忽的原因,在1.2版本中,org.apache.velocity.runtime.log.LogSystem接口被修改了以支持分离的实例末拌。如果你有一个自定义的适用于1.2以前版本的日志记录器,你需要再添加一个init(RuntimeServices)方法。You can create a custom logging class - you simply must implement the interface org.apache.velocity.runtime.log.LogSystem and then simply set the configuration property runtime.log.logsystem.class with the classname, and Velocity will create an instance of that class at init time. You may specify the classname as you specify any other properties. See the information on the Velocity helper class as well as the configuration keys and values. Please note that through oversight, the interface to org.apache.velocity.runtime.log.LogSystem was changed in v1.2 to support the separable instances of the Velocity runtime. If you have an exisiting pre v1.2 custom logger that is going to be instantiated by the Velocity LogManager, you must add the init( RuntimeServices ) method.
- 整合日志系统Integrated Logging
你可以将Velocity日志系统整合进你现有应用已经在使用的日志系统中,只需要实现org.apache.velocity.runtime.log.LogSystem接口。然后,通过配置runtime.log.logsystem属性在Velocity引擎初始化之前传入一你现有的日志类,Velocity就会将日志信息记录到你的应用中的日志中了。请参见 Velocity helper class 和configuration keys and values. 来得到更详细信息。You can integrate Velocity's logging capabilities with your applications existing logging system, simply by implementing the org.apache.velocity.runtime.log.LogSystem interface. Then, pass an instance of your logging class to Velocity via the runtime.log.logsystem configuration key before initializing the Velocity engine, and Velocity will log messages to your applications logger. See the information on the Velocity helper class as well as the configuration keys and values.
使用现有的Log4jUsing Log4j With Existing Category
下面是一个演示怎样配置Velocity使其记录日志到一个存在的Log4j中。Here is an example of how to configure Velocity to log to an existing Log4j Category. 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中找到。Note that the above example can be found in examples/logger_example.
一个自定义日志记录器的例子Simple Example of a Custom Logger
下面是一个演示如何使用一个你自己的日志记录器来作日志的例子。注意我们并没有使用来类的名字,而是传递了一个该类的实例。要做到这点,需要继承LogSystem接口。Here is an example of how to use an instantiation of your class that implements Velocity's logging system as the logger. Note that we are not passing the name of the class to use, but rather a living, existing instantiation of the class to be used. All that is required is that it support the 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 )
{
}
/** * This is the method that you implement for Velocity to call * with log messages. */
public void logVelocityMessage(int level, String message)
{
/* do something useful */
}
...
}
Configuring Resource Loaders
资源加载器Resource Loaders
Velocity的一个重要的基础设施就是资源管理系统和资源加载器。他们指向的是资源,而不只是模版,因为资源管理系统不光能处理模版,也能处理非模版的资源,比如在模版中使用#incude()指示符加载的东西。One of the fundamental and important parts about Velocity is the resource management system and the resource loaders. They are referred to as 'resources' here rather than 'templates' because the resource management system will also handle non-template reasources, specifically things that are loaded via the #include() directive.
资源加载器系统是很灵活的,允许一个或者多个资源加载器同时工作,这允许在配置和资源管理上有很大的灵活性,并允许你为自己的需求编写自定义的资源加载器。The resource loader system if very flexible, allowing one or more resource loaders to be in operation at the same time. This allows tremendous flexibility in configuration and resource managment, and futher allows you to write your own resource loaders for your special needs.
目前,Velocity中有4种资源加载器,都在下面描述。注意,在给出的配置实例中,一个加载器的名字会出现(比如file.resource.loader.path中的"file"),这个名字在你的配置文件中可能不会起作用,请阅读resource configuration properties 小节来理解该系统是怎样工作的。同时,下面的这些加载器都是在org.apache.velocity.runtime.resource.loader包中。There are currently four kinds of resource loaders that are included with Velocity, each described below. Note that in the example configuration properties given, a common name for the loader is shown (ex.'file' in file.resource.loader.path). This 'common name' may not work for your configuration. Please read the section on resource configuration properties to understand how this system works. Also, each of these loaders is located in the package org.apache.velocity.runtime.resource.loader.
- FileResourceLoader : 该加载器从文件系统中加载资源。他的配置属性包括:This loader gets resources from the filesystem. It's configuration properties include :
- file.resource.loader.path = <path to root of templates>
- file.resource.loader.cache = true/false
- file.resource.loader.modificationCheckInterval = <seconds between checks>
这是默认的加载器,并且从当前文件夹加载资源(模版)。当Velocity使用于Servlet中时,这会成为一个问题,因为你一定不希望模版放在你servlet引擎的根目录下。请参见 developing servlets with Velocity 得到更多信息。This is the default loader, and is configured, by default to get templates from the 'current directory'. In the case of using Velocity with servlets, this can be a problem as you don't want to have to keep your templates in the directory from which you start your servlet engine. Please see the section on developing servlets with Velocity for more information.
- JarResourceLoader : 该资源加载器从一个指定的jar文件中加载资源。他的工作状态和FileResourceLoader非常相似,除非你认为将你的模版资源打包如jar文件中是很方便的。他们的配置属性也是一样的,除了jar.resource.loader.path。该属性确定了你把所有的需要加载的资源的jar文件都放入的绝对路径。要配置该属性,需要使用标准的java.net.JarURLConnection中的JAR URL语法。This loader gets resource from specific jar files. It is very similar to the FileResourceLoader, except that you have the convenience of bundling your templates into jars. The properties are identical, except for jar.resource.loader.path, where you provide the full location of the jar(s) you wish to load resources from. To specify a jar for the loader.path you use the standard JAR URL syntax of java.net.JarURLConnection.
- ClasspathResourceLoader : 该加载器从类路径中加载资源。简单的说,该加载器会加载放置在类路径中的模版资源(比如在某个jar中)。在使用符合Servlet2.2或之后的版本的容器时,这是一个比较简单的机制。Tomcat就是这样一种容器。要更有效的使用该加载器,你只需要把所有的模版资源打包为jar文件,并放入你web应用的web-inf文件夹中即可。没有任何的配置选项需要考虑,也没有了关于相对路径绝对路径的考虑。请再次注意,ClasspathResourceLoader不光适用于servlet应用中,也同样适用于其他任何的应用环境。This loader gets resources from the classloader. In general, this means that the ClasspathResourceLoader will load templates placed in the classpath (in jars, for example) While the classpath is a source of great pain and suffering in general, it is a very useful mechanism when working on a Servlet Spec 2.2 (or newer) compliant servlet runner. Tomcat is an example of such. To use this loader effectively, all you must do is jar your templates, and put that jar into the WEB-INF/lib directory of your webapp. There are no configuration options to worry about, nor is the absolute vs. relative path an issue, as it is with Jar and File resource loaders. Again, please note that the ClasspathResourceLoader is not only for use with a servlet container, but can be used in any application context.
- DataSourceResourceLoader : 在加载器会从一个DataSource中加载资源,比如一个数据库中。该加载器不是一个标准的加载器,因为使用它需要J2EE的支持。要构建该加载器,需要下载J2EE的分发包,把j2ee.jar放入build/lib文件夹中,并使用jar-j2ee构建任务来构建一个新的Velocity jar文件。要得到关于该加载器的更多的信息,请参见Javadoc中关于org.apache.velocity.resource.loader.DataSourceResourceLoader类的文档。This loader will load resources from a DataSource such as a database. This loader is not built as part of the standard build as it requires J2EE support. To build this loader, please download the J2EE distribution, move the j2ee.jar into the build/lib directory, and then build the new velocity jar with the jar-j2ee build target. For more information on this loader, please see the javadoc for the class org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader.
配置示例 Configuration Examples
为Velocity配置资源加载器是很直接的事,所有控制的属性都在 resource configuration 小节列出。Configuring the resource loaders for Velocity is straightforward. The properties that control the are listed in the resource configuration section, for further reference.
在Velocity中配置资源加载器的第一件事情就是声明他们的名字。使用resource.loader属性来列出一个或者多个配置器的名称。你可以使用任何你想要的名字------该名字用于接下来配置该加载器的属性。The first step in configuring one or more resource loaders is do 'declare' them by name to Velocity. Use the property resource.loader and list one or more loader names. You can use anything you want - these names are used to associate configuration properties with a given loader. resource.loader = file
该例子表明我们有了一个叫做"file"的资源加载器了,接下来的事情就是为该加载器配置重要的属性,其中最重要的就是申明该加载器的类型:That entry declares that we will have a resource loader known as 'file'. The next thing to do is to set the important properties. The most critical is to declare the class to use as the loader : file.resource.loader.class =
org.apache.velocity.runtime.resource.loader.FileResourceLoader
在这个例子中,我们为file加载器指定了类型------org.apache.velocity.runtime.resource.loader.FileResourceLoader 。下面继续配置其他的属性。In this case, we are telling velocity that we are setting up a resource loadercalled 'file', and are using the class org.apache.velocity.runtime.resource.loader.FileResourceLoaderto be the class to use. The next thing we do is set the properties important to this loader. file.resource.loader.path = /opt/templates
file.resource.loader.cache = true
file.resource.loader.modificationCheckInterval = 2
在这里,我们设置了一些值。首先,我们把模版加载的路径设为/opt/templates;接着,把缓存打开;最后,把模版变化检查间隔设置为2秒,让Velocity检查时候有新的模版。Here, we set a few things. First, we set the path to find the templates to be /opt/templates. Second, we turned caching on, so that after a template or static file is read in, it is cached in memory. And finally, we set the modification check interval to 2 seconds, allowing Velocity to check for new templates.
上面这些都是最基础的配置,下面会是一些特殊的配置了:Those are the basics. What follows are a few examples of different configuraitons.
默认的配置Do-nothing Default Configuration : 同名字一样,该配置除了加载默认的配置以外不做任何改变。该配置适用FileResourceLoader,将当前路径作为默认的资源路径,并关闭缓存。As the name says, there is nothing you have to do or configure to get the default configuration. This configuration uses the FileResourceLoader with the current directory as the default resource path, and caching is off. As a properties set, this is expressed as : 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 : 该配置适用了FileResourceLoader,并设置了多个资源加载路径,同样,开启了缓存,并将检查时间设置为10秒:This configuration uses the FileResourceLoader with several directories as 'nodes' on the template search path. We also want to use caching, and have the templates checked for changes in 10 second intervals. As a properties set, this is expressed as : 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 : 该配置同时设置了3个资源加载器------FileResourceLoader;ClasspathResourceLoader, and the和JarResourceLoader。在该配置中,FileResourceLoader会被首先使用,然后是ClasspathResourceLoader最后是JarResourceLoader。这允许你快速的把一个模版放入模版路径中,而不需要放入类路径中,也不需要重新打包为jar文件。This configuration sets up three loaders at the same time, the FileResourceLoader, the ClasspathResourceLoader, and the JarResourceLoader. The loaders are set-up such that the FileResourceLoader is consulted first, then the ClasspathResourceLoader, and finally the JarResourceLoader. This would allow you to qickly drop a template into the file template area to replace on of the templates found in the classpath (usually via a jar) without having to rebuild the jar. #
- 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,jar"这三个名字仅仅是为了方便,你可以取任何你想要的名字------他们只是把一组属性连接起来的名字。不过,我们也建议你使用能直接表示资源加载器类型的名字。Node that the three names 'file', 'class', and 'jar' are merely for your convenience and sanity. They can be anything you want - they are just used to associate a set of properties together. However, it is recommended that you use names that give some hint of the function.
最后注意,即便这三种加载器的配置都很简单,但是,ClasspathResourceLoader应该是最常用的。Note that while all three require very little configuration information for proper operation, the ClasspathResourceLoader is the simplest. 可插拔的资源管理器和资源缓存Pluggable Resource Manager and Resource Cache资源管理系统中,资源管理器应该是最重要的了。负责响应应用对模版的请求,用合适的资源加载器加载,并选择是否缓存被解析了的模版。资源缓存是资源管理器用来缓存模版并快速重用的机构。默认版本的这两个设施能满足绝大多数应用的需求了,更高级的用户现在也能使用自定义的资源管理器和资源缓存了。The Resource Manager is the main part of the resource (template and static content) management system, and is responsible for taking application requests for templates, finding them in the available resource loaders, and then optionally caching the parsed template. The Resource Cache is the mechanism that the Resource Manager uses to cache templates for quick reuse. While the default versions of these two facilities are suitable for most applications, for advanced users it now is possible to replace the default resource manager and resource cache with custom implementations.
要实现资源管理器需要实现org.apache.velocity.runtime.resource.ResourceManager 接口。要阐述如何实现一个资源管理器已经超出了本指南的范围了,建议要实现自己的资源管理器的开发者看看默认的资源管理器的实现。要让Velocity加载你自己的管理器,需要配置下面的属性:A resource manager implementation must implement the org.apache.velocity.runtime.resource.ResourceManager interface. A description of the requirements of a resource manager is out of scope for this document. Implementors are encouraged to review the default implementation. To configure Velocity to load the replacement implementation, use the configuration key : resource.manager.class
该关键字被定义为RuntimeConstants.RESOURCE_MANAGER_CLASS 。This key is also defined as a contstant RuntimeConstants.RESOURCE_MANAGER_CLASS
要实现资源缓存器需要实现org.apache.velocity.runtime.resource.ResourceCache接口。要阐述如何实现一个资源缓存器已经超出了本指南的范围了,建议要实现自己的资源缓存器的开发者看看默认的资源缓存器的实现。要让Velocity加载你自己的缓存器,需要配置下面的属性:A resource cache implementation must implement the org.apache.velocity.runtime.resource.ResourceCache interface As with the resource manager, a description of the requirements of a resource manager is out of scope for this document. Implementors are encouraged to review the default implementation. To configure Velocity to load the replacement implementation, use the configuration key : resource.manager.cache.class
该关键字被定义为:RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS 。This key is also defined as a contstant RuntimeConstants.RESOURCE_MANAGER_CACHE_CLASS
Template Encoding for Internationalization
在Velocity1.1种,允许你设置模版资源的编码格式了。设置编码格式的API如下:As of version 1.1, Velocity allows you to specify the character encoding of your template resources on a template by template basis. The normal resource API's have been extended to take the encoding as an argument :
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 )
作为参数传入的编码格式必须是你JVM支持的正规的编码。比如UTF-8或者ISO-8859-1。在here察看官方的字符集名称。The value for the encoding argument is the conventional encoding specification supported by your JVM, for example "UTF-8" or "ISO-8859-1". For the official names for character sets, see here.
注意,这里设置的只是模版本身的编码格式,输出的编码格式是应用的一个单独的设置。Note that this applies only to the encoding of the template itself - the output encoding is an application specific issue.
Velocity and XML Velocity灵活和简单的模版语言使他成为一个理想的和XML数据一起工作的环境。Anakia 是一个使用Velocity来代替XSL来为XML合成输出的例子。Velociyt官方网站和所有的文档,都是使用Anakia来从XML资源中合成的。Jakarta网站也是如此。Velocity's flexibility and simple template language makes it an ideal environment for working with XML data. Anakia is an example of how Velocity is used to replace XSL for rendering output from XML. The Velocity site, including this documentation, is generated from XML source using Anakia. The Jakarta site is also rendered using Anakia.
简单来说,Velocity处理XML的模式和使用JDOM处理XML到一个数据结构的模式比较相像。然后,你在XML文件之外定义你的模版来连接从XML中解析的数据。比如,下面是一个XML文档:Generally, the pattern for dealing with XML in Velocity is to use something like JDOM to process your XML into a data structure with convenient Java access. Then, you produce templates that access data directly out of the XML document - directly though the JDOM tree. For example, start with an XML document such as : <?xml version="1.0"?>
<document>
<properties>
<title>Developer's Guide</title>
<author email="geirm@apache.org">Velocity Documentation Team</author>
</properties>
</document>
然后创建一个Java程序:Now make a little Java program that includes code similar to: ...
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 );...
(请参见Anakia的代码来了解更多细节,或者察看Anakia的例子See the Anakia source for details on how to do this, or the Anakia example in the examples directory in the distribution.) 现在,编写一个简单的Velocity模版:Now, make a regular Velocity template : <html>
<body>
The document title is
$root.getChild("document").getChild("properties").getChild("title").getText()
</body>
</html>
然后使用上下文对象中的JDOM树合成模版。当然,这不是最完美的例子,但是他也展示了一些基础的东西------你能在Velocity模版中很容易的得到XML的数据。and render that template as you normally would, using the Context containing the JDOM tree. Of course, this isn't the prettiest of examples, but it shows the basics - that you can easily access XML data directly from a Velocity template.
一个真正的把XML数据纳入Velocity的优势在于,你同时也能访问应用提供的对象。你不仅仅限制于XML中的数据,你能向输出中添加任何你需要的东西,或者提供一些帮助处理XML数据的工具。Bob McWhirter的 Werken Xpath工具就是这样一个很有用的工具------一个该工具在Anakia中的使用的例子可以在org.apache.velocity.anakia.XPathTool中找到。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.
一起使用会出现一个问题,就是怎样处理XML标签。一个技巧是使用Velocity宏来把一个XML标签放入输出流中。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>
其中的escapeEntities()方法为你完成去除工作。另一种方法是创建一个编码工具,并使用上下文作为构造方法的参数或者实现一个方法。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() ) : "";
}
把该对象作为"xenc"并放入上下文中。然后象下面这样使用:Put it into the context as "xenc". Then you can use it as : <text>$xenc.sometext</text>
这使用了Velocity的自省的优势---他会尝试调用上下文中的$xenc对象的get("sometext")方法-----然后xenc对象会从上下文中得到值,并编码,返回。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.
此外,当Velocity使自定义上下文对象的使用变得很简单,你完全可以实现自己的总是能编码的上下文。小心,不能直接调用方法来合成输出,因为在这里面可能会有对象或者需要编码的String。将他们使用#set放入上下文中,并象这样使用: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