在Spring Boot项目里做服务端页面渲染,Thymeleaf几乎是目前最省心的选择。它是Spring官方点名推荐的模板引擎,与Spring MVC的整合几乎零配置,语法也足够直观。这篇文章会从依赖引入、基础配置,到标签语法、实战细节,完整走一遍整合流程。

一、引入依赖与基础配置
整合的第一步是在pom.xml中加入starter依赖。Spring Boot为Thymeleaf提供了专门的starter,引入后自动配置机制会立即生效,无需手写任何Java配置类。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>这个starter内部包含了Thymeleaf本身、Spring的集成适配器以及一些默认的方言支持。引入之后,Spring Boot的自动配置类会帮我们创建好TemplateResolver、SpringTemplateEngine和ThymeleafViewResolver这三个核心Bean,它们分别负责定位模板文件、执行模板渲染和把渲染结果输出为视图。
接下来可以在application.yml中做少量个性化配置。默认情况下模板放在src/main/resources/templates目录下,静态资源放在static目录,文件后缀是.html。开发阶段建议把缓存关掉,否则每次修改页面都要重启应用才能看到效果。
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML
encoding: UTF-8
cache: false # 开发环境关闭缓存,生产环境务必改为true还有一点值得注意:Thymeleaf 3.x开始支持不严格的HTML语法,即使你的页面标签没有完全闭合也能正常解析,这一点比老的XML模式友好得多。如果你的项目使用的是较老版本,建议显式把mode设置为HTML,避免解析报错。
二、编写Controller与模板页面实现数据渲染
配置完成后,写一个简单的Controller来向页面传递数据。这里用一个用户列表的例子,通过Model对象把数据带回前端。
@Controller
public class UserController {
@GetMapping("/users")
public String listUsers(Model model) {
List<User> users = Arrays.asList(
new User("张三", 25, "北京"),
new User("李四", 30, "上海"),
new User("王五", 28, "深圳")
);
model.addAttribute("users", users);
model.addAttribute("pageTitle", "用户管理");
return "user/list"; // 对应 templates/user/list.html
}
}注意这里用的是@Controller而不是@RestController。前者方法的返回值会被解析为视图名,而后者会把返回值直接序列化成JSON写到响应体里,用错了会导致页面上出现一串JSON字符串而不是渲染好的HTML,这是新手最容易踩的坑之一。
然后创建模板文件templates/user/list.html。Thymeleaf的模板就是标准的HTML文件,只是额外引入了th命名空间,通过属性的方式嵌入动态逻辑。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title th:text="${pageTitle}">默认标题</title>
</head>
<body>
<h1 th:text="${pageTitle}">用户列表</h1>
<table border="1">
<tr>
<th>姓名</th>
<th>年龄</th>
<th>城市</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.name}">姓名占位</td>
<td th:text="${user.age}">0</td>
<td th:text="${user.city}">城市</td>
</tr>
</table>
</body>
</html>这种写法有一个非常大的优势:模板文件可以脱离服务器直接用浏览器打开预览。因为所有的动态逻辑都写在th:开头的属性里,浏览器会自动忽略这些不认识的属性,只显示标签里的静态占位内容。设计师和后端工程师可以并行工作,互不干扰,这也是Thymeleaf被称作自然模板的原因,相比FreeMarker和JSP那种必须依赖引擎才能显示的模板,开发体验要好不少。
三、常用标签语法与表达式详解
掌握几个核心标签基本就能应付大部分页面。th:text用于输出文本并自动做HTML转义,能有效防止XSS攻击;如果确实需要输出富文本,可以改用th:utext,但一定要确保数据来源可信。条件判断用th:if和th:unless, switch分支用th:switch配合th:case。
<!-- 条件判断 -->
<span th:if="${user.age} > 18">成年人</span>
<span th:unless="${user.age} > 18">未成年人</span>
<!-- switch分支 -->
<div th:switch="${user.city}">
<p th:case="'北京'">首都用户</p>
<p th:case="*">其他城市用户</p>
</div>表达式方面,标准变量表达式${...}用于访问Model中的数据,选择变量表达式*{...}需要配合th:object使用,适合表单绑定场景,可以少写很多重复的对象名前缀。URL表达式@{...}则会自动处理上下文路径,即使应用部署在子路径下,链接也不会失效。
<!-- th:object配合*{}简化写法 -->
<div th:object="${user}">
<p>姓名:<span th:text="*{name}"></span></p>
<p>年龄:<span th:text="*{age}"></span></p>
</div>
<!-- URL表达式自动拼接上下文路径 -->
<a th:href="@{/users/{id}(id=${user.id})}">查看详情</a>另外两个非常实用的功能是片段复用和内联表达式。用th:fragment定义公共片段,再用th:insert或th:replace引入,可以把页头、页脚、导航栏这类重复结构抽取出来统一维护,改动一处全局生效,这对多页面项目来说是刚需。
<!-- commons/header.html 中定义片段 -->
<header th:fragment="top">
<h1>这是公共页头</h1>
</header>
<!-- 其他页面引入 -->
<div th:replace="commons/header :: top"></div>
<!-- 内联表达式,可在文本节点内部输出变量 -->
<p>[[${user.name}]] 欢迎回来</p>四、常见问题排查与实战建议
实际使用中,最容易遇到的是模板找不到的报错,典型提示是Error resolving template。原因通常是返回的视图名与实际文件路径不一致,比如Controller返回user/list,但文件放到了templates根目录下,或者文件名大小写写错了。Linux服务器对大小写敏感,本地Windows上跑得好好的项目部署上去就报错,多半是这个原因,建议视图名和文件名保持完全一致。
第二个高频问题是改了页面不生效。除了前文提到的缓存配置,如果你使用了devtools热重启,模板缓存也需要确认是关闭状态。还有一个细节:通过mvn spring-boot:run启动和在IDE里直接run main方法,模板的加载路径行为可能略有差异,遇到诡异问题时先清一下target目录重新编译,往往能解决。
<!-- devtools热部署,可选 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>关于生产环境的建议有两条。第一,务必把spring.thymeleaf.cache设为true,模板缓存能显著降低每次请求的渲染开销,对一个访问量稍大的站点来说差距非常明显。第二,Thymeleaf的渲染是同步阻塞的,在超高并发场景下,服务端渲染的吞吐量天然不如前后端分离加静态资源CDN的架构,如果页面逻辑复杂、流量又大,可以考虑将渲染压力转移到前端,或者结合Redis缓存渲染结果做页面静态化。
最后提一下Thymeleaf的其他用武之地。它不仅能渲染网页,配合TemplateEngine还能脱离Web环境独立运行,比如生成HTML格式的邮件正文、批量产出静态HTML文件做SEO优化等。只需要手动构建一个ClassLoaderTemplateResolver指向模板目录,调用process方法传入变量即可,用法和Web场景下的原理完全一致,学会了页面上这一套,其他场景几乎是免费附赠的能力。
Spring BootThymeleaf模板引擎修改时间:2026-09-12 19:23:30