Thymeleaf 模板引擎:快速构建 Spring Boot Web 视图
各位看官,大家好!今天咱们来聊聊 Thymeleaf,这玩意儿可不是什么新出的神奇药草,而是 Spring Boot 里边构建 Web 视图的一把利器。如果你还在为 JSP 的那些糟心事儿烦恼,或者想找个更优雅、更现代的方式来渲染你的 Web 页面,那么 Thymeleaf 绝对值得你驻足停留。
话说 Thymeleaf,它到底是个啥?
简单来说,Thymeleaf 是一种服务器端的 Java 模板引擎,它的目标是提供一种优雅、可维护的方式来创建 Web 页面。它最大的特点就是自然模板 (Natural Templating),这意味着你的模板文件可以直接在浏览器中打开预览,无需启动服务器,这对于前端开发人员来说简直是福音!
想象一下,你写了一个 HTML 页面,里面加了一些 Thymeleaf 的标签,这些标签在浏览器中会被忽略,页面仍然可以正常显示。但是,当 Spring Boot 应用运行起来后,Thymeleaf 引擎会解析这些标签,并将它们替换成动态数据,最终呈现给用户一个完整的、动态的 Web 页面。
Thymeleaf 的优势,那可是杠杠的!
- 自然模板: 如上所述,直接在浏览器中预览,方便开发和调试。
- 与 Spring Boot 无缝集成: Spring Boot 提供了对 Thymeleaf 的自动配置,使用起来非常方便。
- 强大的表达式语言: Thymeleaf 使用 OGNL (Object-Graph Navigation Language) 表达式语言,可以轻松访问 Java 对象和属性。
- 丰富的特性: 支持循环、条件判断、模板布局、消息国际化等等,满足各种 Web 开发需求。
- 良好的性能: Thymeleaf 经过优化,性能表现不错,可以满足大多数 Web 应用的需求。
- 易于学习: Thymeleaf 的语法相对简单,容易上手。
- 安全: Thymeleaf 默认启用 HTML 转义,可以防止 XSS 攻击。
说了这么多,不如来点实际的:Thymeleaf 的入门之旅
要开始使用 Thymeleaf,我们需要先创建一个 Spring Boot 项目。这里假设你已经安装了 JDK 和 Maven,并且对 Spring Boot 有一定的了解。
-
创建 Spring Boot 项目:
可以使用 Spring Initializr ( https://start.spring.io/ ) 创建一个 Spring Boot 项目,选择 Web 和 Thymeleaf 依赖。
或者,使用 Maven 手动创建项目,并在pom.xml
文件中添加以下依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
-
创建一个 Controller:
创建一个简单的 Controller,用于将数据传递给 Thymeleaf 模板。
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HelloController { @GetMapping("/hello") public String hello(Model model) { model.addAttribute("message", "Hello, Thymeleaf!"); model.addAttribute("currentTime", new java.util.Date()); return "hello"; } }
这段代码定义了一个
HelloController
,它有一个/hello
映射。当用户访问/hello
路径时,该方法会将 "Hello, Thymeleaf!" 字符串和当前时间添加到Model
对象中,并将视图名称设置为 "hello"。 -
创建一个 Thymeleaf 模板:
在
src/main/resources/templates
目录下创建一个名为hello.html
的 Thymeleaf 模板文件。<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Hello Thymeleaf</title> </head> <body> <h1 th:text="${message}"></h1> <p>Current Time: <span th:text="${currentTime}"></span></p> </body> </html>
注意
xmlns:th="http://www.thymeleaf.org"
这个声明,它告诉浏览器这是一个 Thymeleaf 模板,并且使用th
命名空间来定义 Thymeleaf 属性。th:text="${message}"
表示将message
变量的值填充到<h1>
标签中。
th:text="${currentTime}"
表示将currentTime
变量的值填充到<span>
标签中。 -
运行 Spring Boot 应用:
运行 Spring Boot 应用,然后在浏览器中访问
http://localhost:8080/hello
。你应该能看到 "Hello, Thymeleaf!" 和当前时间显示在页面上。
Thymeleaf 语法速览,让你如虎添翼
Thymeleaf 提供了丰富的语法,可以满足各种 Web 开发需求。下面是一些常用的语法:
-
变量表达式 (
${...}
): 用于访问 Java 对象和属性。<p th:text="${user.name}"></p> <!-- 访问 user 对象的 name 属性 --> <p th:text="${user.address.city}"></p> <!-- 访问 user 对象 address 对象的 city 属性 -->
-
*选择变量表达式 (`{…}
):** 通常与
th:object` 属性一起使用,用于简化变量表达式。<div th:object="${user}"> <p th:text="*{name}"></p> <!-- 等价于 th:text="${user.name}" --> <p th:text="*{address.city}"></p> <!-- 等价于 th:text="${user.address.city}" --> </div>
-
消息表达式 (
#{...}
): 用于访问消息资源文件,实现国际化。<p th:text="#{welcome.message}"></p> <!-- 从消息资源文件中获取 welcome.message 对应的值 -->
-
URL 表达式 (
@{...}
): 用于构建 URL。<a th:href="@{/products/{id}(id=${product.id})}">View Product</a> <!-- 构建一个 URL,其中 id 是 product.id 的值 --> <link rel="stylesheet" th:href="@{/css/style.css}"> <!-- 引用静态资源 -->
-
字面量: Thymeleaf 支持多种字面量,包括文本、数字、布尔值和 null。
<p th:text="'Hello, World!'"></p> <!-- 文本字面量 --> <p th:text="123"></p> <!-- 数字字面量 --> <p th:text="true"></p> <!-- 布尔值字面量 --> <p th:text="null"></p> <!-- null 字面量 -->
-
字符串连接: 可以使用
+
号连接字符串。<p th:text="'Hello, ' + ${user.name} + '!'"></p>
-
算术运算: Thymeleaf 支持基本的算术运算,包括加、减、乘、除和取模。
<p th:text="${price * quantity}"></p>
-
比较和逻辑运算: Thymeleaf 支持比较运算符 (>, <, >=, <=, ==, !=) 和逻辑运算符 (and, or, not)。
<p th:if="${age >= 18}">Adult</p> <p th:unless="${isAdmin}">Not Admin</p>
-
条件判断 (
th:if
,th:unless
,th:switch
,th:case
): 用于控制页面元素的显示和隐藏。<div th:if="${user != null}"> <p th:text="${user.name}"></p> </div> <div th:unless="${user == null}"> <p th:text="${user.name}"></p> </div> <div th:switch="${user.role}"> <p th:case="'ADMIN'">Administrator</p> <p th:case="'USER'">Regular User</p> <p th:case="*">Unknown Role</p> </div>
-
循环 (
th:each
): 用于遍历集合或数组。<ul> <li th:each="product : ${products}" th:text="${product.name}"></li> </ul>
-
属性设置 (
th:attr
,th:class
,th:style
, 等等): 用于设置 HTML 元素的属性。<a th:href="@{/products/{id}(id=${product.id})}" th:class="${product.available ? 'available' : 'unavailable'}">View Product</a> <div th:style="'color: ' + ${product.color}"></div>
-
片段插入 (
th:insert
,th:replace
,th:include
): 用于将其他模板文件的片段插入到当前模板中。假设我们有一个
fragments.html
文件,其中包含一个名为footer
的片段:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Fragments</title> </head> <body> <div th:fragment="footer"> © 2023 My Company </div> </body> </html>
然后,我们可以在另一个模板文件中使用
th:insert
、th:replace
或th:include
来插入这个片段:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>My Page</title> </head> <body> <h1>My Page</h1> <div th:insert="~{fragments :: footer}"></div> <!-- 将 footer 片段插入到当前 div 中 --> <div th:replace="~{fragments :: footer}"></div> <!-- 将当前 div 替换为 footer 片段 --> <div th:include="~{fragments :: footer}"></div> <!-- 将 footer 片段的内容包含到当前 div 中,不包含 fragment 标签本身 --> </body> </html>
~{fragments :: footer}
表示引用fragments.html
文件中的footer
片段。
Thymeleaf 进阶,让你更上一层楼
除了上面介绍的基本语法,Thymeleaf 还提供了许多高级特性,可以帮助你构建更复杂的 Web 应用程序。
-
模板布局 (Layout Dialect): Thymeleaf 提供了强大的模板布局功能,可以让你轻松创建统一的页面结构。你可以定义一个主模板,然后在其他模板中继承它,并覆盖其中的某些区域。
首先,我们需要添加
thymeleaf-layout-dialect
依赖:<dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> </dependency>
然后,创建一个主模板文件,例如
layout.html
:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> <head> <meta charset="UTF-8"> <title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">My App</title> <link rel="stylesheet" th:href="@{/css/style.css}"> </head> <body> <header> <h1>My App</h1> </header> <div layout:fragment="content"> <!-- Content will be inserted here --> </div> <footer> © 2023 My Company </footer> </body> </html>
layout:title-pattern
用于定义页面标题的格式。
layout:fragment="content"
定义了一个名为content
的片段,其他模板可以覆盖这个片段。接下来,创建一个子模板文件,例如
home.html
:<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}"> <head> <title>Home</title> </head> <body> <div layout:fragment="content"> <h2>Welcome to My App!</h2> <p>This is the home page.</p> </div> </body> </html>
layout:decorate="~{layout}"
表示继承layout.html
模板。
layout:fragment="content"
表示覆盖layout.html
模板中的content
片段。在 Controller 中,返回
home
视图即可:@Controller public class HomeController { @GetMapping("/") public String home() { return "home"; } }
-
自定义 Dialect: 如果你需要扩展 Thymeleaf 的功能,可以创建自定义 Dialect。Dialect 是一组处理器,可以处理特定的属性或标签。
-
Spring Security 集成: Thymeleaf 可以与 Spring Security 集成,实现基于角色的访问控制。
首先,需要添加 Spring Security 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
然后,配置 Spring Security:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests((authz) -> authz .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().permitAll() ) .formLogin(); return http.build(); } }
这段代码配置了 Spring Security,要求访问
/admin/**
路径需要ADMIN
角色。最后,在 Thymeleaf 模板中使用 Spring Security 的标签:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> <head> <meta charset="UTF-8"> <title>My Page</title> </head> <body> <div sec:authorize="hasRole('ADMIN')"> <p>Welcome, Administrator!</p> </div> <a th:href="@{/logout}">Logout</a> </body> </html>
sec:authorize="hasRole('ADMIN')"
表示只有具有ADMIN
角色的用户才能看到该<div>
元素。
Thymeleaf 的最佳实践,助你少走弯路
- 保持模板简洁: 避免在模板中编写复杂的逻辑,尽量将逻辑放在 Controller 或 Service 层处理。
- 使用片段: 将常用的页面元素抽取成片段,方便复用。
- 合理使用缓存: Thymeleaf 支持模板缓存,可以提高性能。
- 使用 HTML 转义: Thymeleaf 默认启用 HTML 转义,可以防止 XSS 攻击。如果需要输出原始 HTML,可以使用
th:utext
属性。 - 使用 IDE 支持: 许多 IDE 都提供了对 Thymeleaf 的支持,可以提供代码补全、语法检查等功能。
Thymeleaf 的注意事项,避免踩坑
- 命名空间声明: 确保在模板文件中声明了 Thymeleaf 命名空间 (
xmlns:th="http://www.thymeleaf.org"
)。 - 表达式语法: Thymeleaf 使用 OGNL 表达式语言,需要熟悉 OGNL 的语法。
- 静态资源访问: 需要正确配置静态资源的访问路径。
- 错误处理: Thymeleaf 提供了异常处理机制,可以捕获和处理模板解析过程中发生的错误。
总结:Thymeleaf,你值得拥有!
Thymeleaf 是一种强大、灵活的 Java 模板引擎,它可以帮助你快速构建 Spring Boot Web 视图。它具有自然模板、与 Spring Boot 无缝集成、强大的表达式语言等优点。如果你正在寻找一种更优雅、更现代的方式来渲染你的 Web 页面,那么 Thymeleaf 绝对值得你尝试。
希望这篇文章能帮助你入门 Thymeleaf,并掌握其基本用法。当然,Thymeleaf 的功能远不止这些,还有许多高级特性等待你去探索。祝你在 Thymeleaf 的世界里玩得开心!
最后,记住一点:写代码就像谈恋爱,选择一个适合自己的,才能长长久久! Thymeleaf,或许就是你 Web 开发旅途中的那个“她/他”。加油!