Apache Velocity Tutorial

1. Overview

Velocity is a Java-based templating engine. It's an open-source web framework designed to be used as a view component in the MVC architecture, and it provides an alternative to some existing technologies such as JSP.
Velocity can be used to generate XML files, SQL, PostScript, and most other text-based formats. In this article, we will explore how it can be used to create dynamic web pages.

2. How Velocity Works with an Example

Follow the below steps to configure and use the velocity template in an application:
  1. Initialize the Velocity engine
  2. Read the template
  3. Put the data model in a context object
  4. Merge the template with context data and render the view

3. Example - Generate Java Code using Apache Velocity Template

3.1 Create a Velocity Template - class.vm

  1. Create a vtemplates folder under /resources directory.
  2. Create a template called class.vm file under vtemplates folder add the following code to it:
package ${packagename};

public ${className} implements Serializable {

 /** Serial Version UID. */
 private static final long serialVersionUID = 1L;

#foreach( $property in $properties )
 private $property.fieldType $property.fieldName;
#end 
 
#foreach( $property in $properties )
 public ${property.fieldType} get${property.getGetterAndSetterField()}() {
     return this.${property.fieldName};
 }
 
 public void set${property.getGetterAndSetterField()}(${property.fieldType} ${property.fieldName}) {
     this.${property.fieldName} = ${property.fieldName};
 } 
#end
}

3.2 Create a Velocity Template Writer

Let's first create Field POJO class:

package net.guides.codegenerator.beans;

public class Field {
    private String fieldName;
    private String fieldType;


    public Field(String fieldName, String fieldType) {
        super();
        this.fieldName = fieldName;
        this.fieldType = fieldType;
    }

    public String getFieldName() {
        return fieldName;
    }
    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
    public String getFieldType() {
        return fieldType;
    }
    public void setFieldType(String fieldType) {
        this.fieldType = fieldType;
    }
}

Follow the below steps to configure and use the velocity template in an application:
  1. Initialize the Velocity engine
  2. Read the template
  3. Put the data model in a context object
  4. Merge the template with context data and render the view
package net.guides.codegenerator.util;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

import net.guides.codegenerator.beans.Field;

public class VelocityWriter {
 
    static String modelName = "User";
    static String packageName = "com.companyname.projectname";
 
    public static void main(String[] args) {
        VelocityEngine velocityEngine = new VelocityEngine();
        velocityEngine.init();
      
        Template t = velocityEngine.getTemplate("vtemplates/class.vm");
       
        VelocityContext context = new VelocityContext();
  
        if(packageName != null) {
            context.put("packagename", packageName);
        }
  
        List<Field> properties = new ArrayList<>();
        properties.add(new Field("id", "int"));
        properties.add(new Field("firstName", "String"));
        properties.add(new Field("lastName", "String"));
        properties.add(new Field("dob", "LocalDate"));
        context.put("className", modelName);
        context.put("properties", properties);
  
        StringWriter writer = new StringWriter();
        t.merge( context, writer );
  
        System.out.println(writer.toString());
    }
}

3.3 Output

