Thymeleaf 模板引擎使用

模板引擎是为了使用户看到的页面与业务数据(内容)分离而产生的一种模板技术,它可以生成特定格式的文档,用于网站的模板引擎会生产出标准的 HTML 静态页面内容。在 Java Web 开发技术栈中,常见的模板引擎有 FreeMarker、Velocity、Thymeleaf 等,JSP 也可以理解为一种模板引擎技术。Thymeleaf 官方学习文档为:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html

入门使用

☕️ SpringBoot 引入 Thymeleaf 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

☕️ 在 application.properties 进行 Thymeleaf 配置

# 页面缓存设置,默认值为 true(开发中方便调试设置为 false,上线稳定后应保持默认 true)
spring.thymeleaf.cache=false

# 模板编码,默认值为 UTF-8
spring.thymeleaf.encoding=UTF-8
# 指定模板页面的存放路径,默认值为 classpath:/templates/
spring.thymeleaf.prefix=classpath:/templates/
# 指定模板页面名称的后缀,默认值为 .html
spring.thymeleaf.suffix=.html
# 指定文本类型,默认值为 text/html 
spring.thymeleaf.servlet.content-type=text/html
# 应用于模板的模板模式,默认值为 HTML
spring.thymeleaf.mode=HTML

☕️ 创建模板文件

在 resources/templates 目录新建模板文件 test.html,新增文件后,首先在模板文件的标签中导入 Thymeleaf 的名称空间:

<html lang="en" xmlns:th="http://www.thymeleaf.org">

导入该名称空间主要是为了 Thymeleaf 的语法提示和 Thymeleaf 标签的使用,最终的模板文件如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>
    <p th:text="${test}">显示测试字段</p>
</body>
</html>

☕️ 编辑 Controller 代码

@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("test", "这里是一个测试!");
        return "test";
    }
}

☕️ 启动并访问

访问localhost:8080/hello,可以看到原本的<p>标签中的内容已经被替换为这里是一个测试!

☕️ 模板解读

上述模板中读取动态数据并渲染的语句如下:

<p th:text="${test}">显示测试字段</p>

该模板语句中包含三块内容:

  1. html 标签
  2. Thymelaf 模板引擎的 th 标签
  3. Thymelaf 表达式

前半部分的<p>为 html 的标签,后半部分为 Thymeleaf 属性标签和表达式语法。th:text表示文本替换,${test}表示读取后台设置的 test 字段,该模板语句的作用就是动态的将<p>标签中的内容替换为后台设置的 test 字段内容。

Thymeleaf 模板文件的编写规则如下:

  • 任意的 Thymeleaf 属性标签th:*需要写在 html 标签体中(th:block除外)
  • Thymleaf 表达式写在 Thymeleaf 属性标签中

th:* 替换属性值

前面我们使用th:text进行文本替换,除此之外还提供了其他的标签属性来替换 HTML5 原生属性的值,具体信息可以查看 thymeleaf-attributes。下面介绍一下通过 Thymeleaf 语法修改属性值,代码如下:

⭐️ 编辑 test.html 模板文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>

<!-- th:background 替换 HTML5 的背景属性 ->-->
<body th:background="${th_backgrourd}" background="#DODODO">
<div>
    <h5>text 标签</h5>
    <!-- th:text 用于替换文本,该标签会对特殊字符进行转义 -->
    <p th:text="${th_text}">th:text 标签演示</p>
    <!-- th:utext 也可以替换文本,但是该标签不会对特殊字符进行转义 -->
    <p th:utext="${th_utext}">th:utext 标签演示</p>
</div>

<div>
    <h5>id、name、value 标签</h5>
    <!-- th:id、th:name、th:value 分别替换 id、name、value 属性 -->
    <input th:id="${th_id}" th:name="${th_name}" th:value="${th_value}"/>
</div>

<!-- th:class、th:href 分别替换 class、href 属性 -->    
<div th:class="${th_class}">
    <h5>class、href 标签</h5>
    <a th:href="${th_href}">链接</a>
</div>
</body>
</html>

⭐️ 编辑 Controller 代码

