模板引擎 Thymeleaf
本教程共 48 篇 · 第 24 篇 · 更新于 2026-08-13 · 约 3 分钟阅读
本节目标:会用 Thymeleaf 在 HTML 里渲染数据、循环列表、做条件判断,并搞清什么时候该用它、什么时候该前后端分离。
模板引擎解决什么问题
页面要展示动态数据,不能写死。模板引擎的做法是:HTML 里留占位,服务端把数据填进去,渲染成完整页面再发给浏览器。
Thymeleaf 是 Spring Boot 官方推荐的模板引擎。最大特点是自然模板:模板本身是合法 HTML,直接用浏览器打开也能看,只是数据是静态的。
加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
模板文件放 src/main/resources/templates/,Spring Boot 自动识别。
第一个页面:控制器传数据
控制器往 Model 里放数据,返回视图名:
package com.example.demo.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class ProductPageController {
@GetMapping("/products")
public String products(Model model) {
model.addAttribute("title", "商品列表");
model.addAttribute("products", List.of(
new Product(1L, "键盘", 199.0),
new Product(2L, "鼠标", 99.0)));
return "products";
}
}
模板 templates/products.html:
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${title}">标题</title>
</head>
<body>
<h1 th:text="${title}">商品列表</h1>
<ul>
<li th:each="product : ${products}"
th:text="${product.name} + ' - ¥' + ${product.price}">
商品名 - 价格
</li>
</ul>
</body>
</html>
访问 /products,th:each 循环渲染每个商品,th:text 替换标签内容。
Note模板属性都带
th:前缀。浏览器打开原文件看到的是占位内容,服务端渲染后才被替换。这就是「自然模板」的含义。
核心语法速查
输出文本:th:text 转义输出,th:utext 不转义(慎用,防 XSS):
<p th:text="${user.name}">默认名字</p>
循环:th:each,循环变量加 Stat 后缀能拿序号:
<tr th:each="product, stat : ${products}">
<td th:text="${stat.count}">1</td>
<td th:text="${product.name}">商品名</td>
</tr>
条件判断:th:if 和 th:unless 成对用:
<p th:if="${product.price > 100}">贵</p>
<p th:unless="${product.price > 100}">便宜</p>
链接:th:href 配合 @{} 写 URL,自动带上下文路径:
<a th:href="@{/products/{id}(id=${product.id})}">详情</a>
表单回填:th:object 绑定对象,th:field 自动回填值:
<form th:action="@{/products}" th:object="${product}" method="post">
<input type="text" th:field="*{name}" />
<button type="submit">保存</button>
</form>
*{name} 是对象导航语法,等价于 ${product.name}。
布局复用
每个页面都复制导航栏、页脚太笨。用 th:fragment 定义公共片段,th:replace 引用。
公共片段 templates/layout.html:
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<body>
<nav th:fragment="navbar">
<a th:href="@{/}">首页</a>
<a th:href="@{/products}">商品</a>
</nav>
</body>
</html>
页面里引用:
<div th:replace="~{layout :: navbar}"></div>
~{文件名 :: 片段名} 定位片段。维护一处,全站生效。
与前后端分离怎么取舍
模板引擎属于服务端渲染(SSR)。后端返回完整 HTML,浏览器直接展示。前后端分离则是后端只出 JSON,前端框架自己渲染。
| 对比 | Thymeleaf 服务端渲染 | 前后端分离 |
|---|---|---|
| 首屏速度 | 快,一次请求拿全页面 | 慢一点,多轮请求 |
| SEO | 友好,搜索引擎能抓内容 | 依赖预渲染 |
| 前后端协作 | 耦合,改页面要动后端 | 解耦,并行开发 |
| 适用场景 | 后台管理、内容站 | 复杂交互应用、App 接口 |
怎么选,看产品形态:
- 内部管理系统、博客内容站:Thymeleaf 够用,开发快。
- 重交互的 C 端应用、要同时服务 App:接口 + 前端框架,Thymeleaf 只做兜底页(错误页、登录页)。
- 混合模式很常见:主功能前后端分离,管理后台用模板。
TipSpring Boot 4.x 对 Thymeleaf 的自动配置很完整:模板目录、缓存、编码都能用
spring.thymeleaf.*配置调整。开发时建议spring.thymeleaf.cache=false,改模板不用重启。
本节小结
- Thymeleaf 是 Spring Boot 默认模板引擎,模板放 templates/。
- th:text 输出、th:each 循环、th:if 判断、@{} 写链接。
- th:fragment + th:replace 做布局复用。
- 后台管理、内容站适合服务端渲染;重交互应用走前后端分离。