Thymeleaf教程
# 一、Thymeleaf 基础概念
# 1.1 什么是 Thymeleaf?
Thymeleaf 是一个现代化的服务器端 Java 模板引擎,用于生成 HTML、XML、JavaScript、CSS 等格式的文档。与其他模板引擎相比,Thymeleaf 的主要特点是能够在没有后端服务器的情况下直接在浏览器中打开并查看静态效果,这使得前端开发人员可以独立于后端进行页面开发。
# 1.2 核心优势
自然模板:Thymeleaf 的模板就是有效的 HTML 文件,可以直接在浏览器中打开查看静态效果。 与 Spring 集成良好:是 Spring Boot 官方推荐的模板引擎。 强大的表达式语言:支持 OGNL、Spring EL 等多种表达式语言。 支持多种视图层技术:可以与 JSP、Freemarker 等共存。
# 二、环境搭建
# 2.1 在 Spring Boot 中集成 Thymeleaf
如果你使用的是 Spring Boot 项目,只需要在 pom.xml 中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2
3
4
# 2.2 配置文件
默认情况下,Thymeleaf 模板文件位于 src/main/resources/templates 目录下,静态资源位于 src/main/resources/static 目录下。
在 application.properties 中可以进行一些自定义配置:
properties
# 模板前缀
spring.thymeleaf.prefix=classpath:/templates/
# 模板后缀
spring.thymeleaf.suffix=.html
# 是否缓存模板,开发阶段建议设置为 false
spring.thymeleaf.cache=false
2
3
4
5
6
7
# 三、基本语法
# 3.1 标准表达式
Thymeleaf 提供了多种表达式语法,最常用的是 ${...} 和 *{...}:
${...}:变量表达式,用于访问上下文变量。 *{...}:选择变量表达式,用于访问当前选择的对象。
# 3.2 文本替换
使用 th:text 属性可以替换标签内的文本内容:
<p th:text="${message}">默认文本</p>
# 3.3 属性修改
使用 th:attr 可以修改标签的任意属性:
<img th:src="@{/images/logo.png}" alt="Logo">
<a th:href="@{/user/{id}(id=${user.id})}">查看用户</a>
2
# 3.4 条件判断
使用 th:if 和 th:unless 进行条件渲染:
<div th:if="${user.age >= 18}">成年人</div>
<div th:unless="${user.age >= 18}">未成年人</div>
2
# 3.5 循环遍历
使用 th:each 进行列表或数组的遍历:
<table>
<tr th:each="user : ${users}">
<td th:text="${user.id}">ID</td>
<td th:text="${user.name}">姓名</td>
<td th:text="${user.age}">年龄</td>
</tr>
</table>
2
3
4
5
6
7
# 3.6 模板布局
Thymeleaf 支持模板布局,可以定义公共的页面结构:
<!-- 定义模板 -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${title}">默认标题</title>
<th:block th:replace="fragments/head :: head"></th:block>
</head>
<body>
<div th:replace="fragments/header :: header"></div>
<div th:insert="~{::content}">主体内容</div>
<div th:replace="fragments/footer :: footer"></div>
</body>
</html>
<!-- 使用模板 -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
th:replace="base :: layout(~{::content})">
<head>
<title>首页</title>
</head>
<body>
<div th:fragment="content">
<h1>欢迎来到首页</h1>
</div>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 四、内置对象
# 4.1 常用内置对象
Thymeleaf 提供了一些内置对象,可以在模板中直接使用:
- #ctx:上下文对象。
- #vars:上下文变量。
- #locale:区域设置。
- #request:HTTP 请求对象(仅在 Web 上下文中可用)。
- #response:HTTP 响应对象(仅在 Web 上下文中可用)。
- #session:HTTP 会话对象(仅在 Web 上下文中可用)。
- #servletContext:Servlet 上下文对象(仅在 Web 上下文中可用)。
# 4.2 使用示例
<p>当前语言: <span th:text="${#locale.language}">en</span></p>
<p>请求路径: <span th:text="${#request.requestURI}">/home</span></p>
<p>会话 ID: <span th:text="${#session.id}">123456</span></p>
2
3
# 五、字符串操作
# 5.1 字符串拼接
<p th:text="'欢迎 ' + ${user.name} + ',您的年龄是 ' + ${user.age} + ' 岁。'">默认文本</p>
# 5.2 字符串格式化
<p th:text="${#strings.capitalize(user.name)}">默认文本</p>
<p th:text="${#strings.toUpperCase(user.name)}">默认文本</p>
<p th:text="${#strings.toLowerCase(user.name)}">默认文本</p>
<p th:text="${#strings.length(user.name)}">默认文本</p>
<p th:text="${#strings.isEmpty(user.name)}">默认文本</p>
2
3
4
5
# 六、日期处理
# 6.1 日期格式化
<p th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}">默认日期</p>
<p th:text="${#dates.format(user.birthday, 'dd/MM/yyyy HH:mm')}">默认日期</p>
2
# 6.2 日期计算
<p th:text="${#dates.createNow()}">当前日期</p>
<p th:text="${#dates.add(user.birthday, 7)}">一周后的日期</p>
<p th:text="${#dates.year(user.birthday)}">年份</p>
<p th:text="${#dates.month(user.birthday)}">月份</p>
<p th:text="${#dates.day(user.birthday)}">日期</p>
2
3
4
5
# 七、表单处理
# 7.1 表单绑定
<form action="#" th:action="@{/user/save}" th:object="${user}" method="post">
<input type="text" th:field="*{name}" placeholder="姓名">
<input type="number" th:field="*{age}" placeholder="年龄">
<input type="email" th:field="*{email}" placeholder="邮箱">
<button type="submit">提交</button>
</form>
2
3
4
5
6
# 7.2 表单验证错误显示
<form action="#" th:action="@{/user/save}" th:object="${user}" method="post">
<input type="text" th:field="*{name}" placeholder="姓名">
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}">姓名错误</span>
<input type="number" th:field="*{age}" placeholder="年龄">
<span th:if="${#fields.hasErrors('age')}" th:errors="*{age}">年龄错误</span>
<button type="submit">提交</button>
</form>
2
3
4
5
6
7
8
9
# 八、AJAX 集成
# 8.1 使用 jQuery 进行 AJAX 请求
Thymeleaf 模板可以与 jQuery 结合使用,实现 AJAX 请求:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>AJAX 示例</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
</head>
<body class="bg-gray-100 min-h-screen">
<div class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-6">用户列表</h1>
<div id="userList" class="bg-white rounded-lg shadow-md p-6">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold">用户列表</h2>
<button id="refreshBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded transition-all duration-300 flex items-center">
<i class="fa fa-refresh mr-2"></i> 刷新
</button>
</div>
<div class="loading hidden">
<i class="fa fa-spinner fa-spin text-blue-500 text-xl"></i> 加载中...
</div>
<div id="usersContainer">
<!-- 用户列表将通过 AJAX 加载到这里 -->
</div>
</div>
</div>
<script>
$(document).ready(function() {
// 页面加载完成后立即加载用户列表
loadUsers();
// 为刷新按钮绑定点击事件
$('#refreshBtn').on('click', function() {
loadUsers();
});
// 加载用户列表的函数
function loadUsers() {
// 显示加载状态
$('.loading').removeClass('hidden');
$('#usersContainer').addClass('opacity-50 transition-opacity duration-300');
// 发送 AJAX 请求
$.ajax({
url: '/api/users',
method: 'GET',
dataType: 'json',
success: function(data) {
// 请求成功,渲染用户列表
renderUserList(data);
},
error: function(error) {
// 请求失败,显示错误信息
$('#usersContainer').html('<div class="text-red-500">加载用户列表失败: ' + error.statusText + '</div>');
},
complete: function() {
// 请求完成,隐藏加载状态
$('.loading').addClass('hidden');
$('#usersContainer').removeClass('opacity-50');
}
});
}
// 渲染用户列表的函数
function renderUserList(users) {
if (users && users.length > 0) {
let html = '<table class="min-w-full divide-y divide-gray-200">';
html += '<thead class="bg-gray-50">';
html += '<tr>';
html += '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>';
html += '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">姓名</th>';
html += '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">年龄</th>';
html += '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">邮箱</th>';
html += '<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>';
html += '</tr>';
html += '</thead>';
html += '<tbody class="bg-white divide-y divide-gray-200">';
users.forEach(function(user) {
html += '<tr class="hover:bg-gray-50 transition-colors duration-200">';
html += '<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">' + user.id + '</td>';
html += '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">' + user.name + '</td>';
html += '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">' + user.age + '</td>';
html += '<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">' + user.email + '</td>';
html += '<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">';
html += '<button class="text-indigo-600 hover:text-indigo-900 mr-3 transition-colors duration-200">';
html += '<i class="fa fa-edit mr-1"></i> 编辑';
html += '</button>';
html += '<button class="text-red-600 hover:text-red-900 transition-colors duration-200">';
html += '<i class="fa fa-trash mr-1"></i> 删除';
html += '</button>';
html += '</td>';
html += '</tr>';
});
html += '</tbody>';
html += '</table>';
$('#usersContainer').html(html);
} else {
$('#usersContainer').html('<div class="text-center py-8 text-gray-500">暂无用户数据</div>');
}
}
});
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111