@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("th_text", "<a href='https://www.baidu.com'>thymeleaf-text</a>");
        model.addAttribute("th_utext", "<a href='https://www.baidu.com'>thymeleaf-utext</a>");

        model.addAttribute("th_id", "thymeleaf-id");
        model.addAttribute("th_name", "thymeleaf-name");
        model.addAttribute("th_value", "thymelaf-value");

        model.addAttribute("th_class", "thymeleaf-class");
        model.addAttribute("th_href", "https://www.baidu.com");
        return "test";
    }
}

⭐ 启动并访问

访问localhost:8080/hello,网页显示:

查看展示给客户端的网页源代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>

<!-- th:background 替换 HTML5 的背景属性 ->-->
<body>
<div>
    <h5>text 标签</h5>
    <!-- th:text 用于替换文本,该标签会对特殊字符进行转义 -->
    <p>&lt;a href=&#39;https://www.baidu.com&#39;&gt;thymeleaf-text&lt;/a&gt;</p>
    <!-- th:utext 用于替换文本,该标签不会对特殊字符进行转义 -->
    <p><a href='https://www.baidu.com'>thymeleaf-utext</a></p>
</div>

<div>
    <h5>id、name、value 标签</h5>
    <!-- th:id、th:name、th:value 分别替换 id、name、value 属性 -->
    <input id="thymeleaf-id" name="thymeleaf-name" value="thymelaf-value"/>
</div>

<!-- th:class、th:href 分别替换 class、href 属性 -->     
<div class="thymeleaf-class">
    <h5>class、href 标签</h5>
    <a href="https://www.baidu.com">链接</a>
</div>
</body>
</html>

Thymeleaf 语法规则

Thymleaf 官方对标准表达式特性总结如下,具体可以查看 Standard Expression Syntax

  • 表达式语法

    • 变量表达式: ${...}
    • 选择表达式: *{...}
    • 信息表达式: #{...}
    • 链接 URL 表达式: @{...}
    • 分段表达式: ~{...}
  • 字面量

    • 字符串: 'one text', 'Another one!' ...
    • 数字: 0, 34, 3.0, 12.3 ...
    • 布尔值: true, false
    • Null 值: null
    • 字面量标记:one, sometext, main ...
  • 文本运算

    • 字符串拼接: +
    • 字面量置换: |The name is ${name}|
  • 算术运算

    • 二元运算符: +, -, *, /, %
    • 负号(一元运算符): (unary operator): -
  • 布尔运算

    • 二元运算符: and, or
    • 布尔非(一元运算符): !, not
  • 比较运算

    • 比较: >, <, >=, <= (gt, lt, ge, le)
    • 相等运算符: ==, != (eq, ne)

    比较运算符也可以使用转义字符,比如大于号,所以 Thymeleaf 语法中&gt;等价于>

  • 条件运算符

    • If-then: (if) ? (then)
    • If-then-else: (if) ? (then) : (else)
    • Default: (value) ?: (defaultvalue)
  • 特殊语法

    • 无操作: _

简单语法使用

下面主要介绍字面量及简单的运算操作,包括字符串、数字、布尔值等常用的字面量及常用的运算和拼接操作,代码如下:

✏️ 编辑 test.html 模板文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>

<body>
<div>
    <h5>基本类型操作(字符串):</h5>
    <p>一个简单的字符串:<span th:text="'thymeleaf text'">default text</span>.</p>
    <p>字符串连接:<span th:text="'thymeleaf text concat, ' + ${thymeleafText}">default text</span>.</p>
    <p>字符串连接:<span th:text="|thymeleaf text concat, ${thymeleafText}|">default text</span>.</p>
</div>

<div>
    <h5>基本类型操作(数字):</h5>
    <p>一个简单的数字:<span th:text="2019">1000</span>.</p>
    <p>算术运算: 2019 + 1 = <span th:text="${number1} + 1">0</span>.</p>
    <p>算术运算: 14 - 1 = <span th:text="14 - 1">0</span>.</p>
    <p>算术运算: 673 * 3=<span th:text="673 * ${number2}">0</span>.</p>
    <p>算术运算: 39 ÷ 3=<span th:text="39 / 3">0</span>.</p>
</div>

<div>
    <h5>基本类型操作(布尔值):</h5>
    <p>一个简单的数字比较:2019 > 2018,结果为:<span th:text="2019&gt;2018">false</span>.</p>
    <p>字符串比较:thymeleafText == 'hello world',结果为:<span th:text="${thymeleafText} == 'hello world'">false</span>.</p>
    <p>数字比较:13 == 39 / 3,结果为:<span th:text="13 == 39 / 3">false</span>.</p>
</div>
</body>
</html>

✏️ 编辑 Controller 代码

@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("thymeleafText", "hello world");
        model.addAttribute("number1", 2019);
        model.addAttribute("number2", 3);
        return "test";
    }
}

✏️ 启动并访问

访问localhost:8080/hello,网页显示:


变量表达式${}

变量表达式即 OGNL 表达式或 Spring EL 表达式,作用是获取模板中与后端返回数据所绑定对象的值,写法为 ${...},这是最常见的一个表达式,在取值赋值、逻辑判断、循环语句中都可以使用该表达式。

简单使用

变量表达式可以是 OGNL 表达式,${...}不但可以访问基本数据类型的变量值,还可以访问对象的属性值,示例如下:

<!-- 使用点(.)来访问属性,等价与调用属性的 getter -->
${person.father.name}

<!-- 使用块([])访问属性 -->
${person['father']['name']}

<!-- 如果对象是一个 map,则点和块语法等价与调用其 get(...) -->
${countriesByCode.ES}
${personsByName['Jim'].age}

<!-- 在块中使用索引访问数组和集合 -->
${personsArray[0].name}

<!-- 可以调用方法同时也支持参数 -->
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

下面使用变量表达式${...}获取后端返回的对象、数组和集合属性值,代码如下:

📚 编辑 test.html 模板文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>

<body>
<div>
    <h5>访问普通属性</h5>
    <!-- 使用(.)来访问对象的属性,等价于调用属性的 getter 方法 -->
    <p>name:<span th:text="${person.name}">Alice</span></p>
    <!-- 使用块([])访问对象的属性,等价于调用属性的 getter 方法 -->
    <p>name:<span th:text="${person['name']}">Alice</span></p>
    <!-- 使用属性的 getter 方法访问对象的属性 -->
    <p>name:<span th:text="${person.getName()}">Alice</span></p>    
</div>

<div>
    <h5>访问数组和 List 集合</h5>
    <!-- 使用索引访问数组对象 -->
    <p>hobbies1:<span th:text="${person.hobbies1[0]}">singing</span></p>
    <!-- 使用索引访问 List 对象 -->
    <p>hobbies2:<span th:text="${person.hobbies2[0]}">singing</span></p>
</div>

<div>
    <h5>访问 Map 集合</h5>
    <!-- 使用(.)和([])都可以访问 Map 对象,等价调用其 get(...) 方法-->
    <p>hobbies3:<span th:text="${person.hobbies3.hobby1}">singing</span></p>
    <p>hobbies3:<span th:text="${person.hobbies3['hobby1']}">singing</span></p>
    <p>hobbies3:<span th:text="${person.hobbies3.get('hobby1')}">singing</span></p>
</div>
</body>
</html>

📚 编辑 Controller 代码

public class Person {
    private String name;
    private Integer age;
    private String[] hobbies1;
    private List<String> hobbies2;
    private Map<String, String> hobbies3;
    
    // 略写 setter 和 getter 方法
}
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        Map<String, String> hobbies = new HashMap<>();
        hobbies.put("hobby1", "dancing");
        
        Person person = new Person();
        person.setName("Bob");
        person.setHobbies1(new String[]{"dancing"});
        person.setHobbies2(Arrays.asList("dancing"));
        person.setHobbies3(hobbies);
        
        model.addAttribute("person", person);
        return "test";
    }
}

📚 启动并访问

访问localhost:8080/hello,网页显示:

复杂使用

✌ 使用内置对象

Thymeleaf 为变量所在域提供了一些内置对象,变量表达式${...}可以直接使用:

  • #ctx:上下文对象

  • #vars:上下文变量

  • #locale:上下文区域设置

  • #request:HttpServletRequest 对象(仅限 Web Context)

  • #response:HttpServletResponse 对象(仅限 Web Context)

  • #session:HttpSession 对象(仅限 Web Context)

  • #servletContext:ServletContext 对象(仅限 Web Context)

