可以从官网下载PDF进行参考:

​https://www.thymeleaf.org/documentation.html​

Thymeleaf - 语法使用详解_Thymeleaf

或者在线参考文档:

​https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html​

Thymeleaf - 语法使用详解_Thymeleaf_02


一个好的习惯是,每一个HTML页面引入Thymeleaf的名称空间:

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

【1】th:text和th:utext

th:text 将div里面的文本内容设置为动态取的值,如果有标签则进行转义,不让标签生效。

示例如下:

<div th:text="${hello}"></div>

th:utext 非转义文本,将div里面的文本内容原样输出设置为动态取的值。

<div th:utext="${hello}"></div>

后台代码如下:

@RequestMapping("/success")
public String success(Map<String,Object> map){
map.put("hello","<h1>你好</h1>");
map.put("users",Arrays.asList("zhangsan","lisi","wangwu"));
return "success";
}

结果如下:

Thymeleaf - 语法使用详解_html_03

查看网页源代码如下:

<div><h1>你好</h1></div>
<div><h1>你好</h1></div>

【2】th标签任意属性

th:任意html属性,来替换原生属性的值。

th:id/class及标签体内容

<div id="div01" class="myDiv" th:id="${hello}" 
th:class="${hello}" th:text="${hello}">这是显示欢迎信息</div>

th:href:

<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">

//两个表达式拼接
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.id}">编辑</a>

th:action

<form class="form-signin" action="dashboard.html" th:action="@{/user/login}" method="post">

th:src

<img th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" />

th:if

<p th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

<input type="hidden" name="_method" value="put" th:if="${emp!=null}"/>

th:placeholder

<input type="text" placeholder="Username" th:placeholder="#{login.username}">

th:selected

<option th:selected="${emp!=null}?${dept.id == emp.department.id}"
th:value="${dept.id}" th:each="dept:${depts}"
th:text="${dept.departmentName}">1</option>

th:checked

<input class="form-check-input" type="radio" name="gender" value="0"
th:checked="${emp!=null}?${emp.gender==0}">

<div class="layui-input-block">
<input type="radio" th:checked="${equipment.state==1}" value="1" name="state"
lay-skin="primary" title="出库">
<input type="radio" th:checked="${equipment.state==2}" value="2" name="state"
lay-skin="primary" title="入库">
</div>

th:value

<input type="hidden" name="id" th:if="${emp!=null}" th:value="${emp.id}">

th:attr
使用该标签为任意属性赋值,包括自定义属性。

//等同于th:value
<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>

//为button设置自定义属性del_uri
<button th:attr="del_uri=@{/emp/}+${emp.id}" class="btn btn-sm btn-danger deleteBtn">删除</button>

//设置多个属性值
<img src="../../images/gtvglogo.png"
th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

th:attrappend

<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />
//等同于如下
<input type="button" value="Do it!" class="btn warning" />

【3】th属性优先级

属性优先级

既然可以写多个任意属性,那么肯定牵涉到属性生效的优先级问题。HTML并没有这种设置,幸运的是Thymeleaf有属性优先级设定。

Thymeleaf - 语法使用详解_html_04


【4】标准表达式语法

Thymeleaf提供了一系列语法、内置对象和工具方法来帮助我们开发。

① Simple expressions(五种基本表达式):

Variable Expressions: ${...}
Selection Variable Expressions: *{...}
Message Expressions: #{...}
Link URL Expressions: @{...}
Fragment Expressions: ~{...}

② Literals(字面量)

Text literals: 'one text' , 'Another one!' ,…
Number literals: 0 , 34 , 3.0 , 12.3 ,…
Boolean literals: true , false
Null literal: null
Literal tokens: one , sometext , main ,…

③ Text operations(文本操作):

String concatenation: +
Literal substitutions: |The name is ${name}|

④ Arithmetic operations(数学运算):

Binary operators: + , - , * , / , %
Minus sign (unary operator): -

⑤ Boolean operations(布尔操作):

Binary operators: and , or
Boolean negation (unary operator): ! , not

⑥ Comparisons and equality(比较运算):

Comparators: > , < , >= , <= ( gt , lt , ge , le )
Equality operators: == , != ( eq , ne )

⑦ Conditional operators(条件运算):

If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)

⑧ Special tokens(特殊语法):

No-Operation: _

【5】变量表达式 ${…}

We already mentioned that ${…} expressions are in fact OGNL (Object-Graph Navigation Language) expressions executed on the map of variables contained in the context.

① 其语法示例如下:

