本文目录导读:

什么是 Velocity?
Velocity 是一个基于 Java 的模板引擎,它允许你使用简单的模板语言(VTL - Velocity Template Language)来引用 Java 代码中定义的对象和方法,它的核心理念是将前端页面与后端逻辑分离,前端开发者专注于编写页面结构,后端开发者提供数据模型。
主要用途:
- 生成 Web 页面(类似 JSP,但更轻量)
- 生成 SQL、XML、邮件内容等文本
- 代码生成器(如 MyBatis 逆向工程)
一个完整的实战案例:生成用户报表
在这个案例中,我们将使用 Velocity 从一个用户数据列表生成一个 HTML 报表。
环境准备(Maven 依赖)
在你的 pom.xml 中添加 Velocity 的依赖:
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
创建 Velocity 模板文件 (user_report.vm)
在 src/main/resources/templates 目录下创建该文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">用户报表 - ${reportTitle}</title>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
th {
background-color: #4CAF50;
color: white;
}
</style>
</head>
<body>
<h1>${reportTitle}</h1>
<p>生成日期:${generatedDate}</p>
#if($users.isEmpty())
<p><strong>暂无用户数据。</strong></p>
#else
<table>
<tr>
<th>用户ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>状态</th>
</tr>
#foreach($user in $users)
<tr>
<td>$!{user.id}</td> <!-- $! 表示如果为 null 则输出空字符串 -->
<td>$!{user.name}</td>
<td>
#if($user.email)
<a href="mailto:${user.email}">$user.email</a>
#else
<span style="color: gray;">未填写</span>
#end
</td>
<td>
#if($user.status == "ACTIVE")
<span style="color: green;">活跃</span>
#elseif($user.status == "DISABLED")
<span style="color: red;">禁用</span>
#else
<span style="color: orange;">未知</span>
#end
</td>
</tr>
#end
</table>
<p>总用户数:${users.size()}</p>
#end
</body>
</html>
创建用户模型类 (User.java)
这是一个简单的 POJO 类。
public class User {
private Long id;
private String name;
private String email;
private String status; // ACTIVE, DISABLED
// 构造函数、getter/setter 省略,但必须齐全
public User() {}
public User(Long id, String name, String email, String status) {
this.id = id;
this.name = name;
this.email = email;
this.status = status;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
}
Java 主程序 (VelocityReportGenerator.java)
这是核心的调用代码。
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class VelocityReportGenerator {
public static void main(String[] args) {
// 1. 初始化 Velocity 引擎
VelocityEngine velocityEngine = new VelocityEngine();
// 设置模板资源加载器为 Classpath(即读取 resources 下的文件)
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
// 设置编码,防止中文乱码
velocityEngine.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
velocityEngine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
velocityEngine.init();
// 2. 创建上下文(数据模型),并填充数据
VelocityContext context = new VelocityContext();
context.put("reportTitle", "2024年第一季度用户统计报告");
context.put("generatedDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// 创建模拟的用户数据
List<User> users = new ArrayList<>();
users.add(new User(1L, "张三", "zhangsan@example.com", "ACTIVE"));
users.add(new User(2L, "李四", null, "DISABLED")); // 没有邮箱
users.add(new User(3L, "王五", "wangwu@example.com", "ACTIVE"));
users.add(new User(4L, "赵六", "zhaoliu@example.com", "PENDING"));
context.put("users", users);
// 3. 获取模板
Template template = velocityEngine.getTemplate("templates/user_report.vm", "UTF-8");
// 4. 合并模板和数据(渲染)
StringWriter writer = new StringWriter();
template.merge(context, writer);
// 5. 输出结果
System.out.println("========== 生成的 HTML 内容 ==========");
System.out.println(writer);
// 你可以将 writer.toString() 保存到文件或通过 HTTP 响应输出
}
}
运行结果
运行 main 方法后,控制台将输出完整的 HTML 代码,它的关键渲染部分如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">用户报表 - 2024年第一季度用户统计报告</title>
<!-- 样式省略 -->
</head>
<body>
<h1>2024年第一季度用户统计报告</h1>
<p>生成日期:2024-05-20 10:30:45</p>
<!-- 表格部分 -->
<table>
<tr>
<th>用户ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>状态</th>
</tr>
<tr>
<td>1</td>
<td>张三</td>
<td><a href="mailto:zhangsan@example.com">zhangsan@example.com</a></td>
<td><span style="color: green;">活跃</span></td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td><span style="color: gray;">未填写</span></td>
<td><span style="color: red;">禁用</span></td>
</tr>
<!-- 王五、赵六等 -->
<p>总用户数:4</p>
</table>
</body>
</html>
Velocity 语法核心点总结
了解以下语法,你就可以应对大部分场景:
- 引用变量:
$variable或${variable}(更推荐后者,可避免拼接歧义)。 - 空值安全引用:
$!{variable},如果变量为null,则输出空字符串而不是"$variable"。 - 设置属性:
#set($var = "value")。 - 条件判断:
#if / #elseif / #else / #end。 - 循环遍历:
#foreach($item in $collection) / #end,可以使用$foreach.index(索引)和$foreach.hasNext。 - 引入其他模板:
#parse("header.vm")或#include("footer.html")。 - 注释:
## This is a comment(单行)和 (多行)。 - 调用方法:可以直接调用对象的 getter 方法(如
$user.getName()通常简写为$user.name),也可以在模板中调用带参数的方法(如$user.isActive())。
常见问题与优化建议
- 中文乱码:务必在初始化引擎时设置
input.encoding和output.encoding为UTF-8,并在获取模板时指定编码(如getTemplate(path, "UTF-8"))。 - 性能:如果你的应用是高并发场景(如 Web MVC),建议使用
VelocityEngine的单例实例,并在应用启动时预加载模板,而不是每次请求都创建新引擎。 - 不要在模板中写复杂业务逻辑:Velocity 的职责是展示数据,复杂的判断和计算应放在 Java 后台完成,只把最终结果放入上下文,保持模板简洁。
如果你需要处理更复杂的场景(如宏定义、布局装饰等),Velocity 还提供了 #macro 和布局工具,可以进一步探索,希望这个例子能帮你顺利上手!如果你还有其他 Velocity 相关的问题,欢迎继续提问。