一、thymeleaf介绍
Thymeleaf 是新一代 Java 模板引擎,与 VeLocity、FreeMarker 等传统 Java 模板引擎不同,Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,因此它可以直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板的静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。
Thymeleaf 通过在 html 标签中,增加额外属性来达到“模板+数据”的展示方式,示例代码如下。
<!DOCTYPE html>
<!--设置命名空间:th才能生效使用 -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<Meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- th:text 为Thymeleaf的属性,用于展示文本 -->
<h1 th:text="hello Thymeleaf">hello HTML</h1>
</body>
</html>
同时,Spring Boot 推荐使用 Thymeleaf 作为其模板引擎。SpringBoot 为 Thymeleaf 提供了一系列默认配置,项目中一但导入了 Thymeleaf 的依赖,相对应的自动配置 (ThymeleafAutoConfiguration) 就会自动生效,因此 Thymeleaf 可以与 Spring Boot 完美整合 。
二、SpringBoot整合thymeleaf
官网:https://www.thymeleaf.org/
2.1 导入依赖
构建springboot项目,导入依赖,创建启动类。
<!--引入父依赖-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/> <!-- lookup parent from repository:当子项目中未定义版本号时可以从父项目中引用 -->
</parent>
...
<dependencies>
<!--springbootweb依赖(包含:spring,springmvc,tomcat等依赖)-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Thymeleaf 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
2.2 配置yml
application.yml
server:
port: 80 #端口
#thymeleaf参数
spring:
thymeleaf:
prefix: classpath:/templates/ #视图前缀
suffix: .html #视图后缀
encoding: UTF-8 #编码
cache: false #缓存(默认开启,开发时建议关闭)
# 以上关于thymeleaf的这些参数其实都无需设置,因为都默认设置好了。参考:ThymeleafProperties
ThymeleafProperties内容如下:
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
...
}
2.3 编写controller
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
//1.将数据传入model
//1.1 存入单个对象
User user = new User();
user.setId(1);
user.setUsername("tom");
user.setPassword("123");
model.addAttribute("user",user);
//1.2 存入list
List<User> userList = new ArrayList<>();
User user1 = new User();
user1.setId(2);
user1.setUsername("jack");
user1.setPassword("123");
userList.add(user);
userList.add(user1);
model.addAttribute("userList",userList);
//2.转发页面取值
return "mypage";
}
}
public class User { //必须满足javabean
private Integer id;
private String username;
private String password;
//get set ...
}
2.4 编写页面
src/main/resources/templates/mypage.html
html模板必须放在templates中,这是因为设置了视图的前缀和后缀。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<Meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--获取单个对象-->
<div>
<span th:text="${user.id}"></span>
<span th:text="${user.username}"></span>
<span th:text="${user.password}"></span>
</div>
<!--获取list-->
<ul>
<li th:each="u:${userList}">
<span th:text="${u.id}"></span>
<span th:text="${u.username}"></span>
<span th:text="${u.password}"></span>
</li>
</ul>
</body>
</html>
<!-- 说明:${key} 默认从request对象中获取值 -->
这样一个thymeleaf的极简入门就完成了。
三、thymeleaf标准表达式
Thymeleaf 模板引擎支持多种表达式,分别是:
- 变量表达式:${…}
- 选择变量表达式:*{…}
- 链接表达式:@{…}
- 国际化表达式:#{…}
- 片段引用表达式:~{…}
3.1 变量表达式
变量表达式语法:${ },该表达式具有以下功能:
-
获取对象的属性和调用方法
例如:${person.lastName}
获取 person 对象的 lastName 属性,默认从request中获取。 -
使用内置的基本对象
thymeleaf中的内置对象有:
① #ctx :上下文对象
② #vars :上下文变量
③ #locale:上下文的语言环境
④ #request:HttpServletRequest 对象(仅在 Web 应用中可用)
⑤ #response:HttpServletResponse 对象(仅在 Web 应用中可用)
⑥ #session:HttpSession 对象(仅在 Web 应用中可用)
⑦ #servletContext:ServletContext 对象(仅在 Web 应用中可用)
例如:${#session.getAttribute('name')} 或 ${session.name}
获取session 对象中的 name属性值。 -
使用内置的工具对象
thymeleaf中的内置工具对象有:
① strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toupperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等;
例如:${#strings.equals('hello',name)}
使用内置工具对象的equals方法判断 name 的值是否为 hello
② numbers:数字工具对象,常用的方法有:formatDecimal 等;
③ bools:布尔工具对象,常用的方法有:isTrue 和 isFalse 等;
④ arrays:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等;
⑤ lists/sets:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等;
⑥ maps:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等;
⑦ dates:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等。
例如:<td th:text="${#dates.format(user.birthday, 'yyyy-MM-dd HH:mm:ss')}"></td>
3.2 选择变量表达式
选择变量表达式的语法为:*{...}
,选择变量表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object
的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代中使用选择变量表达式(*{…})获取该对象中的属性,其中,“*”即代表该对象。
<div th:object="${session.user}" >
<p th:text="*{name}"></p>
</div>
<!--解释:th:object 用于存储一个临时变量,该变量只在该标签及其后代中有效,
在后面的内容“th 属性”中我详细介绍。-->
3.3 链接表达式
在超链接,form表单,img等,凡是链接都可以用链接表达式,语法:@{...}
链接表达式的形式结构如下:
- 无参请求:
@{/xxx}
- 有参请求:
@{/xxx(k1=v1,k2=v2)}
例如:在link标签中使用方式如下
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
3.4 国际化表达式
消息表达式一般用于国际化的场景。
例如:th:text="#{msg}"
,会在后边th属性时具体讲解。
3.5 片段引用表达式
片段引用表达式用于在模板页面中引用其他的模板片段,该表达式支持以下 2 种语法结构:
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
语法说明:
① templatename:模版名,Thymeleaf 会根据模版名解析完整路径:/resources/templates/templatename.html
,要注意文件的路径。
② fragmentname:片段名,Thymeleaf 通过 th:fragment 声明定义代码块,即:th:fragment=“fragmentname”
③ id:HTML 的 id 选择器,使用时要在前面加上 # 号,不支持 class 选择器。
在抽取公共页面章节细说。
四、thymeleaf的th属性
1.th:id
:用于替代html中的id属性
<input th:id="d1"/>
最终显示效果为:<input id="d1"/>
2.文本替换th:text
和 th:utext
<h1 th:text="'hello thymeleaf'">码赛客1024</h1> 文本替换,转义特殊字符(h1会被当做普通字符)
<div th:utext="'<h1>码赛客1024</h1>'"></div> 文本替换,不转义特殊字符(h1会被当做标签执行)
3.替换value值 th:value
<input th:value = "${user.name}" /> 从user对象中获取name属性设置为value的值
4.局部变量赋值运算th:with
<div th:with="isEvens = ${lists.count}%2 == 0" th:text="${isEvens}"></div>
th:text显示内容是th:width中计算后的结果
5.th:object
用于存储一个临时变量在其子标签中使用,在前面选择变量表达式中讲过。
<div th:object="${session.user}" >
<p th:text="*{name}"></p>
</div>
<!--解释:th:object 用于存储一个临时变量,该变量只在该标签及其后代中有效,
在后面的内容“th 属性”中我详细介绍。-->
6.th:style
用于设置样式
<div th:style="'color:red;font-weight:bold'">码赛客1024</div>
7.th:onclick
绑定事件
<button th:onclick = "'getInfo()'"></button>
8.th:each
遍历元素
<ul>
<li th:each="user:${userList}">
<span th:text="${user.id}"></span>
<span th:text="${user.username}"></span>
<span th:text="${user.password}"></span>
</li>
</ul>
9.th:if
和 th:unless
判断
<a th:if ="${userId == collect.userId}">xx</a>
<!--满足条件才展示该标签-->
<div th:unless="${userId == collect.userId}" ></div>
<!--不满足条件才展示该标签-->
10.th:switch
和Java中的switch一样
<div th:switch="${name}">
<span th:case="a">hello</span>
<span th:case="b">1024</span>
</div>
11.th:selected
设置select选择框选中某项
<select>
<option>---</option>
<option th:selected="${name=='a'}">
hello
</option>
<option th:selected="${name=='b'}">
1024
</option>
</select>
12.th:src
设置元素src属性
<img th:src="@{/asserts/img/a.svg}" src="asserts/img/a.svg" />
13.th:action
表单action属性
<form th:action="@{/user/login}" th:method="post"></form>
五、thymeleaf公共页面抽取
在页面中一般顶部导航栏,左侧菜单栏等部分都是重复的,建议抽取成公共页面,在需要的地方引入即可。
5.1 抽取公共页面
我们可以将公共页面片段抽取出来,存放到一个独立的页面中,并使用 Thymeleaf 提供的 th:fragment
属性为这些抽取出来的公共页面片段命名。
公共页面片段的语法是:
<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
<!--
说明:
th:fragment属性:片段名,用来定义一段被引用或包含的模板片段
id属性:片段id,用来定义一段被引用或包含的模板片段
-->
例如:在resources/templates/commons.html
中存放公共片段
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<Meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:fragment="nav" id="nav">
<span>这是页面的导航栏</span>
</div>
<div th:fragment="meun" id="meun">
<span>这是页面的菜单</span>
</div>
</body>
</html>
5.2 引用公共页面
引入公共页面有三种方式:
- th:insert:将代码块片段整个插入到使用了 th:insert 属性的 HTML 标签中;
- th:replace:将代码块片段整个替换使用了 th:replace 属性的 HTML 标签中;
- th:include:将代码块片段包含的内容插入到使用了 th:include 属性的 HTML 标签中。
使用上 3 个属性引入页面片段,都可以通过以下 2 种方式实现。
~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名
但是一般 ~{ } 是可以省略的。
咱们尝试把前面commons.html中的公共片段引入到自己的页面中:
<!--1. th:insert 片段名引入-->
<div th:insert="commons::nav"></div> <!--commons就是文件名,nav是片段名-->
<!--th:insert id 选择器引入-->
<div th:insert="commons::#nav"></div> <!--commons就是文件名,#nav是片段id-->
------------------------------------------------
<!--2. th:replace 片段名引入-->
<div th:replace="commons::nav"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#nav"></div>
------------------------------------------------
<!--3. th:include 片段名引入-->
<div th:include="commons::nav"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#nav"></div>