具体使用代码如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>

<body>
<div>
    <!-- 使用内置对象 #request -->
    <p th:text="${#request.getAttribute('requestObject')}">default text</p>
    <!-- 使用内置对象 #session -->
    <p th:text="${#session.getAttribute('sessionObject')}">default text</p>
</div>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(HttpServletRequest request, HttpSession session) {
        request.setAttribute("requestObject", "读取 request 域内容");
        session.setAttribute("sessionObject", "读取 session 域内容");
        return "test";
    }
}

访问localhost:8080/hello,网页显示:

✌ 使用内置工具类

同时,Thymeleaf 还提供了一系列 Utility 工具对象(内置于 Context 中),${...}可以直接访问:

  • #dates:日期格式化内置对象,具体方法可以参照java.util.Date

  • #calendars:类似于#dates,但是是java.util.Calendar类的方法

  • #numbers:数字格式化

  • #strings:字符串格式化,具体方法可以参照java.lang.String,如 startsWith、contains等

  • #bools:判断 boolean 类型的工具

  • #arrays:数组操作的工具

  • #lists:列表操作的工具,参照java.util.List

  • #sets:Set操作工具,参照java.util.Set

  • #maps:Map操作工具,参照java.util.Map

具体使用代码如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>

<h3>#dates 工具类测试</h3>
<div>
    <!-- 获取日期的 year 字段 -->
    <p>year : <span th:text="${#dates.year(testDate)}"/></p>
    <!-- 获取日期的 month 字段 -->
    <p>month : <span th:text="${#dates.month(testDate)}"/></p>
    <!-- 获取日期的 day 字段 -->
    <p>day : <span th:text="${#dates.day(testDate)}"/></p>
    <!-- 获取日期的 hour 字段 -->
    <p>hour : <span th:text="${#dates.hour(testDate)}"/></p>
    <!-- 获取日期的 minute 字段 -->
    <p>minute : <span th:text="${#dates.minute(testDate)}"/></p>
    <!-- 获取日期的 second 字段 -->
    <p>second : <span th:text="${#dates.second(testDate)}"/></p>
    <!-- 日期格式化(可以自定义日期格式) -->
    <p>格式化: <span th:text="${#dates.format(testDate)}"/></p>
    <p>yyyy-MM-dd HH:mm:ss 格式化: <span th:text="${#dates.format(testDate, 'yyyy-MM-dd HH:mm:ss')}"/></p>
</div>

<h3>#strings 工具类测试 </h3>
<!-- 判断字符串是否为空 -->
<div th:if="${not #strings.isEmpty(testString)}">
    <p>testString初始值 : <span th:text="${testString}"/></p>
    <!-- 将所有字符转换为大写 -->
    <p>toUpperCase : <span th:text="${#strings.toUpperCase(testString)}"/></p>
    <!-- 将所有字符转换为小写 -->
    <p>toLowerCase : <span th:text="${#strings.toLowerCase(testString)}"/></p>
    <!-- 忽略大小写判断字符串是否相等 -->
    <p>equalsIgnoreCase : <span th:text="${#strings.equalsIgnoreCase(testString, '13')}"/></p>
    <!-- 获取字符在字符串中的索引 -->
    <p>indexOf : <span th:text="${#strings.indexOf(testString, 'r')}"/></p>
    <!-- 截取字符子串 -->
    <p>substring : <span th:text="${#strings.substring(testString, 5, 9)}"/></p>
    <!-- 判断字符串是否以指定子串开头 -->
    <p>startsWith : <span th:text="${#strings.startsWith(testString, 'Spring')}"/></p>
    <!-- 判断字符串是否包含指定子串 -->
    <p>contains : <span th:text="${#strings.contains(testString, 'Boot')}"/></p>
</div>

<h3>#bools 工具类测试</h3>
<!-- 判断 bool 是否为 true -->
<!-- 如果 bool 的值为false的话,该div将不会显示-->
<div th:if="${#bools.isTrue(testBool)}">
    <p th:text="${testBool}"></p>
</div>

