Velocity 模板引擎入门
# Velocity 是什么
Apache Velocity 是基于 Java 的模板引擎,使用的模板语言叫 VTL(Velocity Template Language),模板文件常用 .vm 后缀。它将数据填入模板,生成文本;输出可以是 HTML、邮件、配置文件或源代码,不限定为网页。概念与基础语法见 官方用户指南 (opens new window)。
普通字符串替换主要负责填占位符;Velocity 还支持条件、循环和宏,适合根据数据生成重复结构。例如,按字段列表生成 Java 属性,或者按收件人的信息生成不同邮件内容。
# 从数据到输出
渲染流程中有三个角色:
| 角色 | 职责 |
|---|---|
| Java 程序 | 查询、计算并准备数据 |
| Context(上下文) | 保存模板可访问的变量和对象 |
| VTL 模板 | 描述文本结构,通过引用和指令生成内容 |
下面用 JSON 表示待传入的数据结构,仅用于说明;实际 Java 集成需要把值放进 Context,Velocity 不会自动把一段 JSON 文本变成模板变量。
{
"name": "Alice",
"skills": ["Java", "Python"]
}
2
3
4
模板 greeting.vm:
你好,${name}!
你的技能:
#foreach($skill in $skills)
- $skill
#end
2
3
4
5
核心输出如下,空白行处理可能受渲染配置影响:
你好,Alice!
你的技能:
- Java
- Python
2
3
4
Java 中的最小渲染示例
项目需已有 org.apache.velocity:velocity-engine-core 依赖,版本按项目选定。下面直接渲染字符串,便于观察 Context 与模板的关系,不涉及文件资源加载器配置:
import java.io.StringWriter;
import java.util.Arrays;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
public class VelocityExample {
public static void main(String[] args) {
VelocityEngine engine = new VelocityEngine();
engine.init();
VelocityContext context = new VelocityContext();
context.put("name", "Alice");
context.put("skills", Arrays.asList("Java", "Python"));
String template = "你好,${name}!\n你的技能:\n"
+ "#foreach($skill in $skills)- $skill\n#end";
StringWriter output = new StringWriter();
engine.evaluate(context, output, "greeting", template);
System.out.print(output.toString());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
evaluate 处理传入的模板字符串;使用独立 .vm 文件时,可配置资源加载器,通过 getTemplate 读取,再调用 template.merge(context, writer)。Context 和集成方式参见 官方开发指南 (opens new window)。
# VTL 语法速查
| 功能 | 示例 | 说明 |
|---|---|---|
| 变量引用 | $name、${name} | 花括号明确变量边界 |
| 属性访问 | $user.name | 可映射到 Java Bean getter 或 Map 取值等查找规则 |
| 方法调用 | $user.getName() | 调用上下文中对象可访问的方法 |
| 赋值 | #set($count = 3) | 在模板中设置变量 |
| 条件分支 | #if($enabled)启用#else关闭#end | 按条件选择输出 |
| 遍历 | #foreach($item in $items)$item#end | 为集合元素生成重复内容 |
| 单行注释 | ## 这里是注释 | 不输出到结果 |
| 多行注释 | #* 多行注释 *# | 注释可以跨行 |
| 静默引用 | $!optionalValue | 在通常的非严格配置下,未定义或空引用不显示原引用文本 |
| 原样包含文件 | #include("footer.txt") | 读取文件内容,不执行其中的 VTL |
| 渲染子模板 | #parse("footer.vm") | 解析并渲染另一个模板 |
| 定义宏 | #macro(greet $who)你好,$who!#end | 定义可复用模板片段,用 #greet("Alice") 调用 |
语法定义见 官方 VTL Reference (opens new window)。静默引用不等于解决数据缺失;严格模式下的行为应结合项目配置检查。
条件和循环放在哪里
模板适合决定“是否显示某段文本”“重复输出哪些条目”。数据查询、权限判断和复杂业务计算应先在 Java 侧完成,再把结果交给模板,避免渲染过程承担业务流程。
# 阅读模板时的排查顺序
| 现象 | 优先检查 |
|---|---|
输出里出现 $name 原文 | Context 是否传入该变量、名字及大小写是否一致;是否启用了严格模式 |
$user.name 没有得到预期值 | 对象类型、getter/Map 键及属性查找规则 |
| 循环没有输出 | 集合是否存在、是否为空;是否进入了外层条件 |
| 子模板中的指令原样显示 | 是否误用了 #include,需要渲染时应检查 #parse |
| 生成文件的空白与预期不同 | 模板自身空格、换行及引擎的空白处理配置 |
模板运行在宿主引擎中;其他产品即使使用 VTL,也可能只提供部分语法或额外变量。排查时同时核对宿主提供的 Context 和实际引擎版本,不只看 .vm 扩展名。
# 官方文档入口
本文示例参考 Velocity Engine 2.3 文档;接入已有项目时优先阅读相同版本的资料。
| 目标 | 官方入口 |
|---|---|
| 从概念和例子入门 | User Guide (opens new window) |
| 快速查指令与引用语法 | VTL Reference (opens new window) |
| Java 集成、Context、资源加载与空白处理 | Developer Guide (opens new window) |
| 查看引擎项目和其他版本入口 | Apache Velocity Engine (opens new window) |