一、Velocity 核心概念
- 模板(Template):包含静态内容和 Velocity 语法(变量、指令等)的文本文件(通常以
.vm
为后缀)。 - 上下文(Context):存储数据的容器(类似键值对映射),模板通过上下文获取动态数据。
- 引擎(VelocityEngine):Velocity 的核心组件,负责加载模板、解析语法、结合上下文生成最终内容。
二、环境搭建
1. 引入依赖(Maven)
在 pom.xml
中添加 Velocity 依赖:
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.3</version> <!-- 最新稳定版 --> </dependency>
2. 基本目录结构
推荐将模板文件放在 src/main/resources/templates
目录下,示例结构:
src/ └── main/ ├── java/ └── resources/ └── templates/ └── hello.vm # 模板文件
三、Hello World 示例
1. 创建模板文件(hello.vm)
#set($name = "Velocity") # 定义变量 Hello, $name! # 输出变量 Today is $date. # 引用上下文数据
2. 编写 Java 代码
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.util.Date; public class VelocityDemo { public static void main(String[] args) { // 1. 初始化 Velocity 引擎 VelocityEngine engine = new VelocityEngine(); // 配置模板加载路径(从类路径加载) engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); engine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); engine.init(); // 初始化引擎 // 2. 创建上下文并添加数据 VelocityContext context = new VelocityContext(); context.put("date", new Date()); // 放入当前日期 // 3. 加载模板并合并数据 StringWriter writer = new StringWriter(); // 用于接收生成的内容 engine.mergeTemplate("templates/hello.vm", "UTF-8", context, writer); // 4. 输出结果 System.out.println(writer.toString()); } }
3. 运行结果
Hello, Velocity! Today is Thu Jul 10 12:34:56 CST 2025.
四、Velocity 基本语法
1. 变量(Variables)
- 用
$
引用变量,如$name
、$user.name
(访问对象属性)。 - 定义变量:
#set($var = "value")
(等号两侧需空格)。
2. 指令(Directives)
- 条件判断:
#if($age > 18) 成年人 #elseif($age == 18) 刚成年 #else 未成年人 #end
- 循环:
($velocityCount
是循环内置变量,从 1 开始计数) - 注释:
- 单行注释:
## 这是注释
- 多行注释:
#* 多行注释内容 *#
- 引入模板:
#include("header.vm") # 引入其他模板的内容(仅文本) #parse("footer.vm") # 引入并解析其他模板(支持Velocity语法)
3. 转义字符
- 若需输出
$
符号,用\$
转义,如\$name
会直接显示为$name
。
五、在 Web 框架中使用(以 Spring Boot 为例)
1. 引入依赖
在 pom.xml
中添加以下依赖(Spring Boot 2.x 后需手动指定版本):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-velocity</artifactId> <version>2.0.9.RELEASE</version> <!-- Spring Boot 2.x 后需指定版本 --> </dependency>
2. 配置模板路径(使用 YAML 格式)
在 application.yml
中添加以下配置:
spring velocity # 模板文件存放路径,classpath 表示 src/main/resources 目录 resource-loader-path classpath /templates # 模板文件后缀名 suffix .vm # 其他可选配置 charset UTF-8 # 字符编码(防止中文乱码) cache false # 开发环境建议关闭缓存,方便调试 check-template-location true # 检查模板文件是否存在 content-type text/html # 响应内容类型
3. 控制器中使用
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; // 声明为控制器组件 public class HelloController { /** * 处理 /hello 路径的 GET 请求 * @param model 用于传递数据到视图的模型对象 * @return 视图名称(对应 templates 目录下的模板文件) */ "/hello") ( public String hello(Model model) { // 向模型中添加属性,在模板中可以通过 ${name} 访问 model.addAttribute("name", "Spring Boot"); // 返回视图名称,Spring 会根据配置查找 templates/hello.vm 文件 return "hello"; } }
4. 代码解释
1. 代码的「身份标识」:为什么是控制器?
@Controller
注解:这行代码告诉 Spring Boot 框架,HelloController
是一个「控制器」,专门负责接收浏览器的请求、处理业务逻辑,并决定返回什么内容给用户。- 类比:就像餐厅里的「服务员」,负责接收顾客的点单(请求),然后协调厨房(业务逻辑)和出餐(返回内容)。
2. 接收请求:哪个地址会触发这个方法?
@GetMapping("/hello")
注解:表示当浏览器发送 GET 类型的请求,且请求地址是/hello
时(比如访问http://localhost:8080/hello
),就会执行下面的hello()
方法。- 类比:服务员只负责接收「点单暗号为
/hello
」的顾客,其他暗号(如/test
)不会触发这个方法。
3. 传递数据:如何把动态内容传给模板?
Model model
参数:这是 Spring 提供的「数据容器」,作用和 Velocity 中的VelocityContext
一样,用来存储需要传递给模板的动态数据。model.addAttribute("name", "Spring Boot")
:往这个容器里放了一对键值对 —— 键是name
,值是Spring Boot
。这意味着在模板中,可以通过$name
来获取这个值。- 类比:服务员在点单时,记下顾客的特殊要求(比如「少放辣」),然后把这个要求传递给厨房(模板)。
4. 指定模板:告诉框架用哪个模板生成内容?
return "hello"
:这行代码的核心作用是指定模板的名称。结合之前在application.yml
中的配置:
- 模板存放路径:
classpath:/templates
(即项目的src/main/resources/templates
文件夹) - 模板后缀:
.vm
- 因此,框架会自动拼接出模板的完整路径:
src/main/resources/templates/hello.vm
。 - 类比:服务员告诉厨房:「请用编号为
hello
的菜谱(模板)来做这道菜」,厨房就会去对应的菜谱存放处找这道菜谱。
5. 最终结果:用户看到的是什么?
- 框架找到
hello.vm
模板文件(假设内容是
)。Hello, $name!
- 解析模板中的
$name
,用model
中name
的值(Spring Boot
)替换,得到
。Hello, Spring Boot!
- 把解析后的内容转换成 HTML 页面,返回给浏览器。
- 用户在浏览器中看到的就是:
Hello, Spring Boot!
(以标题样式显示)。
六、常见问题
1. 模板加载失败
- 原因:模板路径配置错误或文件未正确打包
- 解决方案:
- 检查
application.yml
中的resource-loader-path
配置 - 确保模板文件位于
src/main/resources/templates
目录下 - 检查 Maven 配置,确保资源文件被正确打包
2. 中文乱码问题
- 原因:编码配置不一致
- 解决方案:
- 在
application.yml
中设置charset: UTF-8
- 确保 IDE 中文件编码设置为 UTF-8
- 模板文件保存时使用 UTF-8 编码
3. 对象属性无法访问
- 原因:Velocity 通过 getter 方法访问对象属性
- 解决方案:
- 确保对象的属性有对应的 getter 方法
- 例如:
$user.name
对应user.getName()
方法
4. Spring Boot 2.x 后 Velocity 支持问题
- 原因:Spring Boot 2.x 后官方不再维护 Velocity starter
- 解决方案:
- 手动指定兼容版本(如示例中的 2.0.9.RELEASE)
- 考虑使用官方推荐的模板引擎(Thymeleaf 或 FreeMarker)
七、学习资源
- 官方文档:Apache Velocity 官方指南
- GitHub 仓库:apache/velocity-engine
- Spring Boot 集成文档:Spring Boot 官方文档