Thymeleaf 语法全面详解:从入门到精通(史上最全)

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:insertth: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>

四、性能优化技巧

  1. 缓存模板:在生产环境中启用模板缓存

    spring.thymeleaf.cache=true
    
  2. 使用片段缓存

    <div th:replace="~{fragments/menu :: main-menu}" th:cacheable="true"></div>
    
  3. 避免复杂表达式:尽量减少模板中的复杂逻辑

  4. 合理使用内联:只在必要时使用内联表达式

  5. 预编译模板:在构建时预编译模板

五、常见问题解决方案

  1. 表达式不解析

    • 确保 HTML 文件有 xmlns:th="http://www.thymeleaf.org" 声明
    • 检查表达式语法是否正确
  2. 表单绑定失败

    • 确保表单有 th:object 属性
    • 检查字段名称是否匹配
  3. 国际化消息不显示

    • 检查消息文件位置和命名
    • 确保有正确的区域设置解析器
  4. 片段无法加载

    • 检查片段路径是否正确
    • 确保片段文件存在
  5. 性能问题

    • 启用模板缓存
    • 减少模板中的复杂逻辑

六、最佳实践

  1. 保持模板简洁:将复杂逻辑移到控制器或服务层

  2. 合理组织模板

    • 使用片段组织可重用部分
    • 创建布局模板
  3. 使用注释

    <!--/* 这是服务器端可见的注释 */-->
    <!-- 这是客户端可见的注释 -->
    
  4. 安全性考虑

    • 使用 th:text 而不是 th:utext 除非必要
    • 对用户输入进行适当转义
  5. 测试模板

    • 编写模板测试用例
    • 验证不同条件下的输出

通过掌握这些 Thymeleaf 语法和技巧,您可以创建灵活、高效且易于维护的模板。记住,模板的主要职责是展示数据,复杂的业务逻辑应该放在 Java 代码中。

喜欢的点个关注,想了解更多的可以关注微信公众号 “Eric的技术杂货库” ,提供更多的干货以及资料下载保存!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clf丶忆笙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值