<h3>#arrays 工具类测试</h3>
<!-- 判断数组是否为空 -->
<div th:if="${not #arrays.isEmpty(testArray)}">
    <!-- 获取数组长度 -->
    <p>length : <span th:text="${#arrays.length(testArray)}"/></p>
    <!-- 判断数组是否包含指定元素 -->
    <p>contains : <span th:text="${#arrays.contains(testArray, 5)}"/></p>
    <!-- 判断数组是否包含指定子数组 -->
    <p>containsAll : <span th:text="${#arrays.containsAll(testArray, testArray)}"/></p>
    <!-- 循环读取数组元素 -->
    <p>循环读取 : <span th:each="i:${testArray}" th:text="${i+' '}"/></p>
</div>

<h3>#lists 工具类测试</h3>
<!-- 判断 list 是否为空 -->
<div th:unless="${#lists.isEmpty(testList)}">
    <!-- 获取 list 长度 -->
    <p>size : <span th:text="${#lists.size(testList)}"/></p>
    <!-- 判断 list 是否包含指定元素 -->
    <p>contains : <span th:text="${#lists.contains(testList, 0)}"/></p>
    <!-- 将 list 排序返回 -->
    <p>sort : <span th:text="${#lists.sort(testList)}"/></p>
    <!-- 循环读取 list 元素 -->
    <p>循环读取 : <span th:each="i:${testList}" th:text="${i+' '}"/></p>
</div>

<h3>#maps 工具类测试</h3>
<!-- 判断 map 是否为空 -->
<div th:if="${not #maps.isEmpty(testMap)}">
    <!-- 获取 map 中的元素个数 -->
    <p>size : <span th:text="${#maps.size(testMap)}"/></p>
    <!-- 判断 map 中是否包含指定 key -->
    <p>containsKey : <span th:text="${#maps.containsKey(testMap, 'id1')}"/></p>
    <!-- 判断 map 中是否包含指定 value -->
    <p>containsValue : <span th:text="${#maps.containsValue(testMap, 'Mac')}"/></p>
    <!-- 读取 map 中指定 key 所对应的 value -->
    <p>读取map中键为id2的值 : <span th:if="${#maps.containsKey(testMap,'id2')}" th:text="${testMap.get('id2')}"/></p>
</div>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("testDate", new Date());
        model.addAttribute("testString", "SpringBoot Thymeleaf 学习");
        model.addAttribute("testBool", true);
        model.addAttribute("testArray", new Integer[]{2018, 2019, 2020, 2021});
        model.addAttribute("testList", Arrays.asList("Spring", "Spring Boot", "Thymeleaf", "MyBatis", "Java"));

        Map<String, String>testMap = new HashMap<>();
        testMap.put("id1", "Windows");
        testMap.put("id2", "Linux");
        testMap.put("id3", "Mac");
        model.addAttribute("testMap", testMap);

        return "test";
    }
}

访问localhost:8080/hello,网页显示:

#dates 工具类测试
year : 2020
month : 11
day : 8
hour : 17
minute : 28
second : 46
格式化: 2020年11月8日 CST 下午5:28:46
yyyy-MM-dd HH:mm:ss 格式化: 2020-11-08 17:28:46

#strings 工具类测试
testString初始值 : SpringBoot Thymeleaf 学习
toUpperCase : SPRINGBOOT THYMELEAF 学习
toLowerCase : springboot thymeleaf 学习
equalsIgnoreCase : false
indexOf : 2
substring : gBoo
startsWith : true
contains : true
    
#bools 工具类测试
true

#arrays 工具类测试
length : 4
contains : false
containsAll : true
循环读取 : 2018 2019 2020 2021

#lists 工具类测试
size : 5
contains : false
sort : [Java, MyBatis, Spring, Spring Boot, Thymeleaf]
循环读取 : Spring Spring Boot Thymeleaf MyBatis Java
    
#maps 工具类测试
size : 3
containsKey : true
containsValue : true

读取map中键为id2的值 : Linux

选择表达式*{}

选择表达式和变量表达式类似,不过它会用一个预先选择的对象来代替上下文变量容器来执行,被选择的对象使用th:object标签来指定:

<div>
    <!-- 下面两行代码是等价的 -->
    <!-- 使用 ${...} 表达式 -->
    <p>name:<span th:text="${person.name}">Alice</span></p>
    <!-- 使用 *{...} 表达式 -->
    <p th:object="${person}">name:<span th:text="*{name}">Alice</span></p>
