Thymeleaf 的语法简单易懂,类似 HTML,但又具有更强大的功能。我们可以在模板中使用 Thymeleaf 表达式访问后端数据,并将其展示在页面中。此外,它还支持条件判断、循环和模板片段等功能,让页面展示更加灵活。

一、创建模板文件

在 HTML 根标签中声明 th 命名空间,即可使用以 th: 开头的 Thymeleaf 属性。

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>

浏览器会将普通 HTML 正常显示;服务端的 Thymeleaf 模板引擎会处理 th: 属性,从而把后端数据渲染到页面中。

二、简单表达式

1. 变量表达式 ${…

变量表达式用于接收后端传来的变量。

<!-- 后端传入:message = "你好" -->
<p th:text="${message}"></p>

此时 p 标签中的内容会被替换为后端传来的 message,即“你好”。

2. 选择变量表达式 *{…}

选择变量表达式会根据父标签的 th:object 所选择的对象,取出对应的属性值。

<div th:object="${user}">
<p th:text="*{name}"></p>
<p th:text="*{sex}"></p>
<p th:text="*{age}"></p>
</div>

user 是一个对象,其中保存了 name、sex 和 age 三个属性。上面的代码等效于:

<div>
<p th:text="${user.name}"></p>
<p th:text="${user.sex}"></p>
<p th:text="${user.age}"></p>
</div>

如果父标签没有通过 th:object 选择对象,*{…} 与 ${… 的效果相同:

<div>
<p th:text="${user.name}"></p>
<!-- 等效于 -->
<p th:text="*{user.name}"></p>
</div>

3. 链接表达式 @{…}

链接表达式可以用来处理 URL。

<!-- 绝对地址 -->
<a th:href="@{https://www.baidu.com}">百度</a>

<!-- 相对地址 -->
<a th:href="@{/commons/base.html}">公共页面</a>

4. 片段表达式 ~{…}

片段表达式可用于复用公共 HTML 代码片段。

先在 base.html 中使用 th:fragment 标记公共代码:

<div id="greet" th:fragment="greetFragment">你好</div>

然后在 index.html 中引用:

<div th:insert="~{base :: greetFragment}"></div>

th:insert 会保留当前标签,渲染结果如下:

<div>
<div id="greet">你好</div>
</div>

当文件不在同一级目录时,例如 templates/commons/base.html 与 templates/index.html,可以这样引用:

<div th:insert="~{commons/base :: greetFragment}"></div>

定义片段时还可以声明参数:

<div th:fragment="crumbs(parent, child)">
<i th:text="${parent}"></i>
<i th:text="${child}"></i>
</div>

<div th:insert="~{:: crumbs('用户中心', '我的订单')}"></div>

也可以使用 ID 或类选择器引用片段:

<div th:insert="~{base :: #greet}"></div>

th:replace 和 th:insert 都可以引用片段,但效果不同:th:insert 会保留当前标签,th:replace 会用片段直接替换当前标签。

三、文本操作

1. 字符串拼接

可以使用 + 拼接字符串:

<p th:text="'Welcome to ' + ${location} + '!'"></p>

2. 字面值替换

也可以使用竖线 |…| 直接嵌入变量:

<p th:text="|Welcome to ${location}!|"></p>

四、使用文本

1. th:text

th:text 会替换标签中的文本内容,并对其中的 HTML 标签进行转义。

<p th:text="你好!"></p>

2. th:utext

th:utext 与 th:text 的区别在于:th:utext 不会转义 HTML 标签。因此当 message = “Welcome to Beijing!“ 时:

<p th:utext="${message}"></p>
<p th:text="${message}"></p>
  • th:utext 的结果:Welcome to Beijing!
  • th:text 的结果:Welcome to Beijing!

使用 th:utext 渲染外部输入时要注意 XSS 风险,确保内容可信或已经过清理。

五、遍历

使用 th:each 可以遍历数组、集合等数据。下面的 city 是自定义变量名,cities 是后端传入的城市对象数组。

<div>
<span>城市:</span>
<select name="city">
<option th:each="city : ${cities}" th:text="${city.name}"></option>
</select>
</div>

此时可以通过 city.属性名 获取对象中的属性值。

六、条件判断

1. th:if

当表达式的结果为真时显示内容,否则不显示:

<p th:if="${user.isVip == true}">VIP</p>

常见的判断规则如下:

  • 值为 null 时,结果为假。
  • 布尔值为 true 时,结果为真。
  • 数字非 0 时,结果为真。
  • 字符非 0 时,结果为真。
  • 字符串不是 “false”、”off” 或 “no” 时,结果为真。
  • 其他非空对象通常视为真。

2. th:unless

th:unless 与 th:if 相反:当表达式为假时显示内容。

3. th:switch 与 th:case

当 switch 表达式满足某个 case 时,才显示对应标签。

<div th:switch="${user.role}">
<p th:case="admin">管理员</p>
<p th:case="user">普通用户</p>
</div>

七、内联表达式

内联表达式允许我们直接在 HTML 文本中使用标准表达式,而不需要使用 th: 开头的标签属性。

1. [[…]]

[[…]] 相当于 th:text,会对 HTML 标签自动进行转义。

<p>[[${htmlContent}]]</p>

2. [(…)]

[(…)] 相当于 th:utext,不会对 HTML 标签进行转义。

<p>[(${htmlContent})]</p>

3. th:inline

th:inline 可以设置不同的内联模式。

none

设置为 none 时会禁用内联表达式,页面会原样输出 [[…]] 和 [(…)]。

text

文本内联模式中可以使用 th:each 等高级语法:

<p th:inline="text">
[# th:each="city : ${cities}"]
[(${city.name})]
[/]
</p>

css

样式内联:

<style th:inline="css">
body {
background-color: [[${bgColor}]];
}
</style>

javascript

脚本内联:

<script th:inline="javascript">
const user = [[${user}]];
alert("用户名:" + user.name);
</script>

总结

掌握表达式、片段、循环、条件判断和内联语法后,就可以用 Thymeleaf 高效地将后端数据渲染到 HTML 页面中。实际项目中建议优先使用 th:text,仅在确认内容安全时使用 th:utext。