本文目录导读:

什么是 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 相关的问题,欢迎继续提问。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播