</div>

在不考虑上下文的情况下,${...}*{...}两者没有区别,唯一区别在于使用*{...}前可以在父标签中通过th:object预先指定一个对象代替上下文变量容器:

<div th:object="${person}">
    ...
   <!-- 读取 person 对象的 name 字段 -->
   <span th:text="*{name}">...</span>
    ...
</div>

链接表达式@{}

链接表达式@{...}用于页面跳转或者资源的引入,一般用于替换 href 标签中的链接 URL 地址,例如:

<!-- 下面三个引用是同一个 URL 地址 -->
<!-- 绝对路径,/myapp 是虚拟目录 -->
<a th:href="@{http://loaclhost:8080/myapp/order/list}">Default URL</a>
<!-- 相对路径,相对应用程序虚拟目录 /myapp 的路径 -->
<a th:href="@{/order/list}">Default URL</a>
<!-- 相对路径,相对服务器的路径 -->
<a th:href="@{~/myapp/order/list}">Default URL</a>

除此之外,链接表达式也可以读取变量值进行动态拼接 URL 地址:

<!-- 下面三个引用是同一个 URL 地址 -->
<a th:href="@{'http://localhost:8080/order/list/1'}">Default URL</a>
<a th:href="@{'/order/list/' + ${order.Id}}">Default URL</a>
<a th:href="@{/order/list/{orderId}(orderId=${order.Id})">Default URL</a>

如果链接的 URL 地址用多个参数,可以自行拼接字符串,还是使用逗号隔开,写法如下:

<!-- 最终生成的 URL 形如 http://localhost:8080/order/list?id=1&type=phone -->
<a th:href="@{/order/list(id=${order.id},type=${order.type})}">Default URL</a>

分段表达式~{}

分段表达式~{}用于将标记片段移动到模板,一般使用th:insertth:replace引用片段。

基本使用

✍ 标记片段

<!-- commmon.html -->
<!-- 使用 th:fragment 标记片段,该标签属性值为片段名 -->
<div th:fragment="copy-fragment">
    标记片段
</div>

✍ 引用片段

<!-- index.html -->
<!-- 使用 th:insert 和 th:replace 引用片段,引用格式为 ~{文件名::片段名} -->
<div th:insert="~{commmon::copy-fragment}"></div>
<div th:replace="~{commmon::copy-fragment}"></div>

最终生成代码如下:

<!-- index.html -->
<!-- th:insert 是插入片段 -->
<div>
    <div>aaa</div>
</div> 

<!-- th:replace 是替换片段 -->
<div>
    aaa
</div>

分段表达式传参

分段表达式~{}可以传递参数,根据传递参数的不同显示不同的样式,例如:

<!-- index.html -->
<!-- 引入侧边栏 sidebar-fragment -->
<div th:replace="sidebar::sidebar-fragment(${path})"></div>
<!-- sidebar.html -->
<div th:fragment="sidebar-fragment(path)">
    <a th:href="@{/index}" th:class="${path}=='index' ? 'active'">index</a> 
    <a th:href="@{/admin}" th:class="${path}=='admin' ? 'active'">admin</a>    
</div>

条件逻辑判断

💡 条件表达式

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>
    <!-- if-then-else 三元运算符 -->
    <p>当前的用户为:<span th:text="${person} != null ? ${person.name} : 'no user authenticated'">Admin</span></p>

    <!-- else 表达式可以省略,等价返回 null 值 -->
    <!-- 在这种情况下,如果条件为 false,页面什么都不会显示 -->
    <p>当前的用户为:<span th:text="${person} != null ? ${person.name}">Admin</span></p>
    <p>当前的用户为:<span th:text="${person} != null ? ${person.name} : null">Admin</span></p>

    <!-- (_) 是无操作标记,表示什么都不做,如果条件为 false,页面直接使用 "Admin" 文本 -->
    <p>当前的用户为:<span th:text="${person} != null ? ${person.name} : _">Admin</span></p>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello() {
        return "test";
    }
}

访问localhost:8080/hello,网页显示:

💡 条件语句

th:if 和 th:unless

Thymeleaf 使用th:ifth:unless进行条件判断,HTML5 标签中的内容只有th:if的表达式条件为 true 时才显示,th:unlessth:if恰好相反,只有表达式条件为 false 时才显示 HTML5 标签中的内容。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>
    <h5>th:if 条件判断</h5>
    <p th:if="${person} != null">当前的用户为:<span th:text="${person.name}">Default Text</span>.</p>

    <h5>th:unless 条件判断</h5>
    <p th:unless="${person} != null">当前的用户为:<span th:text="${person.name}">Default Text</span>.</p>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        Person person = new Person();
        person.setName("Alice");
        model.addAttribute("person", person);
        return "test";
    }
}

访问localhost:8080/hello,网页显示:

th:if的表达式判断规则如下:

  • 如果表达式值为 null,直接返回 true;

  • 如果表达式值不为 null,以下情况返回 true:

    • 表达式值为 boolean 类型,并且为 true;
    • 表达式值是数值类型,并且不为零;
    • 表达式值是字符类型,并且不为零;
    • 表达式值是 String 类型,并且不是 “false” “off” 或 “no”;
    • 表达式值不是 boolean、数值、字符、String 类型的其他类型。

th:unless的表达式判断规则和th:if相反。

th:switch

Thymeleaf 支持多路选择 Switch 结构,类似于 Java 的swith...case...default,只不过默认属性 default 用 * 表示,使用如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>
    <!-- th:switch 多路选择 -->
    <div th:switch="${role}">
        <p th:case="'admin'">User is an administrator</p>
        <p th:case="'manager'">User is an manager</p>
        <p th:case="'*'">User is some other thing</p>
    </div>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("role", "manager");
        return "test";
    }
}

访问localhost:8080/hello,网页显示:


循环迭代访问

💡 基本迭代

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
</head>
<body>
<table>
    <tr>
        <th>姓名</th>
        <th>年龄</th>
    </tr>
    <!-- th:each 将数组或 list 中的元素循环迭代,语法相当于 Java foreach 表达式 -->
    <tr th:each="person : ${persons}">
        <td th:text="${person.name}"></td>
        <td th:text="${person.age}"></td>
    </tr>
</table>
</body>
</html>
public class Person {
    private String name;
    private Integer age;

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    // getter 和 setter 方法略写
}
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 10));
        persons.add(new Person("李四", 20));
        persons.add(new Person("王五", 30));
        persons.add(new Person("赵六", 40));
        model.addAttribute("persons", persons);
        return "test";
    }
}

访问localhost:8080/hello,网页显示:

💡 状态变量

th:each除了循环迭代元素基本使用外,还可以设置状态变量来跟踪迭代器的状态,状态变量有如下属性:

  • index:当前迭代元素的索引,从 0 开始
  • count:当前迭代元素的索引,从 1 开始
  • size:当前迭代集合中元素的总数
  • current:当前的迭代元素对象
  • even/odd:布尔值,判断当前迭代元素的索引是否为偶/奇数(从1开始索引)
  • first:布尔值,判断当前迭代元素是否为第一个
  • last:布尔值,判断当前迭代元素是否为最后一个
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Test</title>
    <style>
        .even{
            color: red;
        }
        .odd{
            color: green;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <th>index</th>
        <th>count</th>
        <th>姓名</th>
        <th>年龄</th>
    </tr>

    <!-- person 为迭代元素,status 为状态变量 -->
    <tr th:each="person, status : ${persons}" th:class="${status.even} ? even : odd">
        <td th:text="${status.index}"></td>
        <td th:text="${status.count}"></td>
        <td th:text="${person.name}"></td>
        <td th:text="${person.age}"></td>
    </tr>
</table>
</body>
</html>
@Controller
public class ThymeleafController {

    @GetMapping("/hello")
    public String hello(Model model) {
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("张三", 10));
        persons.add(new Person("李四", 20));
        persons.add(new Person("王五", 30));
        persons.add(new Person("赵六", 40));
        model.addAttribute("persons", persons);
        return "test";
    }
}

访问localhost:8080/hello,网页显示:


参考

  1. Thymeleaf 语法详解及编码实践
  2. Thymeleaf 内置工具
posted @ 2020-11-09 17:17  呵呵233  阅读(739)  评论(0编辑  收藏  举报