2. Velocity 工作原理
**Velocity 的核心类是 VelocityEngine
**,它负责协调整个流程:读取模板、解析内容并结合数据模型生成结果。
简单粗暴地说,使用 Velocity 的标准流程就四步:
- ✅ 初始化引擎
- ✅ 加载模板文件
- ✅ 准备数据上下文
- ✅ 合并数据与模板输出内容
来看个实战例子:
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.init();
Template t = velocityEngine.getTemplate("index.vm");
VelocityContext context = new VelocityContext();
context.put("name", "World");
StringWriter writer = new StringWriter();
t.merge(context, writer);
3. Maven 依赖配置
要在项目中使用 Velocity,需要添加以下两个核心依赖:
<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>
⚠️ 最新版本建议去 Maven 中央仓库 查找:
4. Velocity 模板语言(VTL)
Velocity Template Language (VTL) 是 Velocity 的精髓,它用最简洁的方式实现动态内容注入。
4.1 引用类型
VTL 引用以 $
开头,分为三种类型:
- 变量引用 - 通过
#set
定义或来自 Java 对象字段:#set ($message="Hello World")
- 属性引用 - 访问对象字段或 getter 方法:
$customer.name // 等价于调用 getName()
- 方法引用 - 直接调用 Java 方法:
$customer.getName()
💡 所有引用最终都会被转换为字符串输出
4.2 指令系统
VTL 提供了丰富的指令集:
- 赋值指令 -
#set
用于给变量赋值:#set ($message = "Hello World") #set ($customer.name = "Brian Mcdonald")
- 条件指令 -
#if/#elseif/#else
实现逻辑分支:#if($employee.designation == "Manager") <h3> Manager </h3> #elseif($employee.designation == "Senior Developer") <h3> Senior Software Engineer </h3> #else <h3> Trainee </h3> #end
- 循环指令 -
#foreach
遍历集合:<ul> #foreach($product in $productList) <li> $product </li> #end </ul>
- 文件包含 -
#include
导入静态文件:#include("one.gif","two.txt","three.html"...)
- 模板解析 -
#parse
动态解析 VTL 文件:#parse (Template)
- 动态求值 -
#evaluate
运行时计算表达式:#set($firstName = "David") #set($lastName = "Johnson") #set($dynamicsource = "$firstName$lastName") #evaluate($dynamicsource) // 输出 "DavidJohnson"
- 流程控制 -
#break
终止循环,#stop
终止模板渲染 - 宏定义 -
#macro
创建可复用模板片段:#macro(tablerows $color $productList) #foreach($product in $productList) <tr> <td bgcolor=$color>$product.name</td> </tr> #end #end
4.3 其他特性
- 数学运算 - 内置基础数学函数:
#set($percent = $number / 100) #set($remainder = $dividend % $divisor)
- 范围操作符 - 生成数字序列:
#set($array = [0..10]) // 创建 0-10 的数组 #foreach($elem in $arr) $elem #end
5. Velocity Servlet 集成
Velocity 引擎本身不处理 Web 相关功能,需要结合 Servlet 使用。Velocity Tools 子项目提供了现成的 VelocityViewServlet
:
public class ProductServlet extends VelocityViewServlet {
ProductService service = new ProductService();
@Override
public Template handleRequest(
HttpServletRequest request,
HttpServletResponse response,
Context context) throws Exception {
List<Product> products = service.getProducts();
context.put("products", products);
return getTemplate("index.vm");
}
}
6. 配置详解
6.1 Web 配置
在 web.xml
中配置 VelocityViewServlet
:
<web-app>
<display-name>apache-velocity</display-name>
<!-- 其他配置 -->
<servlet>
<servlet-name>velocity</servlet-name>
<servlet-class>org.apache.velocity.tools.view.VelocityViewServlet</servlet-class>
<init-param>
<param-name>org.apache.velocity.properties</param-name>
<param-value>/WEB-INF/velocity.properties</param-value>
</init-param>
</servlet>
<!-- 其他配置 -->
</web-app>
所有 .vm
请求都交给 Velocity Servlet 处理:
<servlet-mapping>
<servlet-name>velocityLayout</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
6.2 资源加载器
Velocity 支持多种资源加载方式,可同时配置多个加载器:
-
FileResourceLoader
- 文件系统加载 -
JarResourceLoader
- JAR 包加载 -
ClassPathResourceLoader
- 类路径加载 -
URLResourceLoader
- URL 加载 -
DataSourceResourceLoader
- 数据库加载 -
WebappResourceLoader
- Web 应用加载
在 velocity.properties
中配置:
resource.loader=webapp
webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader
webapp.resource.loader.path =
webapp.resource.loader.cache = true
7. 模板实战
Velocity 模板是视图逻辑的核心,使用 VTL 编写:
<html>
...
<body>
<center>
...
<h2>$products.size() Products on Sale!</h2>
<br/>
We are proud to offer these fine products
at these amazing prices.
...
#set( $count = 1 )
<table class="gridtable">
<tr>
<th>Serial #</th>
<th>Product Name</th>
<th>Price</th>
</tr>
#foreach( $product in $products )
<tr>
<td>$count)</td>
<td>$product.getName()</td>
<td>$product.getPrice()</td>
</tr>
#set( $count = $count + 1 )
#end
</table>
<br/>
</center>
</body>
</html>
8. 页面布局管理
Velocity 提供强大的布局控制能力,通过 VelocityLayoutServlet
实现。
8.1 Web 配置
配置 VelocityLayoutServlet
:
<web-app>
<!-- 其他配置 -->
<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>velocityLayout</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
<!-- 其他配置 -->
</web-app>
8.2 布局模板
默认在 layout/Default.vm
查找布局文件(可配置):
tools.view.servlet.layout.directory = layout/
tools.view.servlet.layout.default.template = Default.vm
布局文件示例:
<html>
<head>
<title>Velocity</title>
</head>
<body>
<div>
#parse("/fragments/header.vm")
</div>
<div>
<!-- 这里会插入 index.vm 的内容 -->
$screen_content
</div>
<div>
#parse("/fragments/footer.vm")
</div>
</body>
</html>
8.3 页面级布局覆盖
在页面开头指定特定布局:
#set($layout = "MyOtherLayout.vm")
8.4 请求参数覆盖
通过 URL 参数指定布局:
http://example.com/page.vm?layout=MyOtherLayout.vm
8.5 错误页面定制
通过 $error_cause
和 $stack_trace
变量展示异常信息:
tools.view.servlet.error.template = Error.vm
9. 总结
本文深入探讨了 Velocity 在动态页面渲染中的强大能力,以及多种 Servlet 集成方案。
我们还有一篇专门讲解 Spring MVC 集成 Velocity 的文章,可以在 Baeldung 查看。
完整代码示例请访问 GitHub 仓库。