外观
Spring Boot 视图引擎
约 1558 字大约 5 分钟
2025-08-16
一、为什么需要专业视图引擎
在 Web 开发中,直接使用 JSP 或纯 HTML 静态页面存在明显问题:
- JSP 语法复杂,与 HTML 混合导致可读性差
- 静态 HTML 无法展示动态数据
- 前后端耦合度高,不利于团队协作
而专业视图引擎如 Thymeleaf 能够:
- 保持 HTML 的原始结构,便于前端开发
- 无缝集成动态数据
- 支持原型设计(HTML 文件可直接在浏览器打开预览)
二、Thymeleaf 简介
1. 什么是 Thymeleaf
Thymeleaf 是一个现代化的服务器端 Java 模板引擎,用于 Web 和独立环境。它能够处理 HTML、XML、JavaScript、CSS 甚至纯文本。
2. 为什么选择 Thymeleaf
- 自然模板:HTML 文件可直接在浏览器打开预览,无需启动服务器
- 与 Spring Boot 完美集成:官方推荐的模板引擎
- 高安全性:默认对变量进行 HTML 转义,防止 XSS 攻击
- 丰富的表达式:支持多种表达式和功能
- 布局功能:强大的模板复用机制
三、基本配置与使用
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>2. 基本配置(application.yml)
spring:
thymeleaf:
# 开发时关闭缓存,便于实时查看修改
cache: false
# 编码设置
encoding: UTF-8
# 文件后缀
suffix: .html
# 模式设置(推荐使用HTML5)
mode: HTML5注意:
mode: LEGACYHTML5已过时,新版 Spring Boot 推荐使用HTML5模式
3. 目录结构
src/main/resources/
├── static/ # 静态资源(CSS, JS, 图片等)
└── templates/ # Thymeleaf 模板文件4. 简单示例
Controller:
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "欢迎使用 Thymeleaf");
return "home";
}
}templates/home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1 th:text="${message}">默认标题</h1>
</body>
</html>四、常用表达式与语法
1. 变量表达式 ${...}
用于访问模型(Model)中的变量:
<p th:text="${user.name}">用户名</p>
<p>你好,[[${user.name}]]</p> <!-- 内联表达式 -->2. 选择表达式 *{...}
用于在选定对象上下文中求值:
<div th:object="${user}">
<p>姓名: <span th:text="*{name}"></span></p>
<p>邮箱: <span th:text="*{email}"></span></p>
</div>3. URL 表达式 @{...}
用于创建上下文相关的 URL:
<a th:href="@{/users/{id}(id=${user.id})}">用户详情</a>
<link rel="stylesheet" th:href="@{/css/style.css}">
<script th:src="@{/js/main.js}"></script>4. 常用操作符
| 操作符 | 说明 | 示例 |
|---|---|---|
+ | 字符串连接 | th:text="'Hello ' + ${name}" |
| ` | ... | ` |
?: | 默认值 | th:text="${name} ?: 'Guest'" |
> < >= <= | 比较 | th:if="${age} > 18" |
== != | 等值比较 | th:if="${role} == 'admin'" |
and or | 逻辑运算 | th:if="${age} > 18 and ${hasLicense}" |
五、常用 th 标签
1. 文本输出
| 标签 | 说明 |
|---|---|
th:text | 转义 HTML 特殊字符后输出 |
th:utext | 不转义直接输出(慎用,可能有 XSS 风险) |
<p th:text="${htmlContent}"></p> <!-- <div>Hello</div> -->
<p th:utext="${htmlContent}"></p> <!-- <div>Hello</div> -->2. 条件判断
| 标签 | 说明 |
|---|---|
th:if | 条件为 true 时显示元素 |
th:unless | 条件为 false 时显示元素 |
<div th:if="${user.admin}">管理员区域</div>
<div th:unless="${user.banned}">正常用户内容</div>3. 循环迭代
<table>
<tr th:each="user, iterStat : ${users}">
<td th:text="${iterStat.index + 1}">序号</td>
<td th:text="${user.name}">用户名</td>
<td th:text="${user.email}">邮箱</td>
</tr>
</table>状态变量(iterStat)常用属性:
index: 当前索引(从 0 开始)count: 当前计数(从 1 开始)size: 总元素数even/odd: 是否为偶数/奇数行first/last: 是否为第一个/最后一个元素
4. 属性处理
| 标签 | 说明 |
|---|---|
th:src | 处理 src 属性 |
th:href | 处理 href 属性 |
th:action | 处理 form 的 action |
th:value | 处理 value 属性 |
th:style | 处理 style 属性 |
th:title | 处理 title 属性 |
<img th:src="@{/images/logo.png}" alt="Logo">
<a th:href="@{/users/{id}(id=${user.id})}">详情</a>
<form th:action="@{/users/save}" method="post">六、布局与模板复用
1. 基本布局结构
创建通用组件(如 header.html):
<!-- templates/partials/header.html -->
<header>
<h1>网站标题</h1>
<nav>
<a th:href="@{/}">首页</a>
<a th:href="@{/about}">关于</a>
</nav>
</header>在主页面中引用:
<!-- templates/home.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>首页</title>
</head>
<body>
<div th:replace="partials/header"></div>
<main>
<h2>欢迎来到首页</h2>
</main>
<div th:replace="partials/footer"></div>
</body>
</html>2. 常用布局标签
| 标签 | 说明 |
|---|---|
th:insert | 将模板内容插入到当前标签内 |
th:replace | 用模板内容替换当前标签 |
th:include | 仅插入模板内容(不包含模板的根元素) |
<!-- 使用示例 -->
<div th:replace="partials/header :: header"></div>
<div th:insert="partials/sidebar :: menu"></div>3. 片段定义与引用
在模板中定义可重用片段:
<!-- templates/partials/header.html -->
<header th:fragment="header">
<h1>网站标题</h1>
<!-- 内容 -->
</header>
<!-- 定义带参数的片段 -->
<nav th:fragment="menu(user)">
<p th:text="'欢迎, ' + ${user.name}"></p>
<!-- 菜单项 -->
</nav>引用片段:
<div th:replace="partials/header :: header"></div>
<div th:replace="partials/header :: menu(${currentUser})"></div>七、实用技巧
1. 内联 JavaScript
<script th:inline="javascript">
/*<![CDATA[*/
var userId = [[${user.id}]];
var userName = /*[[${user.name}]]*/ 'Default Name';
/*]]>*/
console.log('用户ID: ' + userId);
console.log('用户名: ' + userName);
</script>注意:在 JavaScript 中使用
/*[[...]]*/语法可避免 IDE 报错
2. 常用内嵌工具对象
| 工具对象 | 常用方法 | 说明 |
|---|---|---|
#strings | isEmpty(), contains(), startsWith(), substring() | 字符串操作 |
#numbers | formatDecimal(), sequence() | 数字格式化 |
#dates | format(), createNow(), day() | 日期操作 |
#lists | size(), contains(), sort() | 集合操作 |
示例:
<p th:text="${#strings.isEmpty(name)} ? '名称为空' : name"></p>
<p th:text="${#dates.format(user.registrationDate, 'yyyy-MM-dd')}"></p>
<p th:text="${#lists.size(users)} 个用户"></p>3. 开发环境配置
# application-dev.yml
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
# 开启模板热重载
devtools:
restart:
enabled: true4. 多环境模板
通过 Spring Profiles 实现不同环境使用不同模板:
<!-- 开发环境专用 -->
<span th:if="${environment == 'dev'}">开发环境提示</span>
<!-- 生产环境专用 -->
<span th:if="${environment == 'prod'}">生产环境提示</span>八、常见问题
1. 如何在 HTML 中使用特殊字符
使用 th:text 或内联表达式可自动转义特殊字符:
<p th:text="'<div>Hello</div>'"></p> <!-- 显示为 <div>Hello</div> -->2. 如何格式化日期
<p th:text="${#dates.format(user.birthday, 'yyyy-MM-dd')}"></p>
<p th:text="${#dates.year(user.birthday)}年"></p>3. 如何处理空值
<p th:text="${user.nickname} ?: '未设置昵称'"></p>
<p th:text="${user.address?.city} ?: '未填写城市'"></p>4. 如何在 CSS 中使用变量
<style th:inline="css">
.user-badge {
background-color: [[${user.badgeColor}]];
}
</style>