A Comprehensive Guide to Apache Velocity with Java

Introduction to Apache Velocity

Apache Velocity is a powerful Java-based template engine that allows developers to create dynamic web applications and generate textual output (HTML, XML, SQL, etc.) by processing Velocity Template Language (VTL) files.

It is well-suited for web frameworks, content management systems, and other applications requiring a flexible template engine.

To learn how to use velocity in DocsFold reusable templates, check out our quick velocity templating tutorial here.

Setting Up Velocity

To use Apache Velocity in your project, add the following dependency to your Maven pom.xml file:

XML
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>2.3</version>
</dependency>

For Gradle, add the following to your build.gradle file:

groovy
implementation 'org.apache.velocity:velocity:2.3'

Velocity Template Language

VTL is the syntax used to create dynamic content in Apache Velocity templates. It supports variables, loops, conditionals, and other programming constructs, making it a versatile and powerful language for templating.

Variables

To declare a variable, use the $ symbol followed by the variable name:

html
#set($name = "John Doe")

To reference a variable, simply use the $ symbol followed by the variable name:

html
<p>Hello, $name!</p>

Escaping Special Characters

To escape special characters in VTL, use the \ (backslash) character:

html
\# This line will be treated as plain text, not a comment

Velocity Context

The Velocity Context is a Java object that maps keys (variable names) to values (objects). It provides a way to pass data between Java code and Velocity templates.

Here's an example of how to create a Velocity Context and populate it with data:

java
import org.apache.velocity.VelocityContext;
VelocityContext context = new VelocityContext();
context.put("name", "John Doe");
context.put("age", 30);

Control Structures in VTL

VTL supports various control structures, such as loops and conditionals, for dynamic content generation.

If-Else Statements

html
#if($age >= 18)
<p>You are an adult.</p>
#else
<p>You are not an adult.</p>
#end

For Loops

html
#foreach($number in [1..5])
<p>$number</p>
#end

Directives and Macros

Directives

Directives are special commands in VTL that perform specific tasks. Some common directives are:

  • #set: Assigns a value to a variable
  • #if: Starts a conditional block
  • #elseif: Continues a conditional block with another condition
  • #else: Ends a conditional block with a default case
  • #foreach: Iterates through a collection
  • #break: Stops the current loop iteration
  • #include: Includes the content of another template file
  • #parse: Parses and includes the content of another template file, allowing the use of variables and macros from the current context
  • #macro: Defines a reusable block of code

Macros

Macros are reusable code snippets that can be defined using the #macro directive and invoked later in the template. They can accept parameters and have local variables.

Here's an example of defining a macro:

html
#macro(displayUser $user)
<p>Name: $user.name</p>
<p>Age: $user.age</p>
#end

To invoke the macro, use the macro name followed by the required parameters:

html
#displayUser($user)

Integrating with Spring Boot

To integrate Apache Velocity with Spring Boot, add the following dependencies to your Maven pom.xml file:

XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
</dependency>

For Gradle, add the following to your build.gradle file:

groovy
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-velocity'

Configure Velocity in your application.properties file:

java
spring.velocity.resource-loader-path=classpath:/templates/
spring.velocity.suffix=.vm

Create a Velocity template file in the src/main/resources/templates directory:

html
<!-- src/main/resources/templates/welcome.vm -->
<h1>Welcome, $name!</h1>

Finally, create a Spring Boot controller to render the template:

java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class WelcomeController {
@GetMapping("/welcome")
public String welcome(Model model) {
model.addAttribute("name", "John Doe");
return "welcome";
}
}

Apache Velocity Best Practices

  • Keep templates clean and readable by using comments, whitespace, and proper indentation.
  • Use meaningful variable names and keep the scope of variables as narrow as possible.
  • Organize related templates into subdirectories for better maintainability.
  • Prefer #parse over #include to leverage the power of the current context.
  • Use macros for code reuse and to improve template maintainability.
  • Always escape user input to prevent cross-site scripting (XSS) and other security vulnerabilities.

Advanced Techniques in Apache Velocity

Template Inheritance

Apache Velocity does not support template inheritance out-of-the-box. However, you can achieve a similar result using #parse and #define directives in conjunction with a base template.

Here's an example of a base template:

html
<!-- src/main/resources/templates/base.vm -->
<html>
<head>
<title>$pageTitle</title>
</head>
<body>
#parse("header.vm")
#define($content)
#end
$content
#parse("footer.vm")
</body>
</html>

Create a child template that extends the base template:

html
<!-- src/main/resources/templates/child.vm -->
#set($pageTitle = "Child Page")
#define($content)
<h1>Welcome to the child page!</h1>
<p>This is an example of template inheritance using Apache Velocity.</p>
#end
#parse("base.vm")

Working with Maps

Velocity supports working with Java maps, allowing you to store and retrieve key-value pairs. Here's an example of how to use maps in Velocity templates:

java
import java.util.HashMap;
import java.util.Map;
Map<String, String> userInfo = new HashMap<>();
userInfo.put("name", "John Doe");
userInfo.put("email", "john.doe@example.com");
VelocityContext context = new VelocityContext();
context.put("userInfo", userInfo);

In your template, you can access the map values using the following syntax:

html
<p>Name: $userInfo.get("name")</p>
<p>Email: $userInfo.get("email")</p>

Working with Lists

Velocity also supports working with Java lists. Here's an example of how to create a list and use it in a Velocity template:

java
import java.util.ArrayList;
import java.util.List;
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
VelocityContext context = new VelocityContext();
context.put("fruits", fruits);

In your template, you can iterate through the list using the #foreach directive:

html
<ul>
#foreach($fruit in $fruits)
<li>$fruit</li>
#end
</ul>

Apache Velocity Logging and Debugging

Apache Velocity uses the SLF4J logging framework, allowing you to configure logging levels and output formats to suit your needs.

To enable logging, add the following dependencies to your Maven pom.xml file:

XML
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
</dependency>

For Gradle, add the following to your build.gradle file:

groovy
implementation 'org.slf4j:slf4j-api:1.7.32'
implementation 'org.slf4j:slf4j-simple:1.7.32'

Configure the logging level in your application.properties file:

org.slf4j.simpleLogger.defaultLogLevel=debug

To debug Velocity templates, you can use the Log tool, which provides a convenient way to output messages to the log:

html
#set($log = $tool.Log)
$log.debug("Debugging a Velocity template")

These advanced techniques, along with logging and debugging, will help you create more efficient and maintainable Velocity templates, as well as improve your overall experience with the Apache Velocity template engine.

Performance Optimization in Apache Velocity

Optimizing the performance of your Apache Velocity templates is crucial for delivering a fast and responsive user experience. Here are some tips to help you optimize your templates:

  • Use a template cache: Enable Velocity's template cache to reduce the overhead of repeatedly parsing templates. Configure the cache size and expiration policy according to your application's needs.
  • Minimize the use of complex expressions: Complex expressions in VTL can impact rendering performance. Opt for simpler expressions and calculations in your templates, or offload complex calculations to the Java code.
  • Leverage the power of macros: Use macros to encapsulate reusable logic, which can reduce template size and complexity, leading to improved performance.
  • Avoid deeply nested loops: Deeply nested loops can cause performance issues. Consider refactoring your templates to minimize loop nesting.
  • Profile your templates: Use profiling tools to identify performance bottlenecks in your templates and make the necessary optimizations.

Apache Velocity vs. Other Template Engines

When choosing a template engine for your Java project, it's important to understand the strengths and weaknesses of each option. Let's compare Apache Velocity to two popular alternatives: Thymeleaf and FreeMarker.

Apache Velocity

  • Pros:
    • Simple syntax and easy to learn
    • Fast rendering performance
    • Flexible and extensible
  • Cons:
    • Lacks built-in support for template inheritance
    • Limited support for XML and XHTML

Thymeleaf

  • Pros:
    • Natural templating: templates are valid HTML/XML files
    • Rich feature set, including template inheritance and fragments
    • Good integration with Spring Boot
  • Cons:
    • Steeper learning curve
    • Slower rendering performance compared to Velocity and FreeMarker

FreeMarker

  • Pros:
    • Comprehensive feature set, including template inheritance and macros
    • Fast rendering performance
    • Good support for XML and XHTML
  • Cons:
    • More complex syntax than Velocity
    • Less popular and less community support compared to Velocity and Thymeleaf

Ultimately, the choice of a template engine depends on your project requirements and personal preferences. Each engine has its unique features and trade-offs, so it's essential to consider your specific use case when making a decision.

In conclusion, Apache Velocity is a powerful and versatile template engine, well-suited for a wide range of applications. By mastering its features and following best practices, you can create dynamic, maintainable, and high-performing templates that will enhance the user experience of your web applications.

Author Image
About the author

Gustavo Santos

Gustavo is the founder of DocsFold, based in Portugal. He has worked as a software developer for over 15 years. He enjoys exploring new technologies and using them to automate work as much as possible.