Velocity is often used to generate web pages in applications, usually as a direct replacement for JSP. Some of the benefits of using Velocity to generate web pages are:
This document provides some basic info on getting started with Velocity in a web application.
The primary purpose of the Velocity engine is simply to generate text based on a template. Consequently, Velocity does not contain any web-related functionality in and of itself. To make a web application, you will need a framework to respond to HTTP requests, handle user authentication, make business logic calls, and generate a response. There are several strong contenders.
As a side note, you may also come across references to VelocityServlet, which is a deprecated servlet that was included in the Velocity Engine up to version 1.4. Since VelocityServlet is no longer being maintained we strongly recommend you use VelocityViewServlet in Velocity Tools instead.
There are a few issues with Velocity that are specific to web applications. Here is a brief discussion of the most commonly encountered issues.
The default Velocity Engine settings make use of the FileResourceLoader. This is great for most applications that are not deployed to a servlet engine. Once you need to build a web application and ship or deploy it as a WAR file, the FileResourceLoader can become your worst enemy. So, we explicitly recommend you do NOT use the FileResourceLoader for your web applications.
Really, any of the other ResourceLoader implementations out there are preferred, but all the other ResourceLoaders shipped with Velocity Engine will require you to store your templates somewhere besides the standard file system (e.g. in the classpath, in a database, or on a remote server). If that works for you, then great! However, we recognize that these are not convenient for most people's development cycle.
The simplest replacement for FileResourceLoader in a web application is actually a part of the VelocityTools project. It is the WebappLoader . This ResourceLoader implementation is specifically designed to work just like the FileResourceLoader, but it is aware of the servlet context and allows you to configure resource paths relative to the servlet root, rather than the local file system.
If you are using the VelocityViewServlet, then it is automatically configured and ready to use the WebappLoader. So if you want to change the configured path(s), you need only add a line like the following to your velocity.properties:
webapp.resource.loader.path=/WEB-INF/mytemplates/
If you need to set the WebappLoader up on your own, then you can make your properties something like this:
resource.loader=webapp webapp.resource.loader.class=org.apache.velocity.tools.view.servlet.WebappLoader webapp.resource.loader.path=/WEB-INF/mytemplates/
You will also need to put the ServletContext into your VelocityEngine's application attributes before initializing that Engine. This is how the WebappLoader knows how to find templates.
myVelocityEngine.setApplicationAttribute("javax.servlet.ServletContext", servletContext);
Velocity provides the ability to call any method of an object acting as a reference. This can be useful when displaying information into the page but is dangerous when object or application state is modified.
For example, the following code safely calls the size() method of a list and displays the result.
There are $users.size() currently logged in.
An example of an unsafe operation concerns a financial web page with an object in the context that calculates data year by year. The method calculateNextYear() calculates data for the next year and advances an internal counter:
2005 data: $table.data $table.calculateNextYear() 2006 data: $table.data
The problem with this approach is that the code cannot be repeated in multiple parts of the page. You may not intend to do so, but it's easy to forget this when cutting and pasting or writing control statements (such as #if or #foreach). This becomes more of an issue when you are dealing with application or session-level state.
The (strongly) recommended practice is to only use Velocity for inserting information into text. Method calls can be useful to retrieve information. However, it's generally a bad idea to use a method call to change object state, and it's always a bad idea to change application state.
If you find yourself needing to change object state (as in the previous example) try precalculating all the possible values in the controller and putting them in a List or Map. Any changes to application state should always be done by the controller.
On a related note, you should always put a List or Set into the context instead of an Iterator or Enumeration. This allows the collection to be used more than once in the page with no change in behavior.
Any user-entered text that contains special HTML or XML entities (such as <, >, or &) needs to be escaped before included in the web page. This is required, both to ensure the text is visible, and also to prevent dangerous cross-site scripting . Unlike, for example, JSTL (the Java Standard Tag Language found in Java Server Pages), Velocity does not escape references by default.
However, Velocity provides the ability to specify a ReferenceInsertionEventHandler
which will alter the value of a reference before it is inserted into the page.
Specifically, you can configure the EscapeHtmlReference
handler into your velocity.properties
file to escape all
references (optionally) matching a regular expression.
The following example will escape HTML entities in any reference that starts with
"msg" (e.g. $msgText
).
eventhandler.referenceinsertion.class = org.apache.velocity.app.event.implement.EscapeHtmlReference eventhandler.escape.html.match = /msg.*/
Note that other kinds of escaping are sometimes required. For example, in style sheets the @ character needs to be escaped, and in Javascript strings the single apostrophe ' needs to be escaped.
Since a web application is running on a central server, that typically has multiple users and confidential resources,
care must be taken to make certain that the web application is secure. Most standard web security principles apply to a
web application built with Velocity. A few specific issues (such as system configuration, more on cross-site scripting,
and method introspection) are written up in this article on
Building Secure Applications with Velocity
.
In particular, you may want to prevent template designers from including "dangerous" reflection-related methods
by specifying the SecureUberspector
to get/set properties and execute method calls.
runtime.introspector.uberspect = org.apache.velocity.util.introspection.SecureUberspector
A minor point is that (in some circumstances) Velocity, in the absence of any log-related configuration, creates a log file in the current directory. When Velocity is used in a web application the "current directory" is usually the current directory from which the application server is started. If you start seeing the file "velocity.log" files in random places on your server filesystem, check the Velocity log configuration. This is due to the default use of the Avalon Log Kit when present in the classpath. Typically this occurs when Velocity is used within a web application outside of web page generation (e.g. for sending email). To solve this problem, remove any file labeled "avalon-logkit" from the classpath or properly configure the log file location.
What follows is a brief tutorial on building a simple web app with VelocityViewServlet. Note that it suggests you compile VelocityViewServlet from the source. This isn't actually required to use VelocityViewServlet but we recommend it in this case in order to see the source and then compile the example files.
Prerequisites for doing the following include the Java Developer's Kit (JDK) and Apache Ant .
For more information, consult the Velocity Tools documentation.
ant example.simple
<html> <body> I'm a velocity template. #if( $XHTML ) #set( $br = "<br />" ) #else #set( $br = "<br>" ) #end $br $br Here we use a custom tool: $toytool.message $br $br Here we get the date from the DateTool: $date.medium </body> </html>
<toolbox> <xhtml>true</xhtml> <tool> <key>toytool</key> <class>ToyTool</class> </tool> <data type="number"> <key>version</key> <value>1.1</value> </data> <data type="boolean"> <key>isSimple</key> <value>true</value> </data> <data type="string"> <key>foo</key> <value>this is foo.</value> </data> <data type="string"> <key>bar</key> <value>this is bar.</value> </data> <tool> <key>map</key> <class>java.util.HashMap</class> </tool> <tool> <key>date</key> <scope>application</scope> <class>org.apache.velocity.tools.generic.DateTool</class> </tool> </toolbox>
<web-app> <servlet> <servlet-name>velocity</servlet-name> <servlet-class> org.apache.velocity.tools.view.servlet.VelocityViewServlet </servlet-class> <init-param> <param-name>org.apache.velocity.toolbox</param-name> <param-value>/WEB-INF/toolbox.xml</param-value> </init-param> <load-on-startup>10</load-on-startup> </servlet> <servlet-mapping> <servlet-name>velocity</servlet-name> <url-pattern>*.vm</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.vm</welcome-file> </welcome-file-list> </web-app>
http://localhost:8080/simple/index.vm