Let's run above class will output:
19:26:28.268 [main] DEBUG org.apache.velocity - CommonsLogLogChute name is 'org.apache.velocity'
19:26:28.271 [main] DEBUG org.apache.velocity - Initializing Velocity, Calling init()...
19:26:28.271 [main] DEBUG org.apache.velocity - Starting Apache Velocity v1.7 (compiled: 2010-11-19 12:14:37)
19:26:28.271 [main] DEBUG org.apache.velocity - Default Properties File: org\apache\velocity\runtime\defaults\velocity.properties
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.AvalonLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Target log system for org.apache.velocity.runtime.log.AvalonLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log/format/Formatter).  Falling back to next log system...
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.Log4JLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Target log system for org.apache.velocity.runtime.log.Log4JLogChute is not available (java.lang.NoClassDefFoundError: org/apache/log4j/Layout).  Falling back to next log system...
19:26:28.271 [main] DEBUG org.apache.velocity - Trying to use logger class org.apache.velocity.runtime.log.CommonsLogLogChute
19:26:28.271 [main] DEBUG org.apache.velocity - Using logger class org.apache.velocity.runtime.log.CommonsLogLogChute
19:26:28.276 [main] DEBUG org.apache.velocity - ResourceLoader instantiated: org.apache.velocity.runtime.resource.loader.FileResourceLoader
19:26:28.276 [main] DEBUG org.apache.velocity - Do unicode file recognition:  false
19:26:28.276 [main] DEBUG org.apache.velocity - FileResourceLoader : adding path '.'
19:26:28.285 [main] DEBUG org.apache.velocity - ResourceCache: initialized (class org.apache.velocity.runtime.resource.ResourceCacheImpl) with class java.util.Collections$SynchronizedMap cache map.
19:26:28.286 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Stop
19:26:28.287 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Define
19:26:28.287 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Break
19:26:28.288 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Evaluate
19:26:28.289 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Literal
19:26:28.289 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Macro
19:26:28.290 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Parse
19:26:28.291 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Include
19:26:28.292 [main] DEBUG org.apache.velocity - Loaded System Directive: org.apache.velocity.runtime.directive.Foreach
19:26:28.316 [main] DEBUG org.apache.velocity - Created '20' parsers.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : "velocimacro.library" is not set.  Trying default library: VM_global_library.vm
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : Default library not found.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInline = true : VMs can be defined inline in templates
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInlineToOverride = false : VMs defined inline may NOT replace previous VM definitions
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : allowInlineLocal = false : VMs defined inline will be global in scope if allowed.
19:26:28.325 [main] DEBUG org.apache.velocity - Velocimacro : autoload off : VM system will not automatically reload global library macros
19:26:28.348 [main] DEBUG org.apache.velocity - ResourceManager : found vtemplates/class.vm with loader org.apache.velocity.runtime.resource.loader.FileResourceLoader
package com.companyname.projectname;

public User implements Serializable {

 /** Serial Version UID. */
 private static final long serialVersionUID = 1L;

 private int id;
 private String firstName;
 private String lastName;
 private LocalDate dob;
 
 public int getId() {
     return this.id;
 }
 
 public void setId(int id) {
     this.id = id;
 } 
 public String getFirstName() {
     return this.firstName;
 }
 
 public void setFirstName(String firstName) {
     this.firstName = firstName;
 } 
 public String getLastName() {
     return this.lastName;
 }
 
 public void setLastName(String lastName) {
     this.lastName = lastName;
 } 
 public LocalDate getDob() {
     return this.dob;
 }
 
 public void setDob(LocalDate dob) {
     this.dob = dob;
 } 
}

4. Apache Velocity Web Application Example

In this tutorial, we will learn how to use Apache Velocity to build web applications. In order to use Velocity in a web application, we will need a servlet or servlet-based framework. The easiest way to get started is with VelocityViewServlet in the Velocity Tools subproject.

Tools and technologies used

  • Servlet - 2+
  • Apache Velocity - 1.7
  • Maven - 3+
  • JDK - 1.8+
  • Eclipse IDE
  • Apache Tomcat - 8.5

Development Steps

  1. Create a Maven Web Project
  2. Add Maven Dependencies
  3. Project Structure
  4. Create User and UserService Classes
  5. Create UserServlet
  6. Create LayoutServlet
  7. Web Configuration
  8. Resource Loader
  9. Velocity Templates
  10. Managing the Page Layout
  11. Demo

1. Create a Maven Web Project

Use below article to create a maven web project in Eclipse IDE.

2. Add Maven Dependencies

To work with Velocity, we need to add the following dependencies to our Maven project:
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.7</version>
    </dependency>
<dependency>
     <groupId>org.apache.velocity</groupId>
     <artifactId>velocity-tools</artifactId>
     <version>2.0</version>
