整合 Thymeleaf 模板引擎:快速构建 Spring Boot Web 视图

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 有一定的了解。

  1. 创建 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>
  2. 创建一个 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"。

  3. 创建一个 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> 标签中。

  4. 运行 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">
            &copy; 2023 My Company
        </div>
    </body>
    </html>

    然后,我们可以在另一个模板文件中使用 th:insertth:replaceth: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>
            &copy; 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 开发旅途中的那个“她/他”。加油!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注