本文最后更新于 2024-07-03,文章内容可能已经过时。
1、前言 {#1-前言}
最近想学习一下 halo 主题开发,也为了修改一些现有主题供自己使用(由于大多数主题都是用了 thymeleaf 语法)所以浅浅的学习并记录一下常用语法,方便回头查看。
Thymeleaf 作为一种模板引擎,它拥有自己的语法规则。主要由如下两类:
- 标准表达式语法
- th 开头的相关属性
2、标准表达式语法 {#2-标准表达式语法}
2.1 变量表达式 {#2-1-变量表达式}
- 获取对象的属性和方法,和 js 的模版语法无异,语法如下:
# obj 为一个java对象,attribute为其中的一个属性,想要获取该属性则使用下面的语法
${obj.attribute}
-
使用内置的对象和一些方法
#ctx :上下文对象;
#vars :上下文变量;
#locale:上下文的语言环境;
#request:HttpServletRequest 对象(仅在 Web 应用中可用);
#response:HttpServletResponse 对象(仅在 Web 应用中可用);
#session:HttpSession 对象(仅在 Web 应用中可用);
#servletContext:ServletContext 对象(仅在 Web 应用中可用)。
<!-- 示例如下,比如获取到 session 对象中的 map --> ${#session.getAttribute('map')}${session.map}
-
使用一些内置的工具类
strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等; 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 等。
例如,对一段字符串去除空格:
${#strings.trim(str)}
2.2、选择变量表达式 {#2-2-选择变量表达式}
使用场景:
选择变量表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object 的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代中使用选择变量表达式(*{...})获取该对象中的属性,其中,"*"即代表该对象。
<div th:object="${session.user}" > <p th:text="*{fisrtName}">firstname</p></div>
2.3、 a 标签表达式 {#2-3--a-标签表达式}
不管是静态资源的引用,还是 form 表单的请求,凡是链接都可以用链接表达式 (@{...})。
链接表达式的形式结构如下:
- 无参请求:@{/xxx}
- 有参请求:@{/xxx(k1=v1,k2=v2)}
例如使用链接表达式引入 css 样式表,代码如下。
<link href="asserts/css/signin.css" th:href="@{/assets/css/signin.css}" rel="stylesheet">
2.4、 国际化表达式 {#2-4--国际化表达式}
消息表达式一般用于国际化的场景。结构如下。
th:text="#{msg}"
2.5、片段引用表达式 {#2-5-片段引用表达式}
片段引用表达式用于在模板页面中引用其他的模板片段,该表达式支持以下 2 中语法结构:
- 推荐:~{templatename::fragmentname}
- 支持:~{templatename::#id}
以上语法结构说明如下:
- templatename:模版名,Thymeleaf 会根据模版名解析完整路径:/resources/templates/templatename.html,要注意文件的路径。
- fragmentname:片段名,Thymeleaf 通过 th:fragment 声明定义代码块,即:th:fragment="fragmentname"
- id:HTML 的 id 选择器,使用时要在前面加上 # 号,不支持 class 选择器。
3、th 开头的一些常用属性 {#3-th-开头的一些常用属性}
th:text 文本替换,转义特殊字符
<p th:text="hello world" >hello</p>
th:utext 文本替换,不转义特殊字符
div th:utext="'<h1>hello!</h1>'" >欢迎你</div>
th:object 在父标签选择对象,子标签使用 *{...} 选择表达式选取值。没有选择对象,那子标签使用选择表达式和 ${...} 变量表达式是一样的效果。同时即使选择了对象,子标签仍然可以使用变量表达式。
<div th:object="${session.user}" > <p th:text="*{fisrtName}">firstname</p></div>
th:id 替换 HTML 的 id 属性
<input id="html-id" th:id="thymeleaf-id" />
th:value 替换表单元素的 value 属性
<input th:value = "${user.name}" />
th:onclick 点击事件
<td th:onclick = "'getInfo()'"></td>
th:with 局部变量赋值运算
<div th:with="isEvens = ${prodStat.count}%2 == 0" th:text="${isEvens}"></div>
th:style 设置样式
<div th:style="'color:#F00; font-weight:bold'">hello world</div>
th:each 遍历数据,支持 Iterable、Map、List、数组等。
<table>
<tr th:each="m:${session.map}">
<td th:text="${m.getKey()}"></td>
<td th:text="${m.getValue()}"></td>
</tr>
</table>
th:if 根据条件判断是否需要展示此标签
<a th:if ="${userId == collect.userId}">
th:unless 和 th:if 判断相反,满足条件时不显示
<div th:unless="${m.getKey()=='name'}" ></div>
th:switch 与 Java 的 switch case语句类似,通常与 th:case 配合使用,根据不同的条件展示不同的内容
<div th:switch="${name}">
<span th:case="a">casea</span>
<span th:case="b">caseb</span>
</div>
th:fragment 模板布局,类似 JSP 的 tag,用来定义一段被引用或包含的模板片段
<div th:insert="commons/bar::footer"></div>
th:insert 布局标签;将使用 th:fragment 属性指定的模板片段(包含标签)插入到当前标签中。
<div th:insert="commons/bar::footer"></div>
th:replace 布局标签;使用 th:fragment 属性指定的模板片段(包含标签)替换当前整个标签。
<div th:replace="commons/bar::footer"></div>
th:selected select 选择框选中
<select>
<option>---</option>
<option th:selected="${name=='a'}">a</option>
<option th:selected="${name=='b'}">b</option>
</select>
th:src 替换 HTML 中的 src 属性
<img th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" />
th:inline 内联属性;该属性有 text、none、javascript 三种取值,在 标签中使用时,js 代码中可以获取到后台传递页面的对象。
<script type="text/javascript" th:inline="javascript">
var name = /*[[${name}]]*/ 'halo';
alert(name)
</script>
th:action 替换表单提交地址
<form th:action="@{/user/login}" th:method="post"></form>
4、使用 Thymeleaf 抽取公共页面 {#4-使用-Thymeleaf-抽取公共页面}
简单来说,就是增加代码的可复用性,比如 web 应用的 header、footer是公用的,需要被抽离出来!
Thymeleaf 作为一种优雅且高度可维护的模板引擎,同样支持公共页面的抽取和引用。我们可以将公共页面片段抽取出来,存放到一个独立的页面中,并使用 Thymeleaf 提供的 th:fragment 属性为这些抽取出来的公共页面片段命名。
示例:
比如有一个 public.html 的公共模版,对其命名为 fragment-name
<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
现在将 public.html
文件中的片段引入其他页面,可使用如下语法:
<!--th:insert 片段名引入-->
<div th:insert="public::fragment-name"></div>
<!--th:insert id 选择器引入-->
<div th:insert="public::#fragment-id"></div>
<!--th:replace 片段名引入-->
<div th:replace="public::fragment-name"></div>
<!--th:replace id 选择器引入-->
<div th:replace="public::#fragment-id"></div>
<!--th:include 片段名引入--> <div th:include="public::fragment-name"></div> <!--th:include id 选择器引入--> <div th:include="public::#fragment-id"></div>
以上代码使用了 th:insert
、th:replace
、th:iclude
引入了模版片段,三者有如下的不同之处:
- th:insert:将代码块片段整个插入到使用了 th:insert 属性的 HTML 标签中;
- th:replace:将代码块片段整个替换使用了 th:replace 属性的 HTML 标签中;
- th:include:将代码块片段包含的内容插入到使用了 th:include 属性的 HTML 标签中
而使用上 3 个属性引入页面片段,都可以通过以下 2 种方式实现。
- ~{templatename::selector}:模板名::选择器
- ~{templatename::fragmentname}:模板名::片段名
通常情况下,~{} 可以省略,其行内写法为 [[~{...}]] 或 [(~{...})],其中 [[~{...}]] 会转义特殊字符,[(~{...})] 则不会转义特殊字符。
5、传递参数 {#5-传递参数}
Thymeleaf 在抽取和引入公共页面片段时,还可以进行参数传递。
引用公共页面片段时,我们可以通过以下 2 种方式,将参数传入到被引用的页面片段中:
- 模板名::选择器名或片段名(参数1=参数值1,参数2=参数值2)
- 模板名::选择器名或片段名(参数值1,参数值2)
注意点⚠️
若传入参数较少时,一般采用第二种方式,直接将参数值传入页面片段中; 若参数较多时,建议使用第一种方式,明确指定参数名和参数值,。
示例:
在片段中传入参数:
<!--th:insert 片段名引入-->
<div th:insert="public::fragment-name(var1='insert-name',var2='insert-name2')"></div>
<!--th:insert id 选择器引入-->
<div th:insert="public::#fragment-id(var1='insert-id',var2='insert-id2')">
</div>
<!--th:replace 片段名引入-->
<div th:replace="public::fragment-name(var1='replace-name',var2='replace-name2')"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id(var1='replace-id',var2='replace-id2')"></div>
<!--th:include 片段名引入--> <div th:include="public::fragment-name(var1='include-name',var2='include-name2')"></div> <!--th:include id 选择器引入--> <div th:include="commons::#fragment-id(var1='include-id',var2='include-id2')"></div>
在片段中使用参数:
<!--使用 var1 和 var2 声明传入的参数,并在该片段中直接使用这些参数 -->
<div th:fragment="fragment-name(var1,var2)" id="fragment-id">
<p th:text="'参数1:'+${var1} + '-------------------参数2:' + ${var2}">...</p>
</div>
暂时先记录到这儿,在使用过程中慢慢记录一些特殊语法和踩坑记录吧!