</dependency>
Here is the complete pom.xml file:
<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.javaguides</groupId>
    <version>0.1-SNAPSHOT</version>
    <artifactId>apache-velocity</artifactId>
    <name>apache-velocity</name>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>${velocity-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-tools</artifactId>
            <version>${velocity-tools-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>${org.apache.httpcomponents.version}</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <build>
        <finalName>apache-velocity</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <org.apache.httpcomponents.version>4.5.2</org.apache.httpcomponents.version>
        <velocity-version>1.7</velocity-version>
        <velocity-tools-version>2.0</velocity-tools-version>
    </properties>
</project>

3. Project Structure

Use below screenshot to create project structure or packing structure -

4. Create User and UserService Classes

Let's create User POJO class with following content:
package net.javaguides.apache.velocity.model;

public class User {

    private String firstName;
    private String lastName;

    public User(String firstName, String lastName) {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
Let's create UserService class which creates and returns list of users to Servlet. 
Here is the complete code:
package net.javaguides.apache.velocity.service;

import java.util.Arrays;
import java.util.List;

import net.javaguides.apache.velocity.model.User;

public class UserService {

    public List < User > getUsers() {
        System.out.println("User service returning list of Users");

        return Arrays.asList(new User("Ramesh", "Fadatare"),
            new User("Tony", "Stark"),
            new User("Tom", "Cruise"));
    }
}

5. Velocity Servlet - Create UserServlet

Velocity provides one out of the box implementation VelocityViewServlet, which is a part of the velocity-tools subproject.
To make use of the built-in functionality provided by VelocityViewServlet, we can extend our servlet from VelocityViewServlet and override the handleRequest() method:
package net.javaguides.apache.velocity.servlet;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.view.VelocityViewServlet;

import net.javaguides.apache.velocity.model.User;
import net.javaguides.apache.velocity.service.UserService;

public class UserServlet extends VelocityViewServlet {

    private static final long serialVersionUID = 1 L;

    UserService service = new UserService();

    @Override
    public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) {

        List < User > users = service.getUsers();

        context.put("users", users);

        Template template = null;

        try {
            template = getTemplate("templates/index.vm");
            response.setHeader("Template Returned", "Success");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return template;
    }
}

6. Velocity Servlet - Create LayoutServlet

Let's create LayoutServlet which extends VelocityViewServlet:
package net.javaguides.apache.velocity.servlet;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.tools.view.VelocityLayoutServlet;

import net.javaguides.apache.velocity.model.User;
import net.javaguides.apache.velocity.service.UserService;

public class LayoutServlet extends VelocityLayoutServlet {
    private static final long serialVersionUID = 1 L;
    UserService service = new UserService();

    @Override
    public Template handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) {

        List < User > users = service.getUsers();

        context.put("users", users);

        Template template = null;

        try {
            template = getTemplate("templates/layoutdemo.vm");

            response.setHeader("Template Returned", "Success");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return template;
    }
}

7. Web Configuration

Let's see how to configure all the Servlets in web.xml file. The servlet is defined for intercepting the requests for velocity template pages and the layout specific properties are defined in velocity.properties file. The velocity.properties file defined in the next step.
Here is the complete web.xml with all the servlet configured:
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>apache-velocity</display-name>
    <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>net.javaguides.apache.velocity.servlet.UserServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>LayoutServlet</servlet-name>
        <servlet-class>net.javaguides.apache.velocity.servlet.LayoutServlet</servlet-class>
    </servlet>
    <servlet>
        <servlet-name>velocityLayout</servlet-name>
        <servlet-class>org.apache.velocity.tools.view.VelocityLayoutServlet</servlet-class>
        <init-param>
            <param-name>org.apache.velocity.properties</param-name>
            <param-value>/WEB-INF/velocity.properties</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>LayoutServlet</servlet-name>
        <url-pattern>/layout</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>velocityLayout</servlet-name>
        <url-pattern>*.vm</url-pattern>
    </servlet-mapping>
    <!-- session timeout -->
    <session-config>
        <session-timeout>
   30
  </session-timeout>
    </session-config>
    <!-- welcome file -->
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>
We also need to specify the mapping for this servlet. All the requests for velocity templates (*.vm) need to be served by the velocity servlet:
<servlet-mapping>
    <servlet-name>velocityLayout</servlet-name>
    <url-pattern>*.vm</url-pattern>
</servlet-mapping>

8. Resource Loader

Velocity provides a flexible resource loader system. It allows one or more resource loader to be in operation at the same time:
  • FileResourceLoader
  • JarResourceLoader
  • ClassPathResourceLoader
  • URLResourceLoader
  • DataSourceResourceLoader
  • WebappResourceLoader
These resource loaders are configured in velocity.properties:
resource.loader=webapp
webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader
webapp.resource.loader.path = 
webapp.resource.loader.cache = true

9. Velocity Templates

Let's define the velocity index.vm template:

index.vm

<HTML>
<HEAD>
    <TITLE>Online Electronic Store</TITLE>
    <style>
        body {background-color: powderblue;}
        h1   {color: blue;}
        p    {color: red;}
        table.gridtable {
            font-family: verdana,arial,sans-serif;
            font-size:11px;
            color:#333333;
            border-width: 1px;
            border-color: #666666;
            border-collapse: collapse;
        }
        table.gridtable th {
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #666666;
            background-color: tomato;
        }
        table.gridtable td {
            border-width: 1px;
            padding: 8px;
            border-style: solid;
            border-color: #666666;
            background-color: tomato;
        }

    </style>

</HEAD>
<BODY>
<CENTER>
    <h2>Users</h2>
    <BR/>
    #set( $count = 1 )
    <TABLE class="gridtable">
        <TR>
            <TH>Serial #</TH><TH>First Name</TH><TH>Last Name</TH>
        </TR>
        #foreach( $user in $users )
            <TR>
                <TD>$count)</TD>
                <TD>$user.getFirstName()</TD>
                <TD>$user.getLastName()</TD>
            </TR>
            #set( $count = $count + 1 )
        #end
    </TABLE>
    <BR/>
</CENTER>

</BODY>
</HTML>

10. Managing the Page Layout

Velocity provides a simple layout control and customizable error screens for Velocity Tool based applications.
VelocityLayoutServlet encapsulates this capability to render the specified layouts. VelocityLayoutServlet is an extension to VelocityViewServlet.

Layout Templates

The layout template defines the typical structure of a velocity page. By default, the VelocityLayoutServlet searches for Default.vm under the layout folder. Overriding a few properties can change this location:
tools.view.servlet.layout.directory = layout/
tools.view.servlet.layout.default.template = Default.vm

Default.vm

The layout file consists of the header template, footer template, and a velocity variable $screen_content which renders the contents of the requested velocity page.
<html>
<head>
 <title>Velocity</title>
</head>
<body>
  <div>
      #parse("/fragments/header.vm")
  </div>
  
  
  <div>
  
    <!-- View index.vm is inserted here -->
    $screen_content
 
  </div>
  
  <div>
      #parse("/fragments/footer.vm")
  </div>
</body>
</html>

header.vm

<div style="background: tomato; height: 80px; padding: 5px;">
  <div style="float: left">
      <h1> Layout Demo Page</h1>
  </div>
</div> 

footer.vm

<div
   style="background: tomato; text-align: center; padding: 5px; margin-top: 10px;">
   @Copyright javaguides.net
</div>

layoutdemo.vm

#set( $layout = "layout.vm" )
<CENTER>
     <h2>Users</h2>
    <BR/>
    #set( $count = 1 )
    <TABLE class="gridtable">
        <TR>
            <TH>Serial #</TH><TH>First Name</TH><TH>Last Name</TH>
        </TR>
        #foreach( $user in $users )
            <TR>
                <TD>$count)</TD>
                <TD>$user.getFirstName()</TD>
                <TD>$user.getLastName()</TD>
            </TR>
            #set( $count = $count + 1 )
        #end
    </TABLE>
    <BR/>
</CENTER>

11. Demo

Users Page:

Layout Page:

Comments