1、变量
${x}将返回x存储在Thymeleaf上下文中或作为请求属性的变量。${param.x}将返回一个称为的请求参数x(可能是多值)。${session.x}将返回名为的会话属性x。${application.x}将返回名为的Servlet上下文属性x。2、不转义
这是th:text属性的默认行为。如果我们希望Thymeleaf尊重我们的HTML标记而不是对其进行转义,则必须使用不同的属性:(th:utext用于“未转义的文本”):
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
3、使用和显示变量
该${today}表达式仅表示“获取今天调用的变量”,但是这些表达式可能更复杂(例如${user.name}“获取称为用户的变量并调用其getName()方法”)
4、标准表达式
我们已经看到了用这种语法表示的两种有效属性值:消息和变量表达式:
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
<p>Today is: <span th:text="${today}">13 february 2011</span></p>
简单表达式:
- 变量表达式:
${...} - 选择变量表达式:
*{...} - 消息表达:
#{...} - 链接URL表达式:
@{...} - 片段表达式:
~{...}
- 变量表达式:
文字
- 文本文字:
'one text','Another one!',… - 号码文字:
0,34,3.0,12.3,… - 布尔文字:
true,false - 空文字:
null - 文字标记:
one,sometext,main,…
- 文本文字:
文字操作:
- 字符串串联:
+ - 文字替换:
|The name is ${name}|
- 字符串串联:
算术运算:
- 二元运算符:
+,-,*,/,% - 减号(一元运算符):
-
- 二元运算符:
布尔运算:
- 二元运算符:
and,or - 布尔否定(一元运算符):
!,not
- 二元运算符:
比较和平等:
- 比较:
>,<,>=,<=(gt,lt,ge,le) - 等号运算符:
==,!=(eq,ne)
- 比较:
条件运算符:
- 如果-则:
(if) ? (then) - 如果-则-否则:
(if) ? (then) : (else) - 默认:
(value) ?: (defaultvalue)
- 如果-则:
特殊令牌:
无操作:
_所有这些功能都可以组合和嵌套:
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
5、消息
如果我们的应用程序知道随时有谁在访问该站点,而我们想按名称向他们打招呼,该怎么办?
<p th:utext="#{home.welcome(${session.user.name})}">
Welcome to our grocery store, Sebastian Pepper!
</p>
消息密钥本身可以来自变量
<p th:utext="#{${welcomeMsgKey}(${session.user.name})}">
Welcome to our grocery store, Sebastian Pepper!
</p>
6、变量
获取值的其他方式
/*
* 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('-')}
表达式基本对象
#ctx:上下文对象。#vars:上下文变量。#locale:上下文语言环境。#request:(仅在Web上下文中)HttpServletRequest对象。#response:(仅在Web上下文中)HttpServletResponse对象。#session:(仅在Web上下文中)HttpSession对象。#servletContext:(仅在Web上下文中)ServletContext对象。表达工具对象
除了这些基本对象之外,Thymeleaf将为我们提供一组实用程序对象,这些对象将帮助我们在表达式中执行常见任务。
#execInfo:有关正在处理的模板的信息。#messages:用于获取变量表达式内的外部化消息的方法,与使用#{…}语法获得消息的方法相同。#uris:用于转义部分URL / URI的方法#conversions:用于执行已配置的转换服务(如果有)的方法。#dates:java.util.Date对象的方法:格式化,组件提取等。#calendars:类似于#dates,但用于java.util.Calendar对象。#numbers:格式化数字对象的方法。#strings:String对象的方法:包含,startsWith,前置/附加等。#objects:一般对象的方法。#bools:布尔值评估的方法。#arrays:数组方法。#lists:列表方法。#sets:套方法。#maps:地图方法。#aggregates:用于在数组或集合上创建聚合的方法。#ids:用于处理可能重复的id属性的方法(例如,由于迭代的结果)。
<p>
Today is: <span th:text="${#calendars.format(today,'dd MMMM yyyy')}">13 May 2011</span>
</p>
7、选择表达式
只要没有选定的对象,美元和星号的语法就完全一样。
什么是选定对象?使用该th:object属性的表达式的结果。让我们在用户个人资料(userprofile.html)页面中使用一个:
<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>
完全等同于:
<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>
当然,美元和星号语法可以混合使用:
<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>
选择对象后,选定的对象也可以作为#object表达式变量用于美元表达式:
<div th:object="${session.user}">
<p>Name: <span th:text="${#object.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>
如前所述,如果尚未执行任何对象选择,则美元和星号语法是等效的。
<div>
<p>Name: <span th:text="*{session.user.name}">Sebastian</span>.</p>
<p>Surname: <span th:text="*{session.user.surname}">Pepper</span>.</p>
<p>Nationality: <span th:text="*{session.user.nationality}">Saturn</span>.</p>
</div>
8、链接网址
- 绝对网址:
http://www.thymeleaf.org - 相对URL,可以是:
- 相对页面:
user/login.html - 上下文相关:(
/itemdetails?id=3服务器中的上下文名称将自动添加) - 相对于服务器:(
~/billing/processInvoice允许在同一服务器中的另一个上下文(=应用程序)中调用URL。 - 相对协议网址:
//code.jquery.com/jquery-2.0.3.min.js
- 相对页面:
<!-- 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是修饰符属性:处理后,它将计算要使用的链接URL,并将该值设置href为<a>标记的属性。我们被允许对URL参数使用表达式(如您在中所见
orderId=${o.id})。所需的URL参数编码操作也将自动执行。如果需要几个参数,这些将用逗号分隔:
@{/order/process(execId=${execId},execType='FAST')}URL路径中也允许使用变量模板:
@{/order/{orderId}/details(orderId=${orderId})}以
/(例如:)开头的相对URL/order/details将自动以应用程序上下文名称作为前缀。如果未启用Cookie或尚不知道,则
";jsessionid=..."可能会将后缀添加到相对URL中,以便保留会话。这称为URL重写,Thymeleaf允许您通过使用response.encodeURL(...)Servlet API中的机制为每个URL插入自己的重写过滤器。该
th:href属性允许我们(可选)href在模板中具有有效的静态属性,以便当直接打开原型进行原型设计时,模板链接仍可被浏览器导航。
与消息语法(#{...})一样,URL基也可以是求值另一个表达式的结果:
<a th:href="@{${url}(orderId=${o.id})}">view</a>
<a th:href="@{'/details/'+${user.login}(orderId=${o.id})}">view</a>
token
实际上,数字,布尔值和null文字是文字标记的一种特殊情况。
这些标记允许在标准表达式中进行一些简化。它们的工作方式与文本文字('...')完全相同,但是它们仅允许使用字母(A-Z和a-z),数字(0-9),方括号([和]),点(.),连字符(-)和下划线(_)。因此,没有空格,没有逗号等。
好的部分?令牌不需要任何引号引起来。因此,我们可以这样做:
<div th:class="content">...</div>
代替:
<div th:class="'content'">...</div>
9、文本处理
等效于:
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">
文字替换可以与其他类型的表达式结合使用:
<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">
唯一的变量/消息表达式(${...},*{...},#{...})被允许内部|...|字面取代。没有其他文字('...'),布尔/数字标记,条件表达式等。
10、算术运算
<div th:with="isEven=(${prodStat.count} % 2 == 0)">
请注意,这些运算符也可以在OGNL变量表达式内部应用(在这种情况下,将由OGNL代替Thymeleaf标准表达式引擎执行):
<div th:with="isEven=${prodStat.count % 2 == 0}">
11、比较运算
XML规定,不得在属性值中使用<和>符号,因此需要转义
<div th:if="${prodStat.count} > 1">
<span th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')">
一个更简单的选择可能是使用以下某些运算符存在的文本别名:gt(>),lt(<),ge(>=),le(<=),not(!)。还有eq(==),neq/ ne(!=)。
12、条件表达式
<tr th:class="${row.even}? 'even' : 'odd'">
...
</tr>
条件表达式的所有三个部分(condition,then和else)本身的表达式,这意味着它们可以是变量(${...},*{...}),消息(#{...}),网址(@{...})或文字('...')
也可以使用括号嵌套条件表达式:
<tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'">
...
</tr>
其他表达式也可以省略,在这种情况下,如果条件为false,则返回null值:
<tr th:class="${row.even}? 'alt'">
...
</tr>
13、默认表达式
<div th:object="${session.user}">
...
<p>Age: <span th:text="*{age}?: '(no age specified)'">27</span>.</p>
</div>
等效于:
<p>Age: <span th:text="*{age != null}? *{age} : '(no age specified)'">27</span>.</p>
与条件值一样,它们可以在括号之间包含嵌套表达式:
<p>
Name:
<span th:text="*{firstName}?: (*{admin}? 'Admin' : #{default.username})">Sebastian</span>
</p>
14、无操作
No-Operation令牌由下划线符号(_)表示。
<span th:text="${user.name} ?: 'no user authenticated'">...</span>
…我们可以直接将*“未经用户身份验证”*用作原型文本,从设计的角度来看,这使得代码既简洁又通用:
<span th:text="${user.name} ?: _">no user authenticated</span>
15、数据转换/格式化
Thymeleaf为变量()和选择()表达式定义了一个双括号语法,该语法使我们能够通过配置的转换服务来应用数据转换。${...}``*{...}
它基本上是这样的:
<td th:text="${{user.lastAccessDate}}">...</td>
注意到那里有双括号了吗?:${{...}}。这指示Thymeleaf将user.lastAccessDate表达式的结果传递给*转换服务,*并要求它在写入结果之前执行格式化操作(转换为String)。
假设user.lastAccessDate类型为java.util.Calendar,如果已注册转换服务(的实现IStandardConversionService)并且包含的有效转换Calendar -> String,则将应用。
IStandardConversionService(StandardConversionService该类)的默认实现仅对.toString()转换为的任何对象执行String。有关如何注册自定义转换服务实现的更多信息,请参阅“更多关于配置”部分
16、预处理
预处理是在普通表达式之前执行的表达式的执行,该表达式允许修改最终将要执行的表达式。
预处理表达式与普通表达式完全一样,但是出现了一个双下划线符号(如__${expression}__)。
假设我们有一个i18nMessages_fr.properties条目,其中包含一个OGNL表达式,该表达式调用特定于语言的静态方法,例如:
article.text=@myapp.translator.Translator@translateToFrench({0})
…和Messages_es.properties equivalent:
article.text=@myapp.translator.Translator@translateToSpanish({0})
我们可以创建标记片段,该片段根据语言环境评估一个或另一个表达式。为此,我们将首先选择表达式(通过预处理),然后让Thymeleaf执行它:
<p th:text="${__#{article.text('textVar')}__}">Some text here...</p>
请注意,法语语言环境的预处理步骤将创建以下等效项:
<p th:text="${@myapp.translator.Translator@translateToFrench(textVar)}">Some text here...</p>
__可以使用来在属性中对预处理字符串进行转义\_\_。
17、设置属性值
然后输入th:attr属性及其更改设置的标签属性值的能力:
<form action="subscribe.html" th:attr="action=@{/subscribe}">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
</fieldset>
</form>
这个概念非常简单:th:attr只需采用一个为属性分配值的表达式。创建了相应的控制器和消息文件后,处理该文件的结果将是:
<form action="/gtvg/subscribe">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="¡Suscríbe!"/>
</fieldset>
</form>
除了新的属性值之外,您还可以看到应用程序上下文名称已自动前缀为中的URL库/gtvg/subscribe,如上一章所述。
但是,如果我们想一次设置多个属性怎么办?XML规则不允许您在标记中设置属性两次,因此th:attr将采用逗号分隔的分配列表,例如:
<img src="../../images/gtvglogo.png"
th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
给定所需的消息文件,将输出:
<img src="/gtgv/images/gtvglogo.png" title="Logo de Good Thymes" alt="Logo de Good Thymes" />
18、将属性设置为特定值
通常,您将使用其他th:*属性,这些属性的任务是设置特定的标记属性(而不仅仅是诸如之类的任何属性th:attr)。
例如,要设置value属性,请使用th:value:
<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
这类属性很多,每个属性都针对特定的HTML5属性:
th:abbr | th:accept | th:accept-charset |
|---|---|---|
th:accesskey | th:action | th:align |
th:alt | th:archive | th:audio |
th:autocomplete | th:axis | th:background |
th:bgcolor | th:border | th:cellpadding |
th:cellspacing | th:challenge | th:charset |
th:cite | th:class | th:classid |
th:codebase | th:codetype | th:cols |
th:colspan | th:compact | th:content |
th:contenteditable | th:contextmenu | th:data |
th:datetime | th:dir | th:draggable |
th:dropzone | th:enctype | th:for |
th:form | th:formaction | th:formenctype |
th:formmethod | th:formtarget | th:fragment |
th:frame | th:frameborder | th:headers |
th:height | th:high | th:href |
th:hreflang | th:hspace | th:http-equiv |
th:icon | th:id | th:inline |
th:keytype | th:kind | th:label |
th:lang | th:list | th:longdesc |
th:low | th:manifest | th:marginheight |
th:marginwidth | th:max | th:maxlength |
th:media | th:method | th:min |
th:name | th:onabort | th:onafterprint |
th:onbeforeprint | th:onbeforeunload | th:onblur |
th:oncanplay | th:oncanplaythrough | th:onchange |
th:onclick | th:oncontextmenu | th:ondblclick |
th:ondrag | th:ondragend | th:ondragenter |
th:ondragleave | th:ondragover | th:ondragstart |
th:ondrop | th:ondurationchange | th:onemptied |
th:onended | th:onerror | th:onfocus |
th:onformchange | th:onforminput | th:onhashchange |
th:oninput | th:oninvalid | th:onkeydown |
th:onkeypress | th:onkeyup | th:onload |
th:onloadeddata | th:onloadedmetadata | th:onloadstart |
th:onmessage | th:onmousedown | th:onmousemove |
th:onmouseout | th:onmouseover | th:onmouseup |
th:onmousewheel | th:onoffline | th:ononline |
th:onpause | th:onplay | th:onplaying |
th:onpopstate | th:onprogress | th:onratechange |
th:onreadystatechange | th:onredo | th:onreset |
th:onresize | th:onscroll | th:onseeked |
th:onseeking | th:onselect | th:onshow |
th:onstalled | th:onstorage | th:onsubmit |
th:onsuspend | th:ontimeupdate | th:onundo |
th:onunload | th:onvolumechange | th:onwaiting |
th:optimum | th:pattern | th:placeholder |
th:poster | th:preload | th:radiogroup |
th:rel | th:rev | th:rows |
th:rowspan | th:rules | th:sandbox |
th:scheme | th:scope | th:scrolling |
th:size | th:sizes | th:span |
th:spellcheck | th:src | th:srclang |
th:standby | th:start | th:step |
th:style | th:summary | th:tabindex |
th:target | th:title | th:type |
th:usemap | th:value | th:valuetype |
th:vspace | th:width | th:wrap |
th:xmlbase | th:xmllang | th:xmlspace |
19、一次设置多个值
有两个叫比较特殊的属性th:alt-title和th:lang-xmllang可用于同时设置两个属性相同的值。特别:
th:alt-title将设置alt和title。th:lang-xmllang将设置lang和xml:lang。<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />…或与此等效的:
<img src="../../images/gtvglogo.png" th:src="@{/images/gtvglogo.png}" th:title="#{logo}" th:alt="#{logo}" />…有了这个:
<img src="../../images/gtvglogo.png" th:src="@{/images/gtvglogo.png}" th:alt-title="#{logo}" />
20、前置追加和后置追加
Thymeleaf还提供th:attrappend和th:attrprepend属性,这些属性将求值结果附加(后缀)或前缀(前缀)到现有属性值。
<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />
如果将cssStyle变量设置为来处理此模板"warning",则会得到:
<input type="button" value="Do it!" class="btn warning" />
标准方言中还有两个特定的附加属性:th:classappend和th:styleappend属性,用于在元素上添加CSS类或样式片段而不覆盖现有属性:
<tr th:each="prod : ${prods}" class="row" th:classappend="${prodStat.odd}? 'odd'">
21、固定布尔值属性
例如checked:
<input type="checkbox" name="option2" checked /> <!-- HTML -->
<input type="checkbox" name="option1" checked="checked" /> <!-- XHTML -->
标准方言包含一些属性,这些属性使您可以通过评估条件来设置这些属性,因此,如果评估为true,则该属性将设置为其固定值,如果评估为false,则将不设置该属性:
<input type="checkbox" name="active" th:checked="${user.active}" />
标准方言中存在以下固定值布尔属性:
th:async | th:autofocus | th:autoplay |
|---|---|---|
th:checked | th:controls | th:declare |
th:default | th:defer | th:disabled |
th:formnovalidate | th:hidden | th:ismap |
th:loop | th:multiple | th:novalidate |
th:nowrap | th:open | th:pubdate |
th:readonly | th:required | th:reversed |
th:scoped | th:seamless | th:selected |
22、设置任何属性值
Thymeleaf提供了一个默认的属性处理器,即使我们在标准方言中没有为其定义任何特定的处理器,它也允许我们设置任何属性的值th:*。
所以像:
<span th:whatever="${user.name}">...</span>
将导致:
<span whatever="John Apricot">...</span>
23、迭代
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="../../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>
<body>
<h1>Product list</h1>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
</table>
<p>
<a href="../home.html" th:href="@{/}">Return to home</a>
</p>
</body>
</html>
即prod : ${prods}你看到上述手段的属性值“为在评估的结果的每个元素${prods},重复模板的该片段中,使用一个称为PROD可变当前元素”。让我们给每一个看到的事物命名:
- 我们将调用
${prods}的迭代式或迭代变量。 - 我们将调用
prod的迭代变量或者干脆ITER变量。
请注意,proditer变量的作用域为<tr>元素,这意味着它可用于内部标记(如)<td>
24、迭代状态
使用时th:each,Thymeleaf提供了一种用于跟踪迭代状态的有用机制:status变量。
状态变量在th:each属性中定义,并且包含以下数据:
- 当前的迭代索引,从0开始。这是
index属性。 - 从1开始的当前迭代索引。这是
count属性。 - 迭代变量中元素的总数。这是
size财产。 - 每次迭代的iter变量。这是
current财产。 - 当前迭代是偶数还是奇数。这些是
even/odd布尔属性。 - 当前迭代是否是第一个。这是
first布尔属性。 - 当前迭代是否为最后一次。这是
last布尔属性。
让我们看看如何在上一个示例中使用它:
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.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>
</tr>
</table>
iterStat在th:each属性中定义状态变量(在此示例中),方法是在iter变量本身之后写入名称,并用逗号分隔。就像iter变量一样,status变量的范围也由持有th:each属性的标签所定义的代码片段组成。
让我们看一下处理模板的结果:
<!DOCTYPE html>
<html>
<head>
<title>Good Thymes Virtual Grocery</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" />
</head>
<body>
<h1>Product list</h1>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr class="odd">
<td>Fresh Sweet Basil</td>
<td>4.99</td>
<td>yes</td>
</tr>
<tr>
<td>Italian Tomato</td>
<td>1.25</td>
<td>no</td>
</tr>
<tr class="odd">
<td>Yellow Bell Pepper</td>
<td>2.50</td>
<td>yes</td>
</tr>
<tr>
<td>Old Cheddar</td>
<td>18.75</td>
<td>yes</td>
</tr>
</table>
<p>
<a href="/gtvg/" shape="rect">Return to home</a>
</p>
</body>
</html>
如果您未明确设置状态变量,则Thymeleaf将始终通过Stat为迭代变量的名称添加后缀来为您创建一个:
25、条件表达式
有时,您需要模板的一部分才能仅在满足特定条件的情况下出现在结果中。
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
此外,th:if还有一个inverse(反转的/相反的)属性,th:unless我们可以在前面的示例中使用它,而不是not在OGNL表达式内部使用:
<a href="comments.html"
th:href="@{/comments(prodId=${prod.id})}"
th:unless="${#lists.isEmpty(prod.comments)}">view</a>
26、switch语句的使用
还有一种方法可以使用Java中的开关结构的等效条件来显示内容:th:switch/th:case属性集。
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
</div>
请注意,一旦有一个th:case属性的值为true,则其他的th:case同一切换上下文中的所有其他属性的值为false。
默认选项指定为th:case="*":
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
27、模板布局
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
</html>
上面的代码定义了一个片段copy,我们可以使用th:insert或th:replace属性之一轻松地将其包含在主页中(以及th:include,尽管从Thymeleaf 3.0开始不再建议使用它):
<body>
...
<div th:insert="~{footer :: copy}"></div>
</body>
请注意,th:insert需要一个片段表达式(~{...}),这是一个产生片段的表达式。但是,在上面的示例中,它是一个非复杂的片段表达式,(~{,})包围是完全可选的,因此上面的代码等效于:
<body>
...
<div th:insert="footer :: copy"></div>
</body>
模板规范语法:
片段表达式的语法非常简单。有三种不同的格式:
"~{templatename::selector}"包括由于在名为的模板上应用指定的标记选择器而产生的片段templatename。请注意,这selector只能是片段名称,因此您可以~{templatename::fragmentname}像~{footer :: copy}上面一样指定简单的名称。标记选择器语法由底层的AttoParser解析库定义,并且类似于XPath表达式或CSS选择器。有关更多信息,请参见附录C。
"~{templatename}"包括名为的完整模板templatename。请注意,您在
th:insert/th:replace标签中使用的模板名称必须由模板引擎当前正在使用的模板解析器解析。~{::selector}"或"~{this::selector}"从同一模板插入片段,匹配selector。如果在出现表达式的模板上未找到,则将模板调用(插入)堆栈遍历到原始处理的模板(root),直到selector在某个级别匹配。
引用不带 th:fragment的代码片段
...
<div id="copy-section">
© 2011 The Good Thymes Virtual Grocery
</div>
...
我们可以使用上面的片段,简单地通过其id属性引用它,类似于CSS选择器:
<body>
...
<div th:insert="~{footer :: #copy-section}"></div>
</body>
th:insert和th:replace(和th:include)之间的差异
和之间有什么区别th:insert和th:replace(和th:include,因为3.0不推荐)?
th:insert最简单:它将简单地将指定的片段作为其host标签的主体插入。th:replace实际上将其主机标签替换为指定的片段。th:include与相似th:insert,但不插入片段,而是仅插入该片段的内容。
因此,HTML片段如下所示:
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
…在主机<div>代码中包含了3次,如下所示:
<body>
...
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>
…将导致:
<body>
...
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
28、灵活布局
请注意以下片段中title和links变量的使用:
<head th:fragment="common_header(title,links)">
<title th:replace="${title}">The awesome application</title>
<!-- Common styles and scripts -->
<link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
<link rel="shortcut icon" th:href="@{/images/favicon.ico}">
<script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>
<!--/* Per-page placeholder for additional links */-->
<th:block th:replace="${links}" />
</head>
现在,我们可以将该片段称为:
...
<head th:replace="base :: common_header(~{::title},~{::link})">
<title>Awesome - Main</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
...
…结果将使用调用模板中的实际<title>和<link>标记作为title和links变量的值
一个特殊的片段表达式,空片段(~{}),可用于指定无标记。使用前面的示例:
使用无操作令牌
...
<head th:replace="base :: common_header(_,~{::link})">
<title>Awesome - Main</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
...
片段的高级插入
空片段和无操作令牌的可用性使我们能够以非常容易和优雅的方式有条件地执行片段的插入。
例如,我们可以这样做,以便仅在用户是管理员的情况下才插入common :: adminhead片段,否则就什么都不插入(空片段):
...
<div th:insert="${user.isAdmin()} ? ~{common :: adminhead} : ~{}">...</div>
...
同样,我们可以使用no-operation令牌来仅在满足指定条件时插入片段,而在不满足条件的情况下不做任何修改就保留标记:
...
<div th:insert="${user.isAdmin()} ? ~{common :: adminhead} : _">
Welcome [[${user.name}]], click <a th:href="@{/support}">here</a> for help-desk support.
</div>
...
此外,如果我们已配置模板解析器以通过其标志-检查模板资源checkExistence的存在,则可以将片段本身的存在作为默认操作中的条件:
...
<!-- The body of the <div> will be used if the "common :: salutation" fragment -->
<!-- does not exist (or is empty). -->
<div th:insert="~{common :: salutation} ?: _">
Welcome [[${user.name}]], click <a th:href="@{/support}">here</a> for help-desk support.
</div>
...
29、删除片段模板
最后两行是模拟行!好吧,它们当然是:迭代仅应用于第一行,因此没有理由Thymeleaf应该删除其他两行。
我们需要一种在模板处理期间删除这两行的方法。让我们th:remove在第二个和第三个<tr>标签上使用该属性:
<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:unless="${#lists.isEmpty(prod.comments)}">view</a>
</td>
</tr>
<tr class="odd" th:remove="all">
<td>Blue Lettuce</td>
<td>9.55</td>
<td>no</td>
<td>
<span>0</span> comment/s
</td>
</tr>
<tr th:remove="all">
<td>Mild Cinnamon</td>
<td>1.99</td>
<td>yes</td>
<td>
<span>3</span> comment/s
<a href="comments.html">view</a>
</td>
</tr>
</table>
all该属性中的值是什么意思?th:remove可以根据其值以五种不同的方式表现:
all:删除包含标签及其所有子标签。body:请勿删除包含标签,而是删除其所有子标签。tag:删除包含的标签,但不要删除其子标签。all-but-first:删除包含标记的所有子标记,第一个标记除外。none: 没做什么。该值对于动态评估很有用。
该th:remove属性可采取任何Thymeleaf标准表示,只要它返回所允许的字符串值中的一个(all,tag,body,all-but-first或none)。
这意味着删除可能是有条件的,例如:
<a href="/something" th:remove="${condition}? tag : none">Link text not to be removed</a>
还要注意,它th:remove考虑null了的同义词none,因此以下内容与上面的示例相同:
<a href="/something" th:remove="${condition}? tag">Link text not to be removed</a>
在这种情况下,如果${condition}为false,null将被返回,因此不会执行删除。
30、布局继承
<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:replace="${title}">Layout Title</title>
</head>
<body>
<h1>Layout H1</h1>
<div th:replace="${content}">
<p>Layout content</p>
</div>
<footer>
Layout footer
</footer>
</body>
</html>
此示例声明了一个名为layout的片段,其中标题和内容作为参数。在下面的示例中,这两者都将在页面上被继承的片段表达式替换,并继承它。
<!DOCTYPE html>
<html th:replace="~{layoutFile :: layout(~{::title}, ~{::section})}">
<head>
<title>Page Title</title>
</head>
<body>
<section>
<p>Page content</p>
<div>Included on page</div>
</section>
</body>
</html>
在此文件中,html标记将由layout替换,但在布局中title,content将分别由title和section块替换。
如果需要,布局可以由几个片段组成,例如header和footer。
31、9个局部变量
Thymeleaf提供了一种使用th:with属性声明局部变量而无需迭代的方法,其语法类似于属性值分配的语法:
<div th:with="firstPer=${persons[0]}">
<p>
The name of the first person is <span th:text="${firstPer.name}">Julius Caesar</span>.
</p>
</div>
当th:with被处理时,该firstPer变量被创建为一个局部变量,并加入到变量映射从上下文来,使得它可用于评估与在上下文中声明的任何其它变量一起,但仅在含有的边界<div>标记。
您可以使用通常的多重赋值语法同时定义多个变量:
<div th:with="firstPer=${persons[0]},secondPer=${persons[1]}">
<p>
The name of the first person is <span th:text="${firstPer.name}">Julius Caesar</span>.
</p>
<p>
But the name of the second person is
<span th:text="${secondPer.name}">Marcus Antonius</span>.
</p>
</div>
该th:with属性允许重用在同一属性中定义的变量:
<div th:with="company=${user.company + ' Co.'},account=${accounts[company]}">...</div>
<p th:with="df=#{date.format}">
Today is: <span th:text="${#calendars.format(today,df)}">13 February 2011</span>
</p>
32、属性优先级
| 订购 | 特征 | 属性 |
|---|---|---|
| 1个 | 碎片包含 | th:insert th:replace |
| 2 | 片段迭代 | th:each |
| 3 | 条件评估 | th:if th:unless th:switch th:case |
| 4 | 局部变量定义 | th:object th:with |
| 5 | 常规属性修改 | th:attr th:attrprepend th:attrappend |
| 6 | 特定属性修改 | th:value th:href th:src ... |
| 7 | 文字(标签正文修改) | th:text th:utext |
| 8 | 片段规格 | th:fragment |
| 9 | 碎片清除 | th:remove |
这种优先机制意味着,如果属性位置反转,则上述迭代片段将给出完全相同的结果(尽管可读性稍差):
<ul>
<li th:text="${item.description}" th:each="item : ${items}">Item description here...</li>
</ul>
33、注释
<!-- ... -->Thymeleaf模板中的任何位置都可以使用标准的HTML / XML注释。这些注释中的所有内容都不会被Thymeleaf处理,并将逐字复制到结果中:
34、合成th:block标签
th:block仅是一个属性容器,允许模板开发人员指定他们想要的任何属性。Thymeleaf将执行这些属性,然后简单地使该块(而不是其内容)消失。
因此,例如在创建<tr>每个表都需要多个表的迭代表时,它可能会很有用:
<table>
<th:block th:each="user : ${users}">
<tr>
<td th:text="${user.login}">...</td>
<td th:text="${user.name}">...</td>
</tr>
<tr>
<td colspan="2" th:text="${user.address}">...</td>
</tr>
</th:block>
</table>
35、内联
<p>Hello, [[${session.user.name}]]!</p>
…代替此:
<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>
在Thymeleaf中,[[...]]或之间的表达式[(...)]被认为是内联表达式,在其中,我们可以使用在th:textorth:utext属性中也有效的任何类型的表达式。
请注意,尽管[[...]]对应于th:text(即结果将被HTML转义),但[(...)]对应于th:utext且将不执行任何HTML转义。因此msg = 'This is <b>great!</b>',给定该片段,使用诸如的变量:
<p>The message is "[(${msg})]"</p>
禁用内联
不过,可以禁用此机制,因为实际上在某些情况下,我们确实希望输出[[...]]or[(...)]序列而不将其内容作为表达式处理。为此,我们将使用th:inline="none":
<p th:inline="none">A double array looks like this: [[1, 2, 3], [4, 5]]!</p>
这将导致:
<p>A double array looks like this: [[1, 2, 3], [4, 5]]!</p>
Javascript内联
必须使用th:inline="javascript"以下命令明确启用此模式:
<script th:inline="javascript">
...
var username = [[${session.user.name}]];
...
</script>
这将导致:
<script th:inline="javascript">
...
var username = "Sebastian \"Fruity\" Applejuice";
...
</script>
首先,JavaScript内联不仅会输出所需的文本,而且还会用引号将其括起来,并对其内容进行JavaScript转义,以便将表达式结果输出为格式良好的JavaScript文字。
其次,之所以会这样,是因为我们将转义的${session.user.name}表达式输出,即使用双括号表达式:。如果相反,我们使用未转义的形式:[[${session.user.name}]]
css内联
<style th:inline="css">
...
</style>