/*
* Access to properties using the point (.). Equivalent to calling property getters.
*/
${person.father.name}
/*
* Access to properties can also be made by using brackets ([]) and writing
* the name of the property as a variable or between single quotes.
*/
${person['father']['name']}
/*
* If the object is a map, both dot and bracket syntax will be equivalent to
* executing a call on its get(...) method.
*/
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}
/*
* Indexed access to arrays or collections is also performed with brackets,
* writing the index without quotes.
*/
${personsArray[0].name}
/*
* Methods can be called, even with arguments.
*/
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

② Expression Basic Objects

When evaluating OGNL expressions on the context variables, some objects are made available to expressions for higher flexibility. These objects will be referenced (per OGNL standard) starting with the # symbol:

#ctx : the context object.
#vars: the context variables.
#locale : the context locale.
#request : (only in Web Contexts) the HttpServletRequest object.
#response : (only in Web Contexts) the HttpServletResponse object.
#session : (only in Web Contexts) the HttpSession object.
#servletContext : (only in Web Contexts) the ServletContext object.

示例如下:

${#locale.country}"
${#request.getAttribute('foo')}
${#request.getParameter('foo')}
${#request.getContextPath()}
${#request.getRequestName()}
//具体参考官方文档的附录A

③ Expression Utility Objects

Besides these basic objects, Thymeleaf will offer us a set of utility objects that will help us perform common tasks in our expressions.

这个很给力,提供了一系列工具类对象来帮助我们进行页面开发。

#execInfo : information about the template being processed.

#messages : methods for obtaining externalized messages inside variables expressions, in the same way as they
would be obtained using #{…} syntax.

#uris : methods for escaping parts of URLs/URIs

#conversions : methods for executing the configured conversion service (if any).
#dates : methods for java.util.Date objects: formatting, component extraction, etc.

#calendars : analogous to #dates , but for java.util.Calendar objects.

#numbers : methods for formatting numeric objects.

#strings : methods for String objects: contains, startsWith, prepending/appending, etc.

#objects : methods for objects in general.

#bools : methods for boolean evaluation.

#arrays : methods for arrays.

#lists : methods for lists.

#sets : methods for sets.

#maps : methods for maps.

#aggregates : methods for creating aggregates on arrays or collections.

#ids : methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).

示例如下:

${#calendars.format(cal)}
${#calendars.arrayFormat(calArray)}
${#numbers.formatInteger(num,3)}
${#numbers.arrayFormatInteger(numArray,3)}
${#strings.isEmpty(name)}
${#strings.arrayIsEmpty(nameArr)}
${#objects.nullSafe(obj,default)}
${#objects.arrayNullSafe(objArray,default)}
//...具体参考附录B

页面示例如下:

<p style="color: red" th:text="${msg}" 
th:if="${not #strings.isEmpty(msg)}">
</p>

【6】选择表达式{…}*

Not only can variable expressions be written as ${…} , but also as *{…} .

There is an important difference though: the asterisk syntax evaluates expressions on selected objects rather than on the whole context. That is, as long as there is no selected object, the dollar and the asterisk syntaxes do exactly the same.

And what is a selected object? The result of an expression using the th:object attribute. Let’s use one in our user profile ( userprofile.html ) page:

<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>

Which is exactly equivalent to:

<div>
<p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
</div>

Of course, dollar and asterisk syntax can be mixed:

<div th:object="${session.user}">
<p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
<p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>

*号表达是和Thymeleaf - 语法使用详解_html_05{session.user}">​​​,*号表达式可以直接使用​​th:text="*{firstName}`获取属性值。二者也可以同时混淆使用。


【7】Link URL@{…}

通常用来为页面的请求设置URL,示例如下:

① 使用全路径

<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html"
th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>

② 相对于项目根目录

<!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>

③ 路径中使用资源标识

<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>

th:href将会替换a标签中的href属性值。


④ 在form表单使用

<form th:action="@{/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit"/>
</form>

⑤ 在head link中引入CSS

<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">

⑥ URL多参数示例

@{/order/process(execId=${execId},execType='FAST')}

⑦ URL拼接

<a th:href="@{${url}(orderId=${o.id})}">view</a>
<a th:href="@{'/details/'+${user.login}(orderId=${o.id})}">view</a>

⑧ 自动拼接contextPath

Relative URLs starting with / (eg: /order/details ) will be 
automatically prefixed by the application context name.

这个是很友好的,Thymeleaf会自动将项目contextPath拼接在URL前面。

如项目contextPath分别为​​/ , /crud​​​,则使用​​@{/asserts/css/signin.css}​​分别显示如下:

/asserts/css/signin.css;
/crud/asserts/css/signin.css;

⑨ 支持URL重写

If cookies are not enabled or this is not yet known, a “;jsessionid=…” suffix might be added to relative URLs so that the session is preserved.

This is called URL Rewriting and Thymeleaf allows you to plug in your own rewriting filters by using the response.encodeURL(…) mechanism from the Servlet API for every URL.


【8】Fragments~{…}

片段引用表达式,类似于​​<jsp:include page="inlayingJsp.jsp" flush="true"/>​​​或者​​<%@ include file="inlayingJsp.jsp" %>​​​或者​​<c:import url="inlayingJsp.jsp"/>​​…等等还有很多其他类似方式。

即,在当前页面引入其他页面或者片段 !


① 在模板footer.html中定义被引用的片段

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</div>
</body>
</html>

② 在其他页面引用

<body>
...
<div th:insert="~{footer :: copy}"></div>
</body>

效果如下:

<body>
<div >
<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
</div>
</body>

③ 引入片段语法:

~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名
~{templatename}:将模板整个引入当前页面

其中,{}是可选的,可以不用使用{},示例如下:

<div th:insert="footer :: copy"></div>

但是行内写法的时候,需要将其包括

[[~{...}]] or [(~{...})]

模板名:选择器示例如下:

//模板页面
<div id="copy-section">
&copy; 2011 The Good Thymes Virtual Grocery
</div>
//引用页面
<body>
...
<div th:insert="~{footer :: #copy-section}"></div>
</body>

④ 三种不同形式的引用

模板页面如下:

<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>

引用示例如下:

<body>
...
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>

结果如下:

<body>
...
#th:insert--将模板片段插入当前标签内
<div>
<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
</div>
#th:replace--模板片段替换当前标签
<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
#th:include--去掉模板片段外标签然后将内容插入当前标签体
#(Thymeleaf3.0不再推荐使用)
<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
</body>

⑤ 参数化的片段标签

In order to create a more function-like mechanism for template fragments, fragments defined with th:fragment can specify a set of parameters:

模板页面(footer.html)示例如下:

//片段处写变量名
<div th:fragment="frag (onevar,twovar)">
<p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>

引用页面示例如下:

//直接传值
<div th:replace="footer::frag (${value1},${value2})">...</div>
//使用key:value形式传值
<div th:replace="footer::frag (onevar=${value1},twovar=${value2})">
...
</div>

需要注意的是,参数传递顺序可变:

<div th:replace="::frag (twovar=${value2},onevar=${value1})">
...
</div>

此外,甚至可以不用在模板片段处写变量:

<div th:fragment="frag">
...
</div>

此时只能只用第二种方式传递参数:

<div th:replace="footer::frag (onevar=${value1},twovar=${value2})">
...
</div>

【9】遍历th:each

后台代码如下:

@RequestMapping("/success")
public String success(Map<String,Object> map){
map.put("hello","<h1>你好</h1>");
map.put("users",Arrays.asList("zhangsan","lisi","wangwu"));
return "success";
}

页面如下:

<!-- th:each每次遍历都会生成当前这个标签: 3个h4 -->
<h4 th:text="${user}" th:each="user:${users}"></h4>
<hr/>
<h4>
<span th:each="user:${users}"> [[${user}]] </span>
</h4>

显示如下:

Thymeleaf - 语法使用详解_Thymeleaf_06

其中[[${user}]]叫做行内写法,官方说明如下:

Expressions between [[…]] or [(…)] are considered inlined expressions in Thymeleaf, and inside them we can use any kind of expression that would also be valid in a th:text or th:utext attribute.

Note that, while [[…]] corresponds to th:text (i.e. result will be HTML-escaped), [(…)] corresponds to th:utext and will not perform any HTML-escaping.


【10】th:if/unless条件判断

只有if条件成立,标签才会显示,示例如下:

<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
<th>COMMENTS</th>
</tr>
<tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
<td>
<span th:text="${#lists.size(prod.comments)}">2</span> comment/s
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
//如果comments不为空,则a标签显示,否则不显示。
</td>
</tr>
</table>

if 条件判断

  • If value is not null:
  • If value is a boolean and is true .
  • If value is a number and is non-zero
  • If value is a character and is non-zero
  • If value is a String and is not “false”, “off” or “no”
  • If value is not a boolean, a number, a character or a String.
  • (If value is null, th:if will evaluate to false).


th:unless

Also, th:if has an inverse attribute, th:unless , which we could have used in the previous example instead of using a not inside the OGNL expression:

<a href="comments.html"
th:href="@{/comments(prodId=${prod.id})}"
th:unless="${#lists.isEmpty(prod.comments)}">view</a>

效果等同于:

<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
//如果comments不为空,则a标签显示,否则不显示。