Thymeleaf 语法全面详解(史上最全)
itomcoil 2025-06-15 16:59 9 浏览
Thymeleaf 是一个现代化的服务器端 Java 模板引擎,支持 HTML、XML、JavaScript、CSS 甚至纯文本。以下是 Thymeleaf 语法的全面详解,包含所有属性和复杂用法。
一、基础语法
1. 标准表达式语法
Thymeleaf 提供了多种表达式类型:
<p th:text="${message}">默认消息</p>
1.1 变量表达式 ${...}
用于访问变量和模型属性:
<span th:text="${user.name}">用户名</span>
1.2 选择表达式 *{...}
用于选择当前选择的对象:
<div th:object="${user}">
<p th:text="*{name}">姓名</p>
<p th:text="*{age}">年龄</p>
</div>
1.3 消息表达式 #{...}
用于国际化消息:
<p th:text="#{welcome.message}">欢迎消息</p>
1.4 链接表达式 @{...}
用于 URL 链接:
<a th:href="@{/user/details(id=${user.id})}">用户详情</a>
1.5 片段表达式 ~{...}
用于模板片段:
<div th:insert="~{commons :: footer}"></div>
2. 字面量
- 文本字面量: '单引号内容'
- 数字字面量: 123, 3.14
- 布尔字面量: true, false
- null 字面量: null
<span th:text="'固定文本'"></span>
<span th:text="2019"></span>
<span th:text="true"></span>
3. 文本操作
- 字符串连接: +
- 字面量替换: |...|
<span th:text="'欢迎 ' + ${user.name}"></span>
<span th:text="|欢迎 ${user.name}|"></span>
4. 算术运算
- 基本运算: +, -, *, /, %
<span th:text="${count + 1}"></span>
5. 布尔运算
- 比较: >, <, >=, <=, ==, !=
- 逻辑运算: and, or, !, not
<div th:if="${user.age > 18}">成年人</div>
<div th:unless="${not user.active}">活跃用户</div>
6. 条件运算
- if-then: (if) ? (then)
- if-then-else: (if) ? (then) : (else)
- 默认值: (value) ?: (defaultvalue)
<span th:text="${user.admin} ? '管理员' : '普通用户'"></span>
<span th:text="${user.name} ?: '匿名用户'"></span>
二、Thymeleaf 属性详解
1. 核心属性
th:text
设置元素的文本内容,会转义 HTML 标签:
<p th:text="${htmlContent}">默认文本</p>
th:utext
设置元素的文本内容,不转义 HTML 标签:
<p th:utext="${htmlContent}">默认文本</p>
th:value
设置表单元素的值:
<input type="text" th:value="${user.name}" />
th:with
定义局部变量:
<div th:with="first=${user.firstName}, last=${user.lastName}">
<span th:text="${first}"></span>
<span th:text="${last}"></span>
</div>
th:attr
设置任意属性:
<img th:attr="src=@{/images/logo.png}, title=${logoTitle}, alt=${logoAlt}" />
2. 条件属性
th:if/ th:unless
条件显示元素:
<div th:if="${user.admin}">管理员面板</div>
<div th:unless="${user.blocked}">正常用户</div>
th:switch/ th:case
多条件选择:
<div th:switch="${user.role}">
<p th:case="'admin'">管理员</p>
<p th:case="'manager'">经理</p>
<p th:case="*">普通用户</p>
</div>
3. 循环属性
th:each
循环遍历:
<ul>
<li th:each="item : ${items}" th:text="${item.name}">项目名称</li>
</ul>
循环状态变量:
<table>
<tr th:each="user, stat : ${users}">
<td th:text="${stat.index}">序号</td>
<td th:text="${user.name}">姓名</td>
<td th:text="${stat.odd} ? '奇数行' : '偶数行'">行类型</td>
</tr>
</table>
4. 模板布局属性
th:insert
插入模板片段:
<div th:insert="~{fragments/header :: main-header}"></div>
th:replace
替换当前元素为模板片段:
<footer th:replace="~{fragments/footer :: main-footer}"></footer>
th:include
包含模板片段的内容(已废弃,推荐使用 th:insert 或 th:replace)
5. 表单属性
th:field
绑定表单字段:
<input type="text" th:field="*{name}" />
th:action
设置表单提交地址:
<form th:action="@{/user/save}" method="post">
<!-- 表单内容 -->
</form>
th:object
设置表单绑定对象:
<form th:object="${user}" method="post">
<input type="text" th:field="*{name}" />
<input type="text" th:field="*{email}" />
</form>
6. 链接和 URL 属性
th:href
设置链接地址:
<a th:href="@{/user/{id}/profile(id=${user.id})}">用户资料</a>
th:src
设置资源地址:
<img th:src="@{/images/logo.png}" />
7. 片段表达式属性
th:remove
移除模板片段:
<table>
<tr th:remove="all">
<td>将被移除的行</td>
</tr>
<tr th:remove="all-but-first">
<td>第一行保留</td>
</tr>
</table>
可选值:
- all:移除当前标签及其所有子标签
- body:不移除当前标签但移除所有子标签
- tag:移除当前标签但不移除子标签
- all-but-first:移除除第一个外的所有子标签
- none:什么都不移除
8. 其他属性
th:classappend
追加 CSS 类:
<div th:classappend="${user.active} ? 'active' : 'inactive'"></div>
th:styleappend
追加样式:
<div th:styleappend="'color:' + ${user.color}"></div>
th:lang
设置语言:
<html th:lang="${#locale.language}"></html>
th:title
设置 title 属性:
<img th:title="${imageTitle}" />
th:alt
设置 alt 属性:
<img th:alt="${imageAltText}" />
th:onclick
设置 onclick 事件:
<button th:onclick="'alert(\'' + ${message} + '\')'">点击</button>
th:inline
设置内联模式:
<script th:inline="javascript">
var user = [[${user}]];
console.log(user.name);
</script>
支持的值:
- text:文本内联
- javascript:JavaScript 内联
- none:禁用内联
- dart:Dart 内联(已废弃)
三、复杂用法
1. 复杂表达式和实用对象
Thymeleaf 提供了一系列实用对象:
<p th:text="${#strings.isEmpty(user.name)}">检查是否为空</p>
<p th:text="${#lists.size(user.roles)}">角色数量</p>
<p th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">生日</p>
<p th:text="${#numbers.formatDecimal(price, 1, 2)}">格式化数字</p>
<p th:text="${#calendars.createNow()}">当前时间</p>
常用实用对象:
- #strings:字符串工具
- #numbers:数字工具
- #bools:布尔工具
- #arrays:数组工具
- #lists:列表工具
- #sets:集合工具
- #maps:映射工具
- #dates:日期工具(java.util.Date)
- #calendars:日历工具(java.util.Calendar)
- #temporals:Java8 时间工具(java.time.*)
- #objects:对象工具
- #ids:ID生成工具
2. 内联 JavaScript 和 CSS
JavaScript 内联:
<script th:inline="javascript">
var user = [[${user}]];
var message = [[#{welcome.message}]];
console.log(user.name + ": " + message);
</script>
CSS 内联:
<style th:inline="text">
.[[${mainClass}]] {
color: [[${mainColor}]];
}
</style>
3. 模板布局
定义片段:
fragments/header.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="common-header">
<meta charset="UTF-8"/>
<title th:text="${title}">默认标题</title>
</head>
使用片段:
<head th:replace="~{fragments/header :: common-header}">
<!-- 将被替换 -->
</head>
4. 参数化片段
定义带参数的片段:
<div th:fragment="alert (type, message)">
<div class="alert alert-[[${type}]]">
[[${message}]]
</div>
</div>
使用带参数的片段:
<div th:replace="~{:: alert('success', '操作成功')}"></div>
5. 高级表单处理
多复选框绑定:
<input type="checkbox" th:field="*{roles}" th:value="'ADMIN'" /> 管理员
<input type="checkbox" th:field="*{roles}" th:value="'USER'" /> 普通用户
<input type="checkbox" th:field="*{roles}" th:value="'GUEST'" /> 访客
单选按钮绑定:
<input type="radio" th:field="*{gender}" th:value="'MALE'" /> 男
<input type="radio" th:field="*{gender}" th:value="'FEMALE'" /> 女
6. 复杂条件判断
使用 Elvis 运算符:
<span th:text="${user.name} ?: '匿名用户'"></span>
安全导航运算符:
<span th:text="${user?.address?.street}"></span>
7. 集合投影和选择
集合投影:
<div th:each="name : ${#strings.listSplit(user.fullName, ' ')}">
<span th:text="${name}"></span>
</div>
集合选择:
<div th:each="user : ${users.?[age > 18]}">
<span th:text="${user.name}">成年人</span>
</div>
8. 预处理表达式
在表达式执行前进行预处理:
<p th:text="${__#{${user.lang}+'.welcome.message'}__}">欢迎消息</p>
9. 自定义属性处理器
通过方言扩展可以创建自定义属性处理器:
public class MyDialect extends AbstractProcessorDialect {
public MyDialect() {
super("My Dialect", "my", 1000);
}
@Override
public Set<IProcessor> getProcessors(String dialectPrefix) {
Set<IProcessor> processors = new HashSet<>();
processors.add(new MyAttributeTagProcessor(dialectPrefix));
return processors;
}
}
然后在模板中使用:
<div my:customattr="${value}">自定义属性</div>
四、性能优化技巧
- 缓存模板:在生产环境中启用模板缓存
- spring.thymeleaf.cache=true
- 使用片段缓存:
- <div th:replace="~{fragments/menu :: main-menu}" th:cacheable="true"></div>
- 避免复杂表达式:尽量减少模板中的复杂逻辑
- 合理使用内联:只在必要时使用内联表达式
- 预编译模板:在构建时预编译模板
五、常见问题解决方案
- 表达式不解析:
- 确保 HTML 文件有 xmlns:th="http://www.thymeleaf.org" 声明
- 检查表达式语法是否正确
- 表单绑定失败:
- 确保表单有 th:object 属性
- 检查字段名称是否匹配
- 国际化消息不显示:
- 检查消息文件位置和命名
- 确保有正确的区域设置解析器
- 片段无法加载:
- 检查片段路径是否正确
- 确保片段文件存在
- 性能问题:
- 启用模板缓存
- 减少模板中的复杂逻辑
六、最佳实践
- 保持模板简洁:将复杂逻辑移到控制器或服务层
- 合理组织模板:
- 使用片段组织可重用部分
- 创建布局模板
- 使用注释:
- <!--/* 这是服务器端可见的注释 */-->
<!-- 这是客户端可见的注释 --> - 安全性考虑:
- 使用 th:text 而不是 th:utext 除非必要
- 对用户输入进行适当转义
- 测试模板:
- 编写模板测试用例
- 验证不同条件下的输出
通过掌握这些 Thymeleaf 语法和技巧,您可以创建灵活、高效且易于维护的模板。记住,模板的主要职责是展示数据,复杂的业务逻辑应该放在 Java 代码中。
头条对markdown的文章显示不太友好,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,后期会有更多的干货以及资料下载。
相关推荐
- Java 如何从一个 List 中随机获得元素
-
概述从一个List中随机获得一个元素是有关List的一个基本操作,但是这个操作又没有非常明显的实现。本页面主要向你展示如何有效的从List中获得一个随机的元素和可以使用的一些方法。选择一个...
- 想月薪过万吗?计算机安卓开发之"集合"
-
集合的总结:/***Collection*List(存取有序,有索引,可以重复)*ArrayList*底层是数组实现的,线程不安全,查找和修改快,增和删比较慢*LinkedList*底层是...
- China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report
-
ImagegeneratedbyAITMTPOST--ChinaisclosinginontheU.S.intheAIindustry-academia-research...
- 大促系统优化之应用启动速度优化实践
-
作者:京东零售宋维飞一、前言本文记录了在大促前针对SpringBoot应用启动速度过慢而采取的优化方案,主要介绍了如何定位启动速度慢的阻塞点,以及如何解决这些问题。希望可以帮助大家了解如何定位该类问...
- MyEMS开源能源管理系统核心代码解读004
-
本期解读:计量表能耗数据规范化算法:myems/myems-normalization/meter.py代码见底部这段代码是一个用于计算和存储能源计量数据(如电表读数)的小时值的Python脚本。它主...
- Java接口与抽象类:核心区别、使用场景与最佳实践
-
Java接口与抽象类:核心区别、使用场景与最佳实践一、核心特性对比1.语法定义接口:interface关键字定义,支持extends多继承接口javapublicinterfaceDrawabl...
- 超好看 vue2.x 音频播放器组件Vue-APlayer
-
上篇文章给大家分享了视频播放器组件vue-aliplayer,这次给大家推荐一款音频插件VueAplayer。vue-aplayer一个好看又好用的轻量级vue.js音乐播放器组件。清爽漂亮的U...
- Linq 下的扩展方法太少了,MoreLinq 来啦
-
一:背景1.讲故事前几天看同事在用linq给内存中的两个model做左连接,用过的朋友都知道,你一定少不了一个叫做DefaultIfEmpty函数,这玩意吧,本来很流畅的from......
- MapReduce过程详解及其性能优化(详细)
-
从JVM的角度看Map和ReduceMap阶段包括:第一读数据:从HDFS读取数据1、问题:读取数据产生多少个Mapper??Mapper数据过大的话,会产生大量的小文件,由于Mapper是基于虚拟...
- 手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)
-
来源:Python爬虫与数据挖掘作者:霖hero前言关于Scrapy理论的知识,可以参考我的上一篇文章,这里不再赘述,直接上干货。实战演练爬取分析首先我们进入北京新发地价格行情网页并打开开发者工具,如...
- 屏蔽疯狂蜘蛛,防止CPU占用100%(mumu模拟器和雷电模拟器哪个更占用cpu)
-
站点总是某个时间段莫名的cpu100%,资源占用也不高,这就有必要怀疑爬虫问题。1.使用"robots.txt"规范在网站根目录新建空白文件,命名为"robots.txt...
- Web黑客近年神作Gospider:一款基于Go语言开发的Web爬虫,要收藏
-
小白看黑客技术文章,一定要点首小歌放松心情哈,我最爱盆栽!开始装逼!Gospider是一款运行速度非常快的Web爬虫程序,对于爱好白帽黑客的小白来说,可谓是佳作!Gospider采用厉害的Go语言开发...
- 用宝塔面板免费防火墙屏蔽织梦扫描网站
-
今天教大家在免费的基础上屏蔽织梦扫描,首先您要安装宝塔面板,然后再安装免费的防火墙插件,我用的是Nginx免费防火墙,然后打开这个插件。设置GET-URL过滤设置一条简单的宝塔面板的正则规则就可以屏蔽...
- 蜘蛛人再捞4千万美元 连续三周蝉联北美票房冠军
-
7月15日讯老马追踪票房数据的北美院线联盟今天表示,“蜘蛛人:离家日”(Spider-Man:FarFromHome)击退两部新片的挑战,连续第2周勇夺北美票房冠军,海捞4530万美元。法新...
- 夏天到了,需要提防扁虱,真是又小又恐怖的动物
-
夏天马上要到了,你知道吗,扁虱是这个夏天最危险的动物之一,很少有动物能比它还凶猛。Whenitcomestosummer'slittledangers,fewarenastiert...
- 一周热门
- 最近发表
-
- Java 如何从一个 List 中随机获得元素
- 想月薪过万吗?计算机安卓开发之"集合"
- China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report
- 大促系统优化之应用启动速度优化实践
- MyEMS开源能源管理系统核心代码解读004
- Java接口与抽象类:核心区别、使用场景与最佳实践
- 超好看 vue2.x 音频播放器组件Vue-APlayer
- Linq 下的扩展方法太少了,MoreLinq 来啦
- MapReduce过程详解及其性能优化(详细)
- 手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)