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>
该模板语句中包含三块内容:
- html 标签
- Thymelaf 模板引擎的 th 标签
- 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><a href='https://www.baidu.com'>thymeleaf-text</a></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 语法中
>
等价于>
。 - 比较:
-
条件运算符
- If-then:
(if) ? (then)
- If-then-else:
(if) ? (then) : (else)
- Default:
(value) ?: (defaultvalue)
- If-then:
-
特殊语法
- 无操作:
_
- 无操作:
简单语法使用
下面主要介绍字面量及简单的运算操作,包括字符串、数字、布尔值等常用的字面量及常用的运算和拼接操作,代码如下:
✏️ 编辑 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>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:insert
或th: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:if
和th:unless
进行条件判断,HTML5 标签中的内容只有th:if
的表达式条件为 true 时才显示,th:unless
与th: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
,网页显示: