Thymeleaf 基础概述
什么是 Thymeleaf
Thymeleaf 是现代 Java 服务端模板引擎,支持 Web / 独立环境,可解析 HTML、XML、JS、CSS、纯文本 6 种模板模式,核心亮点是自然模板(Natural Templating):
模板本身是合法 HTML,浏览器直接打开可作为静态原型;后端渲染时才解析th:*动态属性,解决前后端协作割裂问题,完全兼容 HTML5 规范。
六大模板模式
方言(Dialect)体系
方言 = 一组标签 / 属性处理器集合,Thymeleaf 核心内置标准方言,日常开发完全够用;
Spring 项目使用
SpringStandardDialect,将 OGNL 替换为 SpringEL,语法几乎一致;两种书写规范(完全等价):
命名空间写法(教程主推):
th:text,需声明xmlns:th="http://www.thymeleaf.org"HTML5 规范写法:
data-th-text,无需额外命名空间,更符合 W3C 标准
<!-- 命名空间版 -->
<p th:text="${name}">默认文本</p>
<!-- HTML5标准data版 -->
<p data-th-text="${name}">默认文本</p>核心架构(TemplateEngine)
三大核心组件,渲染流程:模板解析器 → 模板引擎 → 上下文
ITemplateResolver 模板解析器
负责定位模板文件,内置 4 种实现:
WebApplicationTemplateResolver:Servlet 项目,读取/WEB-INF/templatesClassLoaderTemplateResolver:读取 classpath 下模板FileTemplateResolver:读取本地文件系统StringTemplateResolver:直接解析字符串为模板常用配置:前缀 prefix、后缀 suffix、缓存开关、缓存 TTL
WebApplicationTemplateResolver resolver = new WebApplicationTemplateResolver(app);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setCacheable(true); // 生产开启缓存,开发关闭
resolver.setCacheTTLMs(3600000L); // 缓存1小时TemplateEngine 模板引擎
核心执行类,绑定解析器、消息解析器、转换服务,调用process(模板名, 上下文, 输出流)渲染页面。
IContext 上下文
存储页面所需所有变量、区域语言;Web 专用实现WebContext,内置param/session/application快捷命名空间。
标准表达式语法(核心重点)
五大基础表达式
消息表达式 #{}(国际化)
消息文件规则:与模板同目录,
home.properties(默认)、home_zh_CN.properties(中文)支持占位传参:
# home.properties
home.welcome=欢迎你,{0}!<p th:text="#{home.welcome(${session.user.name})}">欢迎</p> 变量表达式 ${}
内置 Web 快捷命名空间(无需 #):
${param.xxx}:请求参数数组${session.xxx}:session 域属性${application.xxx}:Servlet 上下文属性内置基础对象(# 开头):
#ctx上下文、#locale语言环境内置工具对象(附录 B 全套):
#dates/#temporals/#numbers/#strings/#lists等
<!-- 日期格式化 -->
<span th:text="${#calendars.format(today,'yyyy-MM-dd')}"></span>
<!-- 字符串工具 -->
<span th:text="${#strings.isEmpty(name)?'空':'有值'}"></span>选择表达式 *{}
配合th:object绑定根对象,简化重复取值:
<div th:object="${user}">
<p th:text="*{name}"></p> <!-- 等价 ${user.name} -->
<p th:text="*{age}"></p>
</div>URL 表达式 @{}
支持 4 种 URL,自动上下文路径、参数转义:
<!-- 相对上下文 -->
<a th:href="@{/product/detail(id=${prod.id})}">详情</a>
<!-- 路径变量 -->
<a th:href="@{/user/{uid}/info(uid=${user.id})}"></a>
<!-- 服务器跨上下文 -->
<a th:href="~/admin/login"></a>片段表达式 ~{}
用于th:insert/th:replace引入公共模块,语法~{模板名::选择器}
表达式通用语法
字面量
文本:
'字符串'| 数字 / 布尔 /null:无需引号true / 123 / null字面标记:纯英文单词可省略引号
th:class="main"
字符串拼接
加号拼接:
'你好,' + ${name}竖线简化替换(推荐):
|你好,${name}|
运算与比较
算术:+ - * / %;比较:gt(>) lt(<) ge(>=) le(<=) eq(==) ne(!=)
条件表达式
三目:
${age>18}?'成年':'未成年'Elvis 默认运算符
?:(空值兜底):*{age} ?: '未知年龄'无操作符
_:直接使用原型静态文本兜底
<span th:text="${user.name} ?: _">小橙同学</span>预处理表达式 __表达式__
渲染前先替换表达式内容,动态切换逻辑;
数据转换 {{}}
${{date}}自动执行全局格式化转换服务(日期、数字格式化)。
页面属性操作(th:* 属性大全)
文本输出
th:text:转义输出(防 XSS,默认推荐)th:utext:不转义输出,支持 HTML 标签
msg=这是<b>加粗</b>文字<p th:text="#{msg}">原样输出<b></p>
<p th:utext="#{msg}">显示加粗标签</p>通用属性设置
th:attr:批量设置任意属性(少用,可读性差)
<img th:attr="src=@{img.jpg},title=#{img.title}">专用属性(推荐):th:href/th:src/th:value/th:class/th:title等
追加 / 前置属性:
th:classappend:追加 CSS 类(不覆盖原有 class)th:styleappend:追加样式
布尔属性(checked/disabled/selected 等)
<input type="checkbox" th:checked="${user.vip}">局部变量 th:with
在当前标签及子元素内定义临时变量:
<div th:with="format=#{date.format},now=${today}">
<span th:text="${#calendars.format(now,format)}"></span>
</div>循环迭代 th:each
基础用法
支持迭代:List/Set/ 数组 / Map/Iterator/Stream
<tr th:each="prod : ${productList}">
<td th:text="${prod.name}"></td>
</tr>迭代状态变量
自动携带状态,包含index(0开始)、count(1开始)、size、first、last、odd/even
<tr th:each="prod,stat : ${productList}" th:class="${stat.odd}?'odd-row'">
<td>序号:${stat.count}</td>
</tr>不手动命名时,迭代变量 +Stat自动生成:prodStat.odd
延迟加载变量
LazyContextVariable:仅当页面实际使用集合时才查询数据库,优化性能。
条件判断
th:if / th:unless
th:if:条件为 true 显示标签th:unless:条件为 false 显示(等价th:if=!表达式)判定 true 规则:非 null、非 0 数字、非 false/off/no 字符串
<a th:if="${#lists.size(prod.comments) > 0}" href="">查看评论</a>th:switch / th:case
多分支匹配,th:case="*"为默认分支
<div th:switch="${user.role}">
<p th:case="admin">管理员</p>
<p th:case="user">普通用户</p>
<p th:case="*">游客</p>
</div>模板布局与片段复用(重点工程化)
片段定义 th:fragment
<!-- footer.html -->
<div th:fragment="copyright">©2026 小橙子</div>三种引入指令区别
th:insert:将片段内容插入当前标签内部(保留父标签)
th:replace:整体替换当前标签为片段(最常用)
th:include(3.1 已弱化,不推荐)
<div th:insert="~{footer::copyright}"></div>
<div th:replace="~{footer::copyright}"></div>无 th:fragment 的片段引用
通过 CSS/id 选择器直接抓取页面元素:
<div th:replace="~{footer::#copy-id}"></div>带参数片段(函数式布局)
<!-- 通用头部片段,接收title、links两个参数 -->
<head th:fragment="commonHeader(title, links)">
<title th:replace="${title}"></title>
<th:block th:replace="${links}"></th:block>
</head>
<!-- 页面调用,传入页面自定义标题、样式片段 -->
<head th:replace="~{layout::commonHeader(~{::title}, ~{::link})}">
<title>商品列表</title>
<link rel="stylesheet" th:href="@{/list.css}">
</head>th:remove 移除元素(原型友好)
静态原型保留模拟数据,后端渲染自动删除:
all:删除标签 + 内部所有内容tag:只删标签,保留子内容all-but-first:保留第一行,删除其余模拟行(表格原型神器)
<!-- 仅原型展示,渲染自动删除 -->
<tr th:remove="all">
<td>测试商品</td>
</tr>布局继承
公共 layout 页面定义完整页面骨架,子页面替换标题、主体内容实现复用。
th:block 虚拟标签
唯一 Thymeleaf 专属合成标签,渲染后自动消失,仅承载逻辑,解决 table/tr、select/option 等不能嵌套 div 的场景:
<table>
<th:block th:each="user : ${userList}">
<tr><td th:text="${user.name}"></td></tr>
<tr><td colspan="2">备注:${user.desc}</td></tr>
</th:block>
</table>注释与内联语法
三类特殊注释
标准 HTML 注释 <!-- 渲染后保留 -->
解析级注释 <!--/* 渲染直接删除 */-->:原型也不显示
原型专用注释 <!--/*/ 渲染取消注释 /*/-->:仅静态原型隐藏,后端正常渲染
文本内联(直接写在 HTML 文字中)
[[${xxx}]]:转义输出(等同 th:text)[(${xxx})]:不转义输出(等同 th:utext)
<p>欢迎 [[${user.name}]]</p>
<!-- 关闭内联 -->
<p th:inline="none">文本[[变量]]原样展示</p>JS / CSS 内联
<script th:inline="javascript">、<style th:inline="css">
自动转义字符串、序列化 Java 对象为 JSON,支持注释式自然原型写法:
var name = /*[[${user.name}]]*/ "默认名称";属性执行优先级(同标签多 th:* 执行顺序)
同标签多个 Thymeleaf 属性按优先级从上到下执行:
th:insert /th:replace(引入片段)
th:each(循环)
th:if /th:unless /th:switch(判断)
th:object /th:with(变量绑定)
th:attr 系列(通用属性修改)
th:href /th:src 专用属性
th:text /th:utext(文本输出)
th:fragment(片段定义)
th:remove(删除元素)
高级特性
模板缓存
默认开启,缓存解析后的模板 AST 树,大幅减少 IO;开发环境建议关闭resolver.setCacheable(false),实时刷新页面。 可手动清空缓存:templateEngine.clearTemplateCache()
分离式模板逻辑(解耦 HTML 与动态逻辑)
纯静态 HTML(设计师编写)+ 独立
.th.xml逻辑文件通过 CSS 选择器注入 th:* 属性,完全分离页面结构与后端逻辑
启用开关:
resolver.setUseDecoupledLogic(true)
多解析器 / 多消息解析器
模板引擎可绑定多个解析器,按 order 顺序尝试读取模板;多消息解析器实现分层国际化。
文本模板模式(TEXT/JS/CSS 专用语法)
无 HTML 标签,使用[# th:each] [/]块语法处理纯文本、邮件模板。
开发常见避坑总结
静态原型正常,渲染丢失动态数据:检查缓存是否开启、前缀后缀路径是否正确;
JS 内联变量报错:优先使用
[[${}]]自动转义,不要直接拼接字符串;循环序号错乱:使用状态变量
stat.count而非下标;国际化不生效:消息文件名、语言后缀匹配,检查文件编码 UTF-8;
页面无法访问:
templates目录资源不能直接 URL 访问,必须走控制器跳转;HTML5 规范冲突:改用
data-th-*替代th:*命名空间写法。
附录速查
常用工具对象高频方法
#temporals:JDK8 LocalDate/LocalDateTime 格式化#dates:java.util.Date 工具#numbers金额、百分比、数字补零格式化#strings判断空、截取、大小写、转义#lists/#aggregates集合求和、平均值、判空
内置 Web 上下文对象
#ctx上下文、#locale语言、param请求参数、session会话、application全局域