Springboot 与 Thymeleaf

835 阅读2分钟

准备

  1. 从 Maven 引入
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. application.yml/properties配置 实际上org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties已经有默认的配置项,例如:
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";

所以可以直接使用,暂时不用关心 ThymeleafProperties 中的配置。

  1. html 文件位置及命名空间

  2. 要使用 Thymeleaf 功能的 html 文件,都得放到如下所示 templates 目录下,刚才已经提到了Thymeleaf的一些默认配置,所以,也没必要去改变DEFAULT_PREFIX

// org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
public static final String DEFAULT_PREFIX = "classpath:/templates/";
+---main
|   +---java
|   |   \---com
|   |       \---xxx 包
|   \---resources
|       +---static
|       \---templates
  1. html文件的 html 标签引入 xmlns:th 命名空间,防止 IDE 报错缺少名称空间定义,同时也有了提示,比如使用 IDEA
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge,chrome=1">
    <title>Document</title>
</head>

先了解一下简单的表达式

  • 简单表达式
    • 变量表达式: ${...}
    • 选择变量表达式: *{...}
    • 消息表达: #{...}
    • 链接URL表达式: @{...}
    • 片段表达式: ~{...}

以下使用org.springframework.ui.Model来传递数据

文本

标签本身没有 value 属性的,如 plispan 等用 th:text 渲染,有 value 属性则用 th:value 渲染

判断

@GetMapping("judge")
public String books(Model model) {
    model.addAttribute("param", "xxx");
    return "/books";
}
<!-- 使用 th:if -->
<div th:if="${param}">
 ...
</div>

当是变量是以下情况时 th:if 判断为 false,从而不渲染元素

  1. 变量不存在
  2. 值为 null
  3. 值为 Boolean 类型的 false

循环

  1. 简单循环
@GetMapping("books")
public String books(Model model) {
    List<String> list = Arrays.asList("陸小鳳傳奇", "蘇菲的世界", "毛澤東選集");
    model.addAttribute("books", list);
    return "/books";
}
<ul>
    <li th:each="book :${books}">
        <span th:text="${book}"></span>
    </li>
</ul>
  1. 对象集合
@Getter
@Setter
@AllArgsConstructor
public class UserObj {
    private Integer id;
    private String name;
    private Integer age;
}

@GetMapping("users")
public String users(Model model) {
    UserObj lily = new UserObj(1, "Lily", 22);
    UserObj jasmine = new UserObj(2, "Jasmine", 18);
    UserObj poppy = new UserObj(3, "Poppy", 6);
    List<UserObj> list = Arrays.asList(lily, jasmine, poppy);
    // model.addAllAttributes(list);
    model.addAttribute("users", list);
    return "/user";
}
<table th:if="${users}">
    <thead>
    <tr>
        <th>ID</th>
        <th>NAME</th>
        <th>AGE</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="user,iterStat :${users}" th:class="${iterStat.odd}? 'odd'">
        <td th:text="${user.id}"></td>
        <td th:text="${user.name}"></td>
        <td th:text="${user.age}"></td>
    </tr>
    </tbody>
</table>

第二个参数 iterStat 是一个对象,是为 Thymeleaf 提供了一种有助于跟踪迭代状态的机制,其拥有以下属性:

{
    index:    "索引,从零开始", 
    cou:t:    "从一开始的索引", 
    size:     "数据总数", 
    current:  "当前循环的对象",
    even/odd: "布尔属性,当前迭代是偶数还是奇数",
    first:    "布尔属性,是否是第一个",
    last:     "布尔属性,是否为最后一个"
}

注释

<!-- 普通html注释 -->

<!--/* 被Thymeleaf解析后不显示 */-->

<!--/*/
  <div th:text="${...}">
    静态打开时不显示,被Thymeleaf解析后显示
  </div>
/*/-->

模板

例如页脚,页眉,菜单等部分做成模板以嵌入到其它页面中。

制作

例如制作一个 header 模板,在 /layout 目录下新建一个 header.html,文件内容如下所示,因为这只是一个嵌入到其它 html 的片段,所以不再写 <!DOCTYPE html> 和其它用不到的标签。

<header xmlns:th="https://www.thymeleaf.org" th:fragment="header">
...
</header>
<!-- 或者使用 id 来声明 -->
<header xmlns:th="https://www.thymeleaf.org" id="header">
...
</header>

使用

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
   ...
</head>
<body>
    <div th:replace="~{/layout/header :: header}"></div>
    <!-- 如果使用 id 声明,则加个#号 -->
    <div th:replace="~{/layout/header :: #header}"></div>
</body>
</html>

差异

th:insert th:replaceth:include 之间的差异

3.0 不推荐th:replace

以上面的使用为例

  1. th:insert 最简单:它将简单地将指定的片段作为子标签插入,即
<div>
    <header>
     ...
    </header>
</div>
  1. th:replace实际上将其标签替换为引用的片段,,即
<header>
 ...
</header>
  1. th:include与相似th:insert,但不插入片段,而是仅插入该片段的内容,即
<div>
 ...
</div>

附录

表达式基本对象

expression-basic-objects

未完待续?