当前位置: 首页 > 工具软件 > Thymeleaf > 使用案例 >

Thymeleaf详解

夏侯阳
2023-12-01

官方手册: http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html

一、简介

Thymeleaf是SpringBoot官方所推荐使用的页面模板语言
优点:

  • 动静结合:Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。

  • 开箱即用:它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。

  • 多方言支持:Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。

  • 与SpringBoot完美整合,SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。

二、创建Thymeleaf

1. 添加依赖

<!--SpringBoot 集成 Thymeleaf 的起步依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2. 基本配置

  1. thymeleaf 页面的缓存开关,默认 true 开启缓存(建议在开发阶段关闭 thymeleaf 页面缓存,目的实时看到页面)
spring.thymeleaf.cache=false
  1. thymeleaf的前缀与后缀,下面给出的是SpringBoot的默认值,也可以通过这两个参数进行修改
# 前缀:
spring.thymeleaf.prefix=classpath:/templates/
# 后缀:
spring.thymeleaf.suffix=.html
  1. 在默认配置下,thymeleaf.html的内容要求很严格,建议增加下面的配置:
#去掉html5语法验证
spring.thymeleaf.mode=LEGACYHTML5

spring.thymeleaf.mode的默认值是HTML5,其实是一个很严格的检查,改为LEGACYHTML5可以得到一个可能更友好亲切的格式要求。

使用该配置时,需要额外引入NekoHTML库,相关依赖:

<dependency>
    <groupId>net.sourceforge.nekohtml</groupId>
    <artifactId>nekohtml</artifactId>
</dependency>

3. 后端通过Model传值

通过Model对象将后台的值传递回前台,Model对象实际上是将后台的数据放到了request作用域中,也可以使用HttpServletRequest对象进行传值,但是在idea中会显示报错,且没有提示,但是值可以正常取出来。推荐使用Model对象

@Controller
public class ThymeleafController {

    @RequestMapping("/leaf")
    public String leaf(Model model) {
        model.addAttribute("data", "SpringBoot集成Thymeleaf");
        return "aa";
    }
}

4. 创建Thymeleaf文件

Springboot 使 用 thymeleaf 作 为 视 图 展 示 , 约 定 将 模 板 文 件 放 置 在 src/main/resource/templates 目录下,静态资源放置在 src/main/resource/static 目录下。

在templates新建一个普通的HTML5文件,然后在html标签中添加属性:xmlns:th="http://www.thymeleaf.org"就可以了

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

三、Thymeleaf表达式

1. 标准变量表达式

  • 语法:${…}
  • 说明:
    • 标准变量表达式用于访问容器(tomcat)上下文环境中的变量,功能和 EL 中的 ${} 相同。 Thymeleaf 中的变量表达式使用 ${变量名} 的方式获取 Controller 中 model 其中的数据
  • 使用:
    <span th:text="${user.id}"></span>
    

Thymeleaf中所有的表达式都需要写在"指令"中,指令是HTML5中的自定义属性,在Thymeleaf中所有指令都是以th:开头。表达式${user.name}是写在自定义属性中,因此在静态环境下,表达式的内容会被当做是普通字符串,浏览器会自动忽略这些指令,这样就不会报错了。

(1)访问Request作用域中的值

假设 request 作用域中存在键值对:"key"=value,可以使用
使用标准变量表达式:

<span th:text="${#httpServletRequest.getAttribute('key')}"></span>
或者:<span th:text="${key}"></span>
  • 注意
    • 因为Model中的值本质上是在request作用域中存储的,所以两者的取值方法可以混用
    • 有些标准变量表达式在IDEA中可能会报错,但是在运行时依旧可以取到值

(2)访问Session会话作用域中的值

假设session 作用域中存在键值对:"key"=value
使用标准变量表达式需要加个前缀 session

<span th:text="${session.key}"></span>

(3)访问Application全局作用域中的值

假设 application 作用域中存在键值对:"key"=value
使用标准变量表达式需要加个前缀 application

<span th:text="${application.key}"></span>

(4)空值处理(重要)

语法:${对象名?.属性名}

如果一个对象可能为 null 时,并且要获取该对象的属性时,这时需要在该对象后面加一个"?",当一个为 null 的对象去获取一个属性时,会报TemplateInputException(模板输入/解析异常)

2. 选择变量表达式

  • 语法: *{…}
  • 说明:
    选择变量表达式,也叫星号变量表达式,使用 th:object 属性来绑定对象;也可以不使用 th:object 属性来绑定对象,则使用方法与${}相同
  • 使用:
    <div th:object="${user}">
        用户编号:<span th:text="*{id}"></span><br/>
        用户姓名:<span th:text="*{name}"></span><br/>
    </div>
    

3. URL 表达式

  • 语法:@{…}
  • 说明:
    主要用于链接、地址的展示, 可用于<script src="..."><link href="..."><a href="..."><form action="..."><img src="">等,可以在 URL 路径中动态获取数据

在 URL 表达式前加/,会自动加上上下文根,即上下文相关。

  • 绝对的URL,比如 http://www.thymeleaf.org

  • 相对URL,可以是:

    • 页面相对,像 user/login.html
    • 上下文相关,如/itemdetails?id=3(服务器中的上下文名称将自动添加)
    • 与服务器相关,~/billing/processInvoice(允许在同一服务器中调用另一个上下文(=应用程序)中的URL)。
    • 协议相对URL,如 //code.jquery.com/jquery-2.0.3.min.js
<h1>绝对路径</h1>
<a th:href="@{http://localhost:8080/thymeleaf/info}">绝对路径</a>
<a th:href="@{'http://localhost:8080/thymeleaf/user/info?id='+${user.id}}">绝对路径(带参数)</a>

<h1>相对路径,常用</h1>
<a th:href="@{/thymeleaf/info}">相对路径</a>
<a th:href="@{'/thymeleaf/user/info?id=' + ${user.id}}">相对路径(带参数)(字符串拼接) </a>
<a th:href="@{/thymeleaf/info(id=${user.id}, name=${user.name})}">推荐:带多个参数路径写法</a>

四、常见属性

因为我们 Thymeleaf 是以 html 为载体的,所以 html 不会认识${}语法。

我们请求的流程是,发送请求给服务器,服务器接收请求后,处理请求,跳转到指定的静态 html 页面,在服务器端, Thymeleaf 模板引擎会按照它的语法, 对动态数据进行处理。所以如果要是 th 开头,模板引擎能够识别,会在服务器端进行处理,获取数据;如果没有以 th开头,那么 Thymeleaf 模板引擎不会处理,直接返回给客户端了。

1. th:action

th:action:定义后台控制器的路径,类似<form>标签的 action 属性,主要结合 URL 表达式,获取动态变量

2. th:method

设置请求方法

3. th:href

定义超链接, 主要结合 URL 表达式,获取动态变量

4. th:src

用于外部资源引入,比如<script>标签的 src 属性, <img>标签的 src 属性,常与@{}表达式结合使用。

SpringBoot 项目的静态资源都放到 resources 的 static 目录下。放到 static 路径下的内容,写路径时不需要写上 static

<!--以下方式无法引入 js-->
<script src="/static/js/jquery-1.7.2.min.js"></script>
<!--该方法是常用方法-->
<script type="text/javascript" th:src="@{/jquery-1.7.2.min.js}"></script>

5. th:id/name/value

替换 html 标签中的 id,name,value 属性

6. th:attr

该属性也是用于给 HTML 中某元素的某属性赋值,好处是可以给 html 中没有定义的属性动态的赋值。

<span zhangsan="${user.name}">该方法赋值不成功</span>

<!--通过 th:attr 对自定义的属性赋值-->
<span th:attr="zhangsan=${user.name}">可以赋值成功</span>

7. th:text

用于文本的显示,该属性显示的文本在标签体中,即两个标签对之间。如果是表单标签,使用th:value

8. th:object

用于数据对象绑定,通常用于选择变量表达式(星号表达式)

9. th:onclick

目前 thymeleaf 版本要求只能传递数字和布尔值

<!--目前 thymeleaf 版本要求只能传递数字和布尔值-->
<a th:onclick="'show(' + ${user.id} + ')'">点击:显示学生编号</a>
<script type="text/javascript">
	function show(id) {
		alert("用户编号为: " + id);
	}
</script>

10. th:inline

(1)内敛文本(th:inline=”text”)

内敛文本表达式不依赖于 html 标签,直接使用内敛表达式[[表达式]]即可获取动态数据(相当于是加了两个方括号的EL表达式了), 但必须要求在父级标签上加 th:inline = “text”属性

注意:一般我们将内联文本放到<body th:inline="text">标签中

<div th:inline="text">
	用户编号: <div>[[${user.id}]]</div><br/>
	用户姓名: [[${user.name}]]<br/>
</div>

(2)内敛脚本(th:inline=”javascript”)

th:inline="javascript"用于 js 代码中获取后台的动态数据

<script type="text/javascript" th:inline="javascript">
	function showInlineJavaScript() {
		alert("我叫 " + [[${user.name}]] + " 联系方式: " + [[${user.phone}]]);
	}
</script>

注意:在内敛脚本中使用可能为 null 的对象去获取属性时,一定要使用${对象名.属性名},即使先进行的判空处理(在这踩坑了)。如:

<script type="text/javascript" th:inline="javascript">
	if([[${user != null}]]) {
		//虽然先进行的判断,user不为null,但是thymeleaf在解析内敛脚本时,与html代码不同,是不会跳过代码的,所以user.name也会正常解析
		//当user为null时,就会报TemplateInputException
		alert("我叫 " + [[${user?.name}]] + " 联系方式: " + [[${user?.phone}]]);
	}
</script>

11. th:fragment / include / replace

(1)th:fragment

用于在页面中指定一个通用(复用)的代码片段,例如在页面 common/view1.html 中有如下定义:

<div th:fragment="pageHead">
	一些代码,比如说同一个网站每个页面的头和尾都相同,将公共的代码抽取出来写在这里
</div>

(2)th:include

在页面中引入 th:fragment 定义的代码片段,主要有下面三种形式:

  • th:inclued="view::selector":"::"前面是模板文件名,后面是选择器
  • ::selector:只写选择器,这里指fragment名称,则加载本页面对应的fragment
  • view或者"view::html":只写模板文件名或者使用 html 标签,则加载整个页面

比如说,加载(1)中 th:fragment 定义的代码片段:

<div th:include="common/view1::pageHead"></div>

(3)th:replace

th:replace 和 th:include 都是加载代码块内容,但是还是有所不同

  • th:include:加载模板的内容: 读取加载节点的内容(不含节点名称),替换div内容

  • th:replace:替换当前标签为模板中的标签,加载的节点会整个替换掉加载它的div

  • 例如:

    <!-- th:fragment 定义用于加载的块 -->
    <span th:fragment="view"> 
    这是公共部分
    </span>
    
  • 引用时如下:

    include:
    <div th:include="pagination::view">1</div>
    replace:
    <div th:replace="pagination::view">2</div>
    
  • 结果如下:

    include:
    <div>这是公共部分</div>
    replace:
    <span>这是公共部分</span>
    

12. th:style

设置样式

13. th:class

设置CSS选择器

大部分的html标签都有thymeleaf相对应的属性,这里就不一一列举出来了,在IDEA中,打个th:之后有提示的,拿过来使用即可

五、条件与循环

1. th:each(重点)

这个属性非常常用,比如从后台传来一个对象集合那么就可以使用此属性遍历输出,它与 JSTL 中的<c: forEach>类似,此属性既可以循环遍历集合,也可以循环遍历数组Map

  • 语法:th:each="user , iterStat : ${userList}"或者th:each="user : ${userList}"
    • 第一个参数:定义变量,接收集合中的一个元素
    • 第二个参数:记录循环体信息,也可以不定义,则默认变量名为迭代变量名加上 Stat 后缀,即 userStat
      • index:当前迭代对象的 index(从 0 开始计算)
      • count:当前迭代对象的个数(从 1 开始计算) 这两个用的较多
      • size:被迭代对象的大小
      • current:当前迭代变量
      • even/odd:布尔值,当前循环是否是偶数/奇数(从 0 开始计算)
      • first:布尔值,当前循环是否是第一个
      • last:布尔值,当前循环是否是最后一个
    • 第三个参数:后台传回来的参数
    • 第一个参数和第二个参数之间使用",“隔开,第二个参数和第三个参数之间使用”:"隔开
<h1>遍历集合或者数组</h1>
<div th:each="user,userStat:${userList}">
	<span th:text="${userStat.index}"></span>
	<span th:text="${user.id}"></span>
	<span th:text="${user.name}"></span>
</div>

<h1>遍历map,每个元素就是一个键值对,通过key和value来取出键或者值</h1>
<tr th:each="userMap:${userMaps}">
    <td th:text="${userMap.key}"></td>
    <td th:text="${userMap.value}"></td>
    <td th:text="${userMap.value.name}"></td>
</tr>

2. th:if/unless

th:if是条件满足则执行,th:unless相反,条件不满足时执行

<!--sex等于1则显示男,sex等于0则显示女-->
<div th:if="${sex eq 1}">
	男: <input type="radio" name="sex" th:value="1"/>
</div>
<div th:if="${sex eq 0}">
	女: <input type="radio" name="sex" th:value="0"/>
</div>

3. th:switch/th:case

一旦某个 case 判断值为 true,剩余的 case 默认不执行,"*"表示默认的 case,前面的 case 都不匹配时候,执行默认的 case

<h1>th:switch/th:case 用法</h1>
<div th:switch="${sex}">
	<span th:case="1">性别:男</span><br/>
	<span th:case="2">性别:女</span><br/>
	<span th:case="*">性别:保密</span>
</div>

六、字面量

字面量:对应数据类型的合法取值,可以在 html 页面直接使用,不需要后台传递

  • 文本字面量:用单引号'...'包围的字符串为文本字面量
  • 数字字面量
  • boolean 字面量
  • null 字面量
<h1>文本字面量:用单引号'...'包围的字符串</h1>
<a th:href="@{'/user/info?id=' + ${user.id}}">文本字面的路径使用</a><br/>

<h1>数字字面量</h1>
<span th:text="${1949 + 70}">1949</span><br/>

<h1>boolean字面量</h1>
<div th:if="${success}">执行成功</div>

<h1>null 字面量</h1>
<span th:if="${user ne null}">用户不为空</span><br/>

七、字符串拼接

除了使用加号拼接文本字面量之外,可以使用"|要拼接的内容|"来进行拼接

<h1>文本字面量使用"+"拼接字符串</h1>
<span th:text="'共' + ${totalRows} + '条'+${totalPage} + '页,当前第' + ${currentPage} + '页'"></span>
	
<h1>使用"|要拼接的内容|"拼接字符串,最后的结果与上面的相同</h1>
<span th:text="|共${totalRows}条${totalPage}页,当前第${currentPage}页|"></span>

八、运算符

  • 三元运算:表达式?“正确结果”:“错误结果”
  • 算术运算: +,-,*,/,%
  • 关系比较: >,<,>=,<= (gt,lt, ge,le)
  • 相等判断: ==,!= (eq,ne)

九、表达式基本对象

模板引擎提供了一组内置的对象,这些内置的对象可以直接在模板中使用,这些对象由"#"号开始引用,我们比较常用的内置对象

1. #request

#request 相 当 于java中 HttpServletRequest 对 象 , 这 是 3.x 版 本 , 若 是 2.x 版 本 使 用 #httpServletRequest, 一般用于在页面获取应用的上下文根,一般在 js 中请求路径中加上可以避免 404

  • 获取协议名称:var scheme = [[${#request.getScheme()}]];
  • 获取服务 IP 地址:var serverName = [[${#request.getServerName()}]];
  • 获取服务端口号:var serverPort = [[${#request.getServerPort()}]];
  • 获取上下文根:var contextPath = [[${#request.getContextPath()}]];
<script type="text/javascript" th:inline="javascript">
	var basePath = [[${#httpServletRequest.getScheme() + "://" + 
					#httpServletRequest.getServerName() + ":" + 
					#httpServletRequest.getServerPort() + 
					#httpServletRequest.getContextPath()}]];
</script>

2. #session

相当于java中的 HttpSession 对象,这是 3.x 版本,若是 2.x 版本使用#httpSession

<h1>从 SESSION 中获取用户名称</h1>
<span th:text="${#httpSession.getAttribute('username')}"></span>

3. 其它对象

模板引擎提供的一组功能性内置对象,可以在模板中直接使用这些对象提供的功能方法工作中常使用的数据类型,如集合,时间,数值,可以使用 Thymeleaf 的提供的功能性对象来处理它们
内置功能对象前都需要加#号,内置对象一般都以 s 结尾

  • #dates:java.util.Date 对象的实用方法:

    <span th:text="${#dates.format(curDate, 'yyyy-MM-dd HH:mm:ss')}"></span>
    
  • #calendars:和 dates 类似, 但是 java.util.Calendar 对象;

  • #numbers:格式化数字对象的实用方法;

  • #strings:字符串对象的实用方法: contains,startsWith,prepending/appending,replace 等;

    <span th:text="${#strings.replace('目标字符串', '被替换的字符串', '替换后的字符串')}"></span>
    
  • #objects:对 objects 操作的实用方法;

  • #bools:对布尔值求值的实用方法;

  • #arrays:数组的实用方法;

  • #lists:list 的实用方法,比如

    <span th:text="${#lists.size(datas)}"></span>
    
  • #sets:set 的实用方法;

  • #maps:map 的实用方法;

  • #aggregates:对数组或集合创建聚合的实用方法;

 类似资料: