You need to reuse portions of a template to standardize the display of common elements such as an address or a name.
Use Velocity Macro definitions to reuse logic to print out
both names and addresses. Velocity macros are like subroutines
that take a set of parameters and perform common tasks. In the following
Velocity template, two macros, #name
and #address, handle the printing of
names and addresses:
#set( $volunteer = $appointment.volunteer )
#set( $location = $appointment.location )
#set( $org = $appointment.organization )
## Define the "name" macro
#macro( name $object )$!object.firstName $!object.lastName#end
## Define the "address" macro
#macro( address $object )
$!object.address.street1
$!object.address.street2
$!object.address.city, $!object.address.state $!object.address.zipcode
#end
#name( $volunteer ),
Thank you for volunteering to help serve food at the $location.name next
week. This email is a reminder that you are scheduled to help out from
$appointment.startTime to $appointment.endTime on $appointment.date.
The address of the shelter is:
#address( $location )
If you need directions to the shelter click the following URL:
${org.baseUrl}directions?location=org.codehaus.cjcook:cjcook-content:jar:0.19
Also, if you are unable to help out on $appointment.date, please let us know by
sending an email to ${org.email} or by filling out the form at this URL:
${org.baseUrl}planschange?appointment=org.codehaus.cjcook:cjcook-content:jar:0.19
Thanks again,
#name( $org.president )
#address( $org )In the following code, the template shown previously is loaded
from a classpath resource organize.vm, and an Appointment object is placed in a VelocityContext:
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
// Create and initialize a VelocityEngine setting a configuration property
VelocityEngine vEngine = new VelocityEngine( );
vEnging.setProperty( RuntimeConstants.VM_CONTEXT_LOCALSCOPE, Boolean.TRUE );
vEngine.init( );
// Create a test Appointment
Appointment appointment = testAppointment( );
// Create a Velocity Context and give it the appointment
VelocityContext context = new VelocityContext( );
context.put("appointment", appointment);
// Prepare a StringWriter that will hold the contents of
// our template merge
StringWriter writer = new StringWriter( );
// Get a stream to read in our velocity template. The
// organize.vm file is loaded from the classpath and is stored
// in the same package as the current class.
InputStream templateStream = getClass( ).getResourceAsStream("organize.vm");
Reader reader = new InputStreamReader( templateStream );
// Evaluate the template
vEngine.evaluate(context, writer, "test", reader);
// Print out the results of the template evaluation
System.out.println( "organize: " + writer.toString( ) );The template is merged with a VelocityContext, and the following output is
produced:
John S.,
Thank you for volunteering to help serve food at the Boston Homeless
Veterans Shelter next week. This email is a reminder that you are
scheduled to help out from 9:00 AM to 2:00 PM on Monday, September
12, 2003. The address of the shelter is:
17 Court Street
Boston, MA 01260
If you need directions to the shelter click the following URL:
http://www.organize.com/directions?location=2342
Also, if you are unable to help out on September 12th, please let us
know by sending an email to organize@helpout.com
or by filling out the form at this URL:
http://www.organize.com/planschange?appointment=29932422
Thanks again,
Brishen R.
201 N. 2nd Street
Jersey City, NJ 20213A macro definition is started with the #macro directive and ended with #end; the same macro is invoked by calling
#<macro_name>( <parameters>
). Velocity macros must be defined before they are referenced,
using the following syntax:
#macro(<name> <arguments>)
<Macro Body>
#endMacro parameters are not typed as are method parameters in Java; there is no
mechanism to check that an Address
object is passed to the #address
macro, throwing an exception if an inappropriate object is encountered.
To successfully render this Velocity template, verify that an Address is sent to the #address macro and a Person is sent to the #name macro.
In the previous example, an instance of VelocityEngine is created and the RuntimeConstants.VM_CONTEXT_LOCALSCOPE
property is set to true. This
property corresponds to the velocimacro.context.localscope, which controls
the scope of references created by #set directives within macros. When this
configuration property is set to true, references created in the body of a
macro are local to that macro.
The Velocity template in the Solution expects a single reference
$appointment to an Appointment bean. Each Appointment has a volunteer property of type Person, and every Organization has a president property of type Person. These Person objects, ${appointment.volunteer} and ${appointment.organization.president}, are
passed to the #name macro that prints out the first and last name. Two
Address objects, ${appointment.location.address} and ${appointment.organization.address}, are
passed to the #address macro that
prints a standard U.S. mailing address.
A macro can contain any directive used in Velocity; the following
macro uses nested directives to print out a list of numbers in HTML.
#numberList allows you to specify a
range with $low and $high; values in $numbers within this range will be printed
bold:
#macro( numberList $numbers $low $high )
<ul>
#foreach( $number in $numbers )
#if( ($number > $low) && ($number < $high) )
<li><b>$number</b> - In Range!</li>
#else
<li>$number</li> - Out of Range!</li>
#end
#end
</ul>
#endThe macro defined above would be called by the following Velocity
template. Note the presence of comments, which are preceded by two
hashes (##):
#set( $squares = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] )
## Print out a list of numbers highlighting numbers
## between 25 and 75
#numberList( $squares, 25, 75 )
If your system has a large number of Velocity templates, you can
create a set of files to hold common macros, which will be made
available to every Velocity template using the velocimacro.library property. For more
information, see the Velocity User Guide (http://velocity.apache.org/engine/releases/velocity-1.6.1/user-guide.html#Velocimacros).
