Velocity 是 Apache 软件基金会 Jakarta 项目下的一个开源模板引擎。
模板引擎是一种设计模式和技术实现,它允许使用简单的标记语言来定义页面或文档结构,并通过数据填充这些模板来生成最终的输出。模板引擎广泛应用于 Web 开发、邮件发送、报告生成等领域。
常见模板引擎
Velocity
Velocity 是 Apache 软件基金会下的开源模板引擎,以其简洁易用而著称。它主要用于生成 HTML 页面,但也可以用于创建 SQL 查询、XML 文件等文本输出。Velocity 的设计理念是让非程序员也能相对容易地理解和修改模板。
主要特点:
- 简单直观:语法非常简洁。
- 职责分离:专注于视图层的表现逻辑。
- 灵活性:直接访问 Java 对象及其属性。
- 国际化支持:支持多语言环境。
- 可扩展:可以通过自定义指令或工具类进行扩展。
FreeMarker
FreeMarker 是另一个功能强大的 Java 模板引擎,被广泛应用于企业级应用中。它提供了比 Velocity 更丰富的标签库和表达式语言。
特点:
- 功能丰富:提供多种内置函数和宏。
- 灵活度高:适合处理复杂的逻辑。
- 国际化友好:内置了良好的多语言支持。
- 社区活跃:有大量的实际案例和社区资源。
Thymeleaf
Thymeleaf 是一种面向 XML/XHTML/HTML5 的模板引擎,特别适用于 Spring Boot 应用程序。它的特点是可以在浏览器中直接预览未经处理的模板。
特点:
- 自然模板:可以直接在浏览器中查看模板。
- XML/HTML 友好:非常适合处理 XML 和 HTML 文档。
- Spring 集成:与 Spring 框架集成得非常好。
- 强大的表达式语言:提供了丰富的表达式来操作数据。
JSP
JSP (JavaServer Pages) 是 Java EE 标准的一部分,历史悠久且成熟稳定。它允许在页面中嵌入 Java 代码,提供了极大的灵活性。
特点:
- 成熟稳定:有悠久的历史和广泛的行业采用。
- 嵌入 Java 代码:可以直接在页面中编写 Java 代码。
- 组件化:支持自定义标签库,封装复杂的 UI 组件。
- 调试工具:许多 IDE 和服务器都提供了针对 JSP 的良好调试支持。
Velocity主要用途
Velocity最初是为了解决Java应用程序中的视图层问题而设计的,但它的应用范围已经扩展到了其他多种场景:
- 生成 Web 页面:这是 Velocity 最常见的用途,它可以将 Java 对象中的数据填充到 HTML 模板中,生成动态网页。
- 创建文档:Velocity 可以生成 SQL 脚本、PostScript 文件、XML 文件等,适用于自动化生成各种类型的文档。
- 代码生成:Velocity 用于生成 Java、C#、PHP 等语言的代码,简化了开发流程。
Velocity基本概念
模板
Velocity的模板(Template)是开发者与Velocity交互的主要方式。这些模板文件是普通的文本文件,可以包含任何文本内容,比如HTML、XML或JavaScript代码。这些模板还包含了Velocity Template Language (VTL) 的指令,这些指令用于插入动态内容。模板定义了最终输出文档的结构和布局。
例如,一个简单的网页模板可能看起来像这样:
<html>
<head>
<title>Welcome to cengxuyuan.cn Website</title>
</head>
<body>
<h1>$pageTitle</h1>
<p>Welcome, $userName!</p>
</body>
</html>
在这个例子中,$pageTitle
和 $userName
是变量占位符,它们将在运行时被实际的数据所替换。
模板通常以.vm
作为扩展名,这有助于识别文件类型,并且可以在配置文件中指定如何加载这些模板。
VTL
VTL(Velocity Template Language)是Velocity的核心,它是一种简洁而强大的语言,旨在与Java对象交互并生成文本输出。
VTL提供了多种语法元素,包括但不限于:
- 变量引用:通过
$variableName
的形式来引用上下文中的变量。例如,如果上下文中有一个名为userName
的变量,则可以通过$userName
在模板中引用它。 - 属性引用:访问Java对象的属性使用点符号,即
$object.property
。如果有一个User
对象,并且这个对象有一个name
属性,那么在模板中就可以这样引用这个属性:$user.name
。 - 方法调用:可以调用Java对象的方法,形式为
$object.method()
。如果有参数,它们应该放在括号内,并且多个参数之间用逗号分隔。例如,如果有getFullName(firstName, lastName)
方法,则可以在模板中这样调用:$user.getFullName($firstName, $lastName)
。 - 控制结构:VTL支持条件语句(如
#if
,#else
)和循环(如#foreach
),使得模板能够根据数据的不同情况生成不同的内容。
VTL的设计目标是简单易学,同时保持足够的灵活性来处理复杂的逻辑需求。
上下文
上下文(Context)是Velocity引擎用来存储和传递数据给模板的一个关键组件。它本质上是一个键值对的映射,类似于Java中的HashMap
。键通常是字符串,而值可以是任何类型的Java对象,比如字符串、数字、日期或者是自定义的对象。
上下文的作用是充当桥梁,连接Java应用程序和Velocity模板。当渲染模板时,Velocity会查找上下文中对应的键,并使用关联的值来填充模板中的变量。
例如,在Java代码中,我们可以创建一个VelocityContext
实例,然后添加数据到其中:
VelocityContext context = new VelocityContext();
context.put("pageTitle", "cengxuyuan Homepage");
context.put("userName", "cengxuyuan");
VTL基本语法
变量引用
- 格式:
$variableName
- 作用:从上下文中获取变量的值。在模板中使用
$
符号加上变量名即可引用存储在VelocityContext
中的数据。例如,如果上下文中有一个名为userName
的变量,则可以通过$userName
来访问其值。 - 示例:velocity如果
<p>Welcome, $userName!</p>
userName
的值是"John Doe"
,那么输出将会是<p>Welcome, John Doe!</p>
。
属性引用
- 格式:
$object.property
- 作用:访问Java对象的属性。通过点符号
.
可以访问一个对象的属性或嵌套的对象。这允许你深入到复杂的对象结构中去获取数据。 - 示例:velocity假设
<p>User ID: $user.id</p> <p>User Name: $user.name</p>
user
对象有id
和name
属性,这段代码会输出用户的ID和名字。
方法调用
- 格式:
$object.method()
- 作用:执行对象的方法,并可以在模板中引用返回值。方法可以有参数,多个参数之间用逗号分隔。
- 示例:velocity这里假设
<p>Full Name: $user.getFullName($firstName, $lastName)</p>
user
对象有一个getFullName
方法,接受两个参数firstName
和lastName
,并返回全名。
指令
类型:VTL 提供了多种指令来控制模板的行为。
#set:用于设置变量。
- 格式:
#set($variable = "value")
- 示例:velocity
#set($greeting = "Hello, World!") <p>$greeting</p>
- 格式:
#if/#elseif/#else/#end:用于条件判断。
- 格式:velocity
#if($condition) ... content if condition is true ... #elseif($anotherCondition) ... content if anotherCondition is true ... #else ... default content ... #end
- 示例:velocity
#if($user.isAdmin()) <p>You are an admin.</p> #else <p>You are a regular user.</p> #end
- 格式:
#foreach:用于循环遍历集合。
- 格式:
#foreach($item in $list)
- 示例:velocity这段代码会生成一个无序列表,其中每一项都是
<ul> #foreach($item in $items) <li>$item.name: $item.price</li> #end </ul>
items
集合中的元素。
- 格式:
其他指令:还有诸如
#macro
(定义宏)、#include
(包含其他模板)等指令,这些都提供了更高级的功能。
注释
单行注释:
##
示例:
velocity## This is a single-line comment
多行注释:
#* ... *#
示例:
velocity#* This is a multi-line comment *#
作用:注释不会出现在最终的输出中,它们主要用于文档化模板或暂时禁用某些代码片段。
Velocity使用流程
引入Velocity依赖
首先,需要在Java项目中引入Velocity的依赖。如果是Maven项目,可以在pom.xml
文件中添加以下依赖:
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>3</version>
</dependency>
创建Velocity模板
创建一个.vm
扩展名的文本文件,这个文件将包含静态内容和动态内容。动态内容通过VTL标记来表示。
例如,创建一个名为hello.vm
的模板文件:
查看代码
<!DOCTYPE html>
<html>
<head>
<title>$title</title>
</head>
<body>
<h1>Hello, $name!</h1>
#foreach($greeting in $greetings)
<p>$greeting</p>
#end
</body>
</html>
在这个模板中,$title
、$name
和 $greetings
是变量,它们将在运行时被替换为实际的值。
初始化Velocity引擎
在Java代码中,初始化Velocity引擎,并设置所需的属性。
查看代码
import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import java.io.StringWriter;
import java.util.Properties;
public class VelocityExample {
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
properties.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
Velocity.init(properties);
}
}
创建上下文对象
创建一个VelocityContext
对象,并将需要传递给模板的数据放入上下文。
VelocityContext context = new VelocityContext();
context.put("title", "Welcome Page");
context.put("name", "Alice");
context.put("greetings", Arrays.asList("Hello", "Bonjour", "Hola"));
合并模板
使用Velocity引擎合并模板和上下文数据,生成最终的输出。
StringWriter writer = new StringWriter();
Velocity.mergeTemplate("hello.vm", "UTF-8", context, writer);
String output = writer.toString();
System.out.println(output);
输出或使用结果
将合并后的结果输出到控制台、保存到文件或发送到Web浏览器。
// 输出到控制台
System.out.println(output);
// 保存到文件
try (FileWriter fileWriter = new FileWriter("output.html")) {
fileWriter.write(output);
} catch (IOException e) {
e.printStackTrace();
}