目录
Velocity是一个基于Java的模板引擎,可以通过特定的语法获取在java对象的数据 , 填充到模板中,从而实现界面和java代码的分离 !
那 Velocity 有什么应用场景呢?
- Web应用程序 : 作为为应用程序的视图, 展示数据。
- 源代码生成 : Velocity可用于基于模板生成Java源代码。
- 自动电子邮件 : 网站注册 , 认证等的电子邮件模板。
- 网页静态化 : 基于velocity模板 , 生成静态网页。
组成结构:
| 模块 | 描述 |
| app | 主要封装了一些接口 , 暴露给使用者使用。主要有两个类,分别是Velocity(单例)和VelocityEngine。 |
| Context | 主要封装了模板渲染需要的变量 |
| Runtime | 整个Velocity的核心模块,Runtime模块会将加载的模板解析成语法树,Velocity调用mergeTemplate方法时会渲染整棵树,并输出最终的渲染结果。 |
| RuntimeInstance | RuntimeInstance类为整个Velocity渲染提供了一个单例模式,拿到了这个实例就可以完成渲染过程了。 |
详细介绍大家可以看官网,传送门放这里了:The Apache Velocity Project
这里给大家简单演示如何使用Velocity定义html 模板,然后将动态数据填充到模板中,最后形成一个完整的html 页面。
首先我们创建一个项目,我就直接创建一个springBoot 项目了,大家可以根据自己的需求来。

创建好项目,我们引入velocity依赖。
- <dependency>
- <groupId>org.apache.velocity</groupId>
- <artifactId>velocity-engine-core</artifactId>
- <version>2.2</version>
- </dependency>
我们在resources 目录下创建模板文件。

模板文件内容
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
-
- hello , ${name} !
-
- </body>
- </html>
模板创建好之后,我们到Test 类中,编写java 代码。

- @Test
- void contextLoads() throws IOException {
- // 1、设置velocity资源加载器
- Properties prop = new Properties();
- prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
- // 2、初始化velocity引擎
- Velocity.init(prop);
- // 3、创建Velocity容器
- VelocityContext context = new VelocityContext();
- context.put("name", "一切总会归于平淡");
- // 4、加载Velocity模板
- Template tpl = Velocity.getTemplate("vms/demo01.vm", "UTF-8");
- // 5、合并数据到模板
- FileWriter fw = new FileWriter("E:\\code\\Demo\\velocityDemo\\src\\main\\resources\\html\\demo01.html");
- tpl.merge(context, fw);
- // 6、释放资源
- fw.close();
- }
输出结果:

Velocity解决了如何在后台程序和网页之间传递数据的问题,后台代码和视图之间相互独立,一方的修改不影响另一方,他们之间是通过环境变量(Context)来实现的,网页制作一方和后台程序一方相互约定好对所传递变量的命名约定,比如上面程序例子中的 name变量,它们在网页上就是$name 。
只要双方约定好了变量名字,那么双方就可以独立工作了。无论页面如何变化,只要变量名不变,那么后台程序就无需改动,前台网页也可以任意由网页制作人员修改。这就是Velocity的工作原理。
Velocity Template Language (VTL) , 是Velocity 中提供的一种模版语言 , 旨在提供最简单和最干净的方法来将动态内容合并到网页中。
简单来说VTL可以将程序中的动态数展示到网页中。
VTL的语句分为4大类:注释 , 非解析内容 , 引用和指令。
语法:
- 行注释: ## 行注释内容
- 块注释:#* 块注释内容1 块注释内容2 *#
- 文档注释:#** 文档注释内容1 文档注释内容2 *#
代码演示:

什么是非解析内容?
非解析内容就是不会被velocity 解析的内容,所写的内容都会原样输出出来。
那这到底有什么用呢?因为我们就算是直接在模板文件中书写内容,它也会原样直接显示出来呀。
大家直接往下看。
语法:#[[ 非解析内容1 非解析内容2 ]]#
代码演示 :

我们再把java代码运行一下。


引用语句就是对引擎上下文对象中的属性进行操作。语法方面分为常规语法($属性)和正规语法(${属性})。
| 语法 | 描述 |
| $变量名 | 若上下文中没有对应的变量,则输出字符串"$变量名" |
| ${变量名} | 若上下文中没有对应的变量,则输出字符串"${变量名}" |
| $!变量名 | 若上下文中没有对应的变量,则输出空字符串"" |
| $!{变量名} | 若上下文中没有对应的变量,则输出空字符串"" |
代码演示:

我们运行java 代码看看执行效果:

| 语法 | 描述 |
| $变量名.属性 | 若上下文中没有对应的变量,则输出字符串"$变量名.属性" |
| ${变量名.属性} | 若上下文中没有对应的变量,则输出字符串"${变量名.属性}" |
| $!变量名.属性 | 若上下文中没有对应的变量,则输出字符串"" |
| $!{变量名.属性} | 若上下文中没有对应的变量,则输出字符串"" |
代码演示:

我们创建一个实体类。

我们修改一下测试类代码。

我们运行一下代码,看看执行效果。

方法引用实际就是指方法调用操作,关注点返回值和参数 , 方法的返回值将输出到最终结果中
| 语法 | 描述 |
| $变量名.方法([入参1[, 入参2]*]?) | 若上下文中没有对应的变量,则输出字符串"$变量名.方法([入参1[, 入参2]*]?" |
| ${变量名.方法([入参1[, 入参2]*]?)} | 若上下文中没有对应的变量,则输出字符串"${变量名.方法([入参1[, 入参2]*]?)}" |
| $!变量名.方法([入参1[, 入参2]*]?) | 若上下文中没有对应的变量,则输出字符串"" |
| $!{变量名.方法([入参1[, 入参2]*]?)} | 若上下文中没有对应的变量,则输出字符串"" |
代码演示:
我们修改一下java代码。

然后修改 模板文件。

然后我们看看执行效果。

方法引用实际就是指方法调用操作,关注点返回值和参数 , 方法的返回值将输出到最终结果中
| 语法 | 描述 |
| $变量名.方法([入参1[, 入参2]*]?) | 若上下文中没有对应的变量,则输出字符串"$变量名.方法([入参1[, 入参2]*]?" |
| ${变量名.方法([入参1[, 入参2]*]?)} | 若上下文中没有对应的变量,则输出字符串"${变量名.方法([入参1[, 入参2]*]?)}" |
| $!变量名.方法([入参1[, 入参2]*]?) | 若上下文中没有对应的变量,则输出字符串"" |
| $!{变量名.方法([入参1[, 入参2]*]?)} | 若上下文中没有对应的变量,则输出字符串"" |
代码演示:
我们修改一下java代码。

然后修改 模板文件。

然后我们看看执行效果。

指令主要用于定义重用模块、引入外部资源、流程控制。指令以 # 作为起始字符。
| 指令 | 语法 | 描述 |
| #set | #set($变量 = 值) | 在页面中声明定义变量 |
| #if/#elseif/#else | 下面演示 | 进行逻辑判断 |
| #foreach | 下面演示 | 遍历循环数组或者集合 |
1、#set

看看执行效果:

2、#if/#elseif/#else

我们看看执行效果。

3、#foreach

我们看看生成效果。

内置属性:
| $foreach.index | 获取遍历的索引 , 从0开始 |
| $foreach.count | 获取遍历的次数 , 从1开始 |
| 指令 | 描述 |
| #include | 引入外部资源 , 引入的资源不会被引擎所解析 |
| #parse | 引入外部资源 , 引入的资源将被引擎所解析 |
| #define | 定义重用模块(不带参数) |
| evaluate | 动态计算 , 动态计算可以让我们在字符串中使用变量 |
1、#include
我们新建一个模板文件。

、
然后我们在 demo01.vm 中引入。

我们来看看执行效果

我们可以看到 ${now }并未被解析,这是大家要注意的。
2、#parse

我们看看执行的效果。

我们可以看到解析了。
3、#define

效果:

4、#evaluate

效果:

作用 : 定义重用模块(可带参数)
定义语法:
- #macro(宏名 [$arg]?)
- .....
- #end
调用语法:
#宏名([$arg]?)
演示:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- #set($userList = [
- {"name":"一切总会归于平淡","sex":"男","age":"22"}
- ])
- <h1>定义宏</h1> #macro(table $list)
- <table border="1px">
- <tr>
- <td>编号</td>
- <td>用户名</td>
- <td>密码</td>
- <td>邮箱</td>
- <td>年龄</td>
- <td>操作</td>
- </tr>
- #foreach($item in $list)
- <tr>
- <td>${foreach.count}</td>
- <td>${item.name}</td>
- <td>${item.sex}</td>
- <td>${item.age}</td>
- </tr>
- #end
- </table>
- #end
- <h1>调用宏</h1>
- #table($userList)
- </body>
- </html>
效果:
