Velocity: Fast Track to Templating
Velocity is a fast and easy-to-use Java-based templating engine. Velocity's speed, ease of use, and flexibility contribute to its use in a broad range of applications, including code generation, email templating, and web user-interface creation. A template is a parameterized, predesigned text format. A template engine processes a template and fills in the parameterized pieces with concrete data. The bulk of this article focuses on email templating with Velocity. The template, in this context, is an email body with special syntax used to indicate points within the email to insert specific data, such as a name, order number, or order details. This article first introduces Velocity with a simple, easy-to-run example, then briefly covers the templating syntax, and ends with a full-featured and detailed look at Velocity in action for templating automated emails.
Owner's Manual
Before we delve into the details of Velocity's inner workings and syntax, let's get a straightforward example working to make sure that all of the pieces are in place and we have a framework in which to experiment.
Follow these four steps:
Download Velocity's binary distribution (version 1.3.1 was used for this article).
Save StartYourEngines.java (see the listing below) to your local file system.
From the command line, compile:
javac -classpath <path to velocity -dep JAR> StartYourEngines.javaVelocity ships with two JAR files, one with
-depin its name. The-depJAR file includes all third-party dependencies needed to run Velocity, such as several of the Jakarta Commons APIs. The velocity-dep-1.3.1.jar file is used for all code in this article.Now run it:
java -classpath <path to velocity -dep JAR>:. StartYourEngines uno dos tresYou should see this output:
args = uno dos tres
You can see in this code listing that the StartYourEngines program places the command-line arguments
array into a Velocity context. The template is
an embedded string that iterates over each item in the array
and outputs it. In the next section we will define Velocity's terminology.
StartYourEngines.java
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import java.io.StringWriter;
public class StartYourEngines {
public static void main(String[] args) throws Exception {
VelocityContext context = new VelocityContext();
context.put("args", args);
String template = "args = #foreach ($arg in $args) $arg #end";
StringWriter writer = new StringWriter();
Velocity.init();
Velocity.evaluate(context,
writer,
"LOG", // used for logging
template);
System.out.println(writer.getBuffer());
}
}
Under the Hood
There are two key concepts to understand with Velocity: the context and the template. The following diagram illustrates these concepts, along with the merging of a context and a template to generate output.
The data placed in the Velocity context is accessible to the
template. For example, processing a template containing Dear ${person.firstName} would replace ${person.firstName} with the value of the firstName property of the object named person.

Fill 'Er Up: The Context
Velocity's context is a container of Java objects, each
with a unique name to reference it from a template. There are
no restrictions on what types of objects can be placed in a context.
Collections, arrays, and maps are all easily dealt with by
Velocity; the args object in the StartYourEngines demo is an
example of placing an array in the context. JavaBeans and collections of JavaBeans
are the most common object types used to push data into a template.
Following the Roadmap: The Template
A Velocity template is text that serves as a model for output. Templates contain a combination of references to context data, Velocity Template Language (VTL) directives, and static text. Static text is passed through, as is, into the generated output. References and VTL are processed by the Velocity engine.
The StartYourEngines demo template uses a combination of static
text (args =), VTL (#foreach and #end),
and references ($arg and $args).
The following two sections cover references and VTL in greater detail.
References
Objects in the Velocity context are accessed using references
from within a template. References begin with a dollar sign. The name
following the dollar sign refers to a name of an object within the
context. Since you may want to nestle a reference with static text
following it, formal notation (surrounding
the complete reference with curly brackets) may be
used to keep things clear and unambiguous. For example,
to put the fields name and number together, separated by a dash,
${name}-${number} is used, with curly brackets around
the references. Had the brackets not been used, $name would not
be expanded, as the processing would look for a context object
named name-.
If a context object does not exist for a named reference, the
reference itself ($whatever) is left as is in the output, unless
quiet reference notation is used. References with an exclamation point
after the dollar sign, such as $!name and $!{name},
are replaced with an empty string when the reference does not
exist within the context.
So far, we've seen simplistic references that refer directly to objects in the context. These are called variable references. There are two types of references. Nested properties of context objects are referenced using property references. Method references invoke methods on objects within the context.
Property References
A dotted syntax is used to access properties of context objects.
The expression ${person.name} will output the name
property of the context object named person. The person object
could be a simple JavaBean such as this, and the getName()
method will be called:
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Or person could be a java.util.Map with
an entry named name. The following test case illustrates
a Map being used identically to a JavaBean in a template.
public void testMap() throws Exception {
Map person = new HashMap();
person.put("name", "Duke");
context.put("person", person);
Velocity.evaluate(context, writer, "TEST", "${person.name}");
assertEquals("Duke", writer.getBuffer().toString());
}
Method References
Velocity is a Pull-MVC framework, referring to the templates' capability of pulling information that was not explicitly pushed into the context. Variable and property references are using a push model. The pull action comes from method references. Methods on the context objects are called in the same manner that they are in Java, using a parenthetical expression with any required arguments. Method calls are primarily used for data formatting, although they can certainly be leveraged for other purposes, such as computations.
It is common to see utility objects with useful formatting
or computation methods placed into the context. This is such a
common practice that these objects are known as tools.
The Velocity distribution ships with VelocityFormatter,
a class with some date, array, and other formatting methods. The
testFormatter test demonstrates using this tool and
its formatShortDate method. Note that a property reference is
used as a parameter to formatShortDate, which requires a java.util.Date
argument. Formatting tools allow developers to put
rich objects into the context and defer formatting decisions to the
template writers, where it belongs.
public void testFormatter() throws Exception {
Date today = new Date();
context.put("formatter", new VelocityFormatter(context));
context.put("today", today);
Velocity.evaluate(context, writer, "TEST", "today is $formatter.formatShortDate($today)");
DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
String expected = "today is " + format.format(today);
assertEquals(expected, writer.getBuffer().toString());
}
Velocity Template Language
In the initial example, the #foreach directive
was used to iterate over an array. There are only a handful
of other built-in directives that compose the Velocity Template Language
(VTL). All of these directives are listed in the following
table.
| Directive | Syntax | Purpose |
|---|---|---|
#foreach |
|
Iterates over a collection, array, or map. |
#if / #else / #elseif |
|
Conditional. Null can be checked for using
#if ($obj) obj not null #end syntax.
|
#parse |
#parse("header.vm") |
Loads, parses, and incorporates the specified template into the generated output. |
#macro |
|
Defines a new directive and any required parameters.
The result is interpreted when used later in the template.
The example macro would be used
as #currency($item.cost). |
#include |
|
Includes the specified file, as is, into the generated output. |
#set |
|
Assigns a value to a context object. If the context object does not exist, it is added; otherwise, it is replaced. |
#stop |
|
Stops template processing. This is usually used for debugging purposes. |
This is the entire set of built-in directives. New directives
may be defined using #macro. Velocity's User Guide does a great job of giving detailed information
on VTL -- please refer to it for more explanation and usage examples.
Shifting Into Overdrive: Email Templating Example
It is almost guaranteed that the systems you work on need to send automated emails to the users, either as receipts for online purchases or for system-event notifications. These emails are very likely dynamic, such as the case of an email receipt listing the items purchased, their costs, and an order number. There are many technical solutions to this problem, including using JSP or tokenized regular-expression substitutions. Velocity, of course, is the recommended solution here, as it provides all of the needed flexibility and a straightforward template language allowing even your end users customization capabilities.
This example is going to pull out all of the stops illustrating the majority of Velocity's capabilities. Our user story is this:
Implement a Java method that accepts an Order
and sends a receipt email to the customer. The email format
must allow easy runtime customization.
From a top-down approach, our method interface is:
public void sendReceipt(Order order) throws Exception
An Order is a Java object encapsulating a
Customer, order line items (a collection of Items),
order number generation, and a method to compute the order total.
import java.util.List;
import java.util.Iterator;
import java.util.Date;
public class Order {
private Customer customer;
private List lineItems;
private String orderNumber;
public Order (Customer customer, List lineItems) {
this.customer = customer;
this.lineItems = lineItems;
// for example purposes, "generate" a simple order number.
orderNumber = customer.getId() + "-" + new Date().getTime();
}
public Customer getCustomer() {
return customer;
}
public List getLineItems() {
return lineItems;
}
public String getOrderNumber() {
return orderNumber;
}
public float total() {
float total = 0;
for (Iterator iterator = lineItems.iterator(); iterator.hasNext();) {
Item item = (Item) iterator.next();
total += item.getCost();
}
return total;
}
}
Customer and Item are fairly typical
JavaBeans, shown below.
public class Customer {
private String firstName;
private String lastName;
private String email;
public Customer (String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
/**
* For demonstration purposes, an id is a concatenation of
* first and last initials
*/
public String getId() {
return "" + firstName.charAt(0) + lastName.charAt(0);
}
}
public class Item {
private String description;
private float cost;
public Item(String description, float cost) {
this.description = description;
this.cost = cost;
}
public String getDescription() {
return description;
}
public float getCost() {
return cost;
}
}
Now that we've got the underlying details out of the way, the
Emailer class usage becomes:
/**
* Example usage of Emailer functionality
*/
public static void main(String[] args) throws Exception {
Emailer emailer = new Emailer();
ArrayList lineItems = new ArrayList();
lineItems.add(new Item("Java Development with Ant", 44.95f));
lineItems.add(new Item("Lucene in Action", 41.37f));
Customer customer = new Customer("Duke", "Jahvah", "duke@java.net");
emailer.sendReceipt(new Order(customer, lineItems));
}
Still no view of Velocity -- this is an intentional design
decision, to keep things decoupled and cohesive. The Emailer
class itself fully encapsulates the use of the Velocity API.
Velocity is transparent to developers using Emailer, except for the need
to create a corresponding template. Before we proceed deeper
into the code, we need to first analyze the end goal, an actual
email. Here is an example email:
Duke,
Thank you for your purchase.
Your order number is DJ-1070292605890.
Description Cost
Java Development with Ant $44.95
Lucene in Action $41.37
Total $86.32
Visit us again at http://java.net!
Seeing an actual email body gives us some insight into some implementation details. First, note some formatting concerns. The description is output in a fixed-width style. Cost and total are formatted as currency. If our system is designed to service multiple stores, store information such as the URL in the last line perhaps should be provided dynamically into the context rather than being fixed text in the template. One final foreshadowing of the issues to address: what about the subject of the email? Shouldn't this be customizable using the same type of templating?
Continuing the outside-in zoom into Emailer, we see the Emailer
constructor and the sendReceipt method.
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import java.util.ArrayList;
import java.util.Properties;
import java.util.HashMap;
import java.io.StringWriter;
public class Emailer {
VelocityEngine engine = new VelocityEngine();
public Emailer() throws Exception {
configure(engine);
}
/**
* "Sends" (actually writes to System.out for demonstration
* purposes) a receipt e-mail for the specified order.
*/
public void sendReceipt(Order order) throws Exception {
Template template = engine.getTemplate("email.vm");
VelocityContext context = createContext();
context.put("order", order);
StringWriter writer = new StringWriter();
template.merge(context, writer);
writer.close();
System.out.println("To: " + order.getCustomer().getEmail());
System.out.println("Subject: " + context.get("subject"));
System.out.println(writer.getBuffer());
}
// ...configure and createContext coming soon...
}
A few new tricks are introduced here. First, VelocityEngine
is used, rather than the singleton Velocity seen in the
earlier examples. VelocityEngine is an instance-based way to
invoke the templating merge, keeping configuration separate from
other instances, whereas the singleton does not. The template is
external to our code (more on this later). Also of note is
the call to context.get("subject"). The context is
not a one-way "push," thus allowing the template to inject items back
into it. In this case, our template pushes an email "subject" string
into the context and the sendReceipt method retrieves it. It is
handy to keep the subject and body of an email close together,
and placing them both in the same template allows for customization
of both the subject and body in one spot.
Configuration of Resource Loaders
The trickiest thing when working with Velocity is configuration.
Several configuration options are available with Velocity. For the
Emailer example, Velocity needs to know how to find the template.
Velocity has a resource loader abstraction with built-in
loaders to retrieve templates from the file system, the classpath,
or a data source. Custom resource loaders could be written to
retrieve templates in a way custom to your architecture if needed.
Our email.vm (.vm for Velocity macro) template is not hardcoded
into our source code. Rather, it lives as a file on the classpath.
Velocity can be configured either through the API, or through
a velocity.properties file. I prefer controlling it through the
API to avoid the issue of where to put the velocity.properties file.
Most of Velocity's documentation, however, will show configuration
using the properties-file syntax. Configuring through the API
is a simple translation; here is the properties file equivalent
of the configure method:
resource.loader=classpath
classpath.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
Using some provided constants, the same configuration is
achieved using the API. The term classpath in the configuration
examples is an arbitrary name used to tie the classname (and potentially
other configuration) to a specific loader.
/**
* Configures the engine to use classpath to find templates
*/
private void configure(VelocityEngine engine) throws Exception {
Properties props = new Properties();
props.setProperty(VelocityEngine.RESOURCE_LOADER, "classpath");
props.setProperty("classpath." + VelocityEngine.RESOURCE_LOADER + ".class",
ClasspathResourceLoader.class.getName());
engine.init(props);
}
Refer to the Velocity Developer's Guide for more details on configuring resource loaders and other parameters.
Emailer Context
To put the final touches on our Emailer class, our context
is created with more than just the Order object. In order to
give our template control over formatting (rather than forcing our
Java code to deal with it less flexibly), a formatter tool is
placed in the context. General store information is injected
into the context as a Map.
/**
* Creates a Velocity context and adds a formatter tool
* and store information.
*/
private VelocityContext createContext() {
VelocityContext context = new VelocityContext();
context.put("formatter", new Formatter());
HashMap store = new HashMap();
store.put("name", "java.net Bookstore");
store.put("url", "http://java.net");
context.put("store", store);
return context;
}
Formatter is the final Java code to show before
we get to the template. Two formatting functions are needed: padding
or truncating a string to fixed width, and converting a float
amount into a pleasant, locale-dependent currency display.
import java.text.Format;
import java.text.NumberFormat;
public class Formatter {
public String currency(float amount) {
Format formatter = NumberFormat.getCurrencyInstance();
return formatter.format(new Float(amount));
}
public String pad(String string, int width) {
if (string.length() >= width) {
return string.substring(0, width);
}
StringBuffer output = new StringBuffer(string);
for (int i=0; i < (width - string.length()); i++) {
output.append(' ');
}
return output.toString();
}
}
Nearing the Finish Line: The Email Template
Even though we're on our last lap, keep your seat belts
fastened. The email.vm template utilizes several VTL directives,
including the cool #macro. A detailed
analysis of the template follows.
1. #set ($customer = ${order.customer})
2. #macro(currency $amount)${formatter.currency($amount)}#end
3. #macro(pad $string)${formatter.pad($string, 30)}#end
4. #macro(description $item)#pad($item.description)#end
5.
6. ${customer.firstName},
7.
8. Thank you for your purchase.
9. Your order number is ${order.orderNumber}.
10.
11. #pad("Description") Cost
12. #foreach ($item in ${order.lineItems})
13. #description($item) #currency(${item.cost})
14.
15. #end
16.
17. #pad("Total") #currency($order.total())
18.
19.
20. Visit us again at ${store.url}!
21.
22. #set ($subject="${store.name} receipt")
The line numbers on the left are not part of the original
template, but rather for discussion purposes. Lines 6 through 20
make up the email body. The only objects in the
Velocity context are order, store, and formatter.
Line 6 refers to customer.firstName. The customer object
was created on Line 1 using #set. It is merely there
for convenience, simplifying access to the customer object that
is nested within the order object. First name could also be
displayed using ${order.customer.firstName}.
Column headings are generated on Line 11. To keep things
aligned, the #pad macro is defined on Line 3, wrapping
the Formatter.pad method invocation. This keeps
the width in one place within the template. The item descriptions
are also padded, but they go through a #description
wrapper around #pad that is Item aware. Alternatively,
#pad could have been used on Line 13, like #pad($item.description).
Currency is formatted on both Lines 13 and 17. On Line 17,
the Order.total() method is invoked.
The URL to the store, rather than being fixed in the template,
comes from the store context object. This context object is
a Map that contains a url-named entry. Pleasantly, the template
deals with object properties and map entries identically, so it is
possible to switch the underlying implementation of the context object
without affecting the template.
And finally, Line 22 performs the trick previously mentioned,
injecting a subject object into the context, which is retrieved
after the merge in Emailer.sendReceipt.
White space is always an issue with templating engines. Velocity
does some intelligent things to collapse white space, but
experience shows that experimentation is needed to tweak a template
into generating the exact desired output.
The #macro and #set directives on Lines 1-4 and 22 do not directly cause any output during the merge. Notice that the #macro definitions are completely collapsed to avoid them generating
undesirable spaces when used later in the template.
The blank Line 14 is needed to put each item on a separate line.
Lane Ends, Merge Right
This has been a speedy look at Velocity, yet all of the major pieces have been covered. Adding Velocity to your technical toolkit is highly recommended. A general-purpose templating engine comes in handy in many aspects of development, and Velocity is the best one for the Java language. This look at Velocity covered one primary use, generating automated emails; there are many other uses, which can be extrapolated from the examples provided here. For example, generating HTML output from a web application using Velocity merely involves morphing the code shown in Emailer into a servlet (but refer to Resources before doing so, as several such implementations are already available). More details on Velocity's syntax, API, and configuration were intentionally omitted from this article, since these are covered in Velocity's excellent provided documentation.
Resources
Indispensable companions to this article are Velocity's User's Guide, Developer's Guide, VTL Reference Guide, and API Reference.
Many useful tools and wrapper frameworks, including tight integration with Struts, are included in the VelocityTools. Many Struts developers are replacing the typical JSP view with Velocity templates.
Velocity is used as a first-class templating solution in the code-generation tools Middlegen and XDoclet2. Megg uses Velocity templates to generate complete starter Java project infrastructures.
VPP provides a powerful templating solution during your build process, to generate, for example, environment-specific configuration files. The VPPFilter handily beats the clunkier
<filterset>token replacements to which you may be accustomed.Mastering Apache Velocity (Wiley)
- Login or register to post comments
- Printer-friendly version
- 16234 reads



