目前项目用到Thymeleaf2.1的版本,所以笔记写的都是这个版本的内容,而现在最新版是Thymeleaf3.0,之后有空再看下有何变化。
Thymeleaf是一个可以处理XML / XHTML / HTML5的Java模板引擎,能用于转换模板文件,以显示应用程序产生的数据和文本。
- XML
- Valid XML
- XHTML
- Valid XHTML
- HTML5
- Legacy HTML5
Thymeleaf是一个极具可扩展性的模板引擎(事实上更应称作模板引擎的框架),允许你自定义模板中处理的DOM节点,及如何处理他们。
Thymeleaf的核心是一个DOM处理引擎,它使用自己高性能的DOM实现,而非的标准DOM API。
-
简单表示式:
- 变量表达式:${…}
- 选择变量表达式:*{…}
- 消息表达式:#{…}
- 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)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
用法: #{...}
示例: <p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
可配合变量表达式使用:
<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>
变量表达式可以使用OGNL的语法。
示例:
/*
* 使用点号(.)访问属性
*/
${person.father.name}
/*
* 也可以使用中括号([])访问属性
*/
${person['father']['name']}
/*
* 如果是map类型对象,点号和中括号语法相当于调用get方法
*/
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}
/*
* 通过索引来访问数组或集合
*/
${personsArray[0].name}
/*
* 调用有参数方法
*/
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}
-
OGNL基本内置对象
- #ctx:上下文对象
- #vars:上下文变量
- #locale :上下文语言环境
- #httpServletRequest :(只在web context中) HttpServletRequest对象
- #httpSession :(只在web context中) HttpSession对象
-
表达式工具对象
- #dates:为java.util.Date对象提供工具方法,比如:格式化,提取年月日等。
- #calendars:类似于#dates,但是只针对java.util.Calendar对象。
- #numbers:为数值型对象提供的工具方法。
- #strings:为String对象提供的工具方法。包括:contains, startsWith, prepending/appending等。
- #objects:为object对象提供的工具方法。
- #bools:为boolean对象提供的工具方法。
- #arrays:为array对象提供的工具方法。
- #lists:为list对象提供的工具方法。
- #sets:为set对象提供的工具方法。
- #maps:为map对象提供的工具方法。
- #aggregates:为创建array或者collection聚集函数提供的工具方法。
- #messages:在表达式中获取外部信息的工具方法,与使用
#{…}
相同。 - #ids:为处理可能重复的id属性提供的工具方法,例如,作为迭代的结果。
变量表达式不仅能用在${...}上,还能用在*{...}上。两者的区别在于*{...}基于选定对象而不是上下文的对象进行运算,若无选定的对象,两者使用上是相同的。
用法:
- 使用
th:object
选择对象,再通过*{...}
使用对象属性。 $
与*
语法可以混合使用。- 选定的对象也可以通过#object进行访问。
- 若无选择的对象,
$
与*
语法效果是相同的。
示例:
<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>
选定的对象也可以通过#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>
th:href
属性修饰符:计算并替换<a>
标签的href属性值。- 参数可使用表达式。
- 多个参数使用逗号隔开。
- 变量模板可用在URL路径中,如
@{/order/{orderId}/details(orderId=${orderId})}
。 - URL中以
/
开头的路径(如/order/details
)将会自动在前缀加上应用上下文地址。 - 如果cookies被禁用需要重写URL,可通过
response.encodeURL(...)
插入重写过滤器。 th:href
标签可以使用静态的href属性。- 可使用
@{~/path/to/something}
创建服务器相对根路径来链接同一台服务器不同上下文。
- 文本:包含在单引号内的字符串,单引号字符需要用斜杠
\
转义。 - 数值:0 , 34 , 3.0 , 12.3 ,…
- 布尔值:true , false
- 空值:null
- 文字标记(Literal tokens):数值、布尔值、空值实际上是特殊的文字标记。这些文件标记使表达式更加简洁,其工作方式和文本完全一样,但是只能使用字符(a-z,A-Z),数值(0-9),中括号,点号,连字符和下划线。不能有空格和逗号等。
文字替换需要使用 |
来包围替换的内容。注意:仅变量表达式(${...})允许在文字替换( |...|
)中使用,而像文本、布尔值、数值都不允许。
示例:
<span th:text="|Welcome to our application, ${user.name}!|">
等价于:
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">
与其他表达式结合使用:
<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">
在表达式中可以使用一些算术运算符,如: +, -, *, /, %
。这些运算符实际会被OGNL解析执行。注意这些运算符存在文本别名: div (/), mod (%)
。
表达式中的值可以通过 >, <, >=, <=
来进行比较,也可以通过 ==
和 !=
判断是否相等。注意XML元素不允许属性值使用 <
和 >
符号,应该使用 <
和 >
取代。
注意对应的文本别名: gt (>), lt (<), ge (>=), le (<=), not (!), eq (==), neq/ne (!=)
条件表达式所有部分(condition, then, else)都可以使用变量表达式(${...}, *{...}),消息表达式(#{...}),URL链接(@{...})和文本 ('...')。条件表达式中else部分也可以省略,自动返回null值。
缺省表达式是没有then部分时提供一个缺省值,如果条件判断值不为空就用这个条件的值,否则就用缺省值。
示例:
<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>
预处理是在表达式被执行之前进行处理的操作,处理后的表达式被实际执行。预处理表达式和一般的表达式很像,但被双下划线包含( __${expression}__
)。
示例:
国际化资源信息的文件Message_fr.properties包含一个特定语言的OGNL表达式
[email protected]@translateToFrench({0})
Messages_es.properties中包含的信息如下:
[email protected]@translateToSpanish({0})
使用:
<p th:text="${__#{article.text('textVar')}__}">Some text here...</p>
法语地区会被预处理成:
<p th:text="${@myapp.translator.Translator@translateToFrench(textVar)}">Some text here...</p>
Thymeleaf中可以使用安全导航操作符 ?.
,这是来自Spring EL的用法,参考了Groovy。安全导航操作符将简单地返回空代替抛出的异常,用来避免产生空指针异常。
示例:
<span th:text="${error?.summary}">Static summary</span>
- 为任意属性设置值:
th:attr
,多个属性值可用逗号隔开,示例:<input type="submit" value="Subscribe me!" th:attr="value=#{subscribe.submit}"/>
。 - 为指定属性设置值:
th:value
,包括th:action th:class th:style
等,示例<form action="subscribe.html" th:action="@{/subscribe}">
。 - 一次设置多个值:
th:alt-title
和th:lang-xmllang
,前者设置alt和title属性,后者设置lang和xmllang属性。示例:<img src="../../images/gtvglogo.png" th:src="@{/images/gtvglogo.png}" th:alt-title="#{logo}" />
。 - 追加和预加:
th:attrappend
和th:attrprepend
,此外还可以使用th:classappend
和th:styleappend
对class和style进行追加。示例:<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />
- 固定值布尔属性:
th:checked th:disabled th:multiple th:readonly th:selected
等,标准表达式可以通过计算条件来设置这些固定值属性。示例:<input type="checkbox" name="active" th:checked="${user.active}" />
。 - HTML5友好的属性和元素名称:
data-{prefix}-{name}
,“data-前缀-名称”是HTML5中的自定义属性,这种语法是th:*
的附加方式。
标准表达式提供一个使用迭代的属性 th:each
, 可迭代的对象包括:
- java.util.List
- java.util.Iterable
- java.util.Map
- 数组
- 任何包含自身的单值列表
Thymeleaf提供了一种跟踪迭代器状态的机制:状态变量,包含了以下数据:
- 当前的迭代索引,从0开始,属性为index;
- 当前的迭代索引,从1开始,属性为count;
- 迭代集合长度,属性为size;
- 当前的迭代变量,属性为current;
- 当前的迭代是奇数还是偶数,even/odd布尔属性
- 当前的迭代是否是第一个元素,属性为first的布尔值
- 当前的迭代是否为最后一个元素,属性为last的布尔值
状态变量(iterStat)定义在th:each属性中,用逗号与迭代变量分隔开。若无定义,默认可通过迭代变量名加后缀 Stat
来使用。示例:
<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>
条件判断的内容只在条件判断成立时才显示。th:if
“反向”属性是 th:unless
。注意 th:if
可以根据以下规则判断为“true”:
- 布尔值为true
- 非零数值
- 非零字符
- 字符串(非“false”, “off” 或 “no)
- 非布尔值、数值、字符、字符串
Thymeleaf中提供了类似Java中的switch结构语法: th:switch / th:case
。注意,只要有一个case条件为真,其它剩余的都不会继续判断。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>
<p th:case="*">User is some other thing</p>
</div>
Thymeleaf表达式将在片段被 th:include
和 th:replace
引入到模版中时解析,它们可以引用上下文环境中的变量。有三种引用方式:
- "templatename::domselector" 或 "templatename::[domselector]":包含templatename指定部分
- "templatename":包含完整模板
- "::domselector" 或 "this::domselector":当前模版中的片段
示例:
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
</body>
</html>
引用:
<body>
...
<div th:include="footer :: copy"></div>
</body>
也可以通过id进行引用:
<div id="copy-section">
© 2011 The Good Thymes Virtual Grocery
</div>
通过 footer :: #copy-section
来引用。
th:include
会将片段的内容包含进宿主标签。th:replace
会用片段的标签取代宿主标签。th:replace
可以用别名th:substituteby
。
th:fragment
属性可以接收一系列参数:
<div th:fragment="frag (onevar,twovar)">
<p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
引入:
<div th:include="::frag (${value1},${value2})">...</div>
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div>
使用无参数的片段本地变量:
<div th:include="::frag (onevar=${value1},twovar=${value2})">
相当于:
<div th:include="::frag" th:with="onevar=${value1},twovar=${value2}">
用 th:assert
在模版内进行断言:
<div th:assert="${onevar},(${twovar} != 43)">...</div>
可以用于验证片段签名:
<header th:fragment="contentheader(title)" th:assert="${!#strings.isEmpty(title)}">...</header>
可以使用 th:remove
来移除模板片段,th:remove
可以处理Thymeleaf标准表达式的标签,有五种不同的方式:
- all:删除标签和标签内的所有子元素
- body:不删除标签,但删除标签的子元素
- tag:只删除标签,但不删除子元素
- all-but-first:删除除了第一个之外的所有子元素
- none(空值):什么都不删除,一般用于动态解析
Thymeleaf称那些定义在模板的特定片段,且只能用于该片段中的变量为本地变量。可以使用 th:with
定义或者在迭代中定义。允许重用在当前 th:with
中已经定义的变量。
有效范围:
- 在标签范围内,对任何其他th:*标签有效。
- 标签的所有子元素内都有效。
所有的Thymeleaf属性都定义了优先级,顺序如下:
Order | Feature | Attributes |
---|---|---|
1 | Fragment inclusion | th:include th:replace |
2 | Fragment iteration | th:each |
3 | Conditional evaluation | th:if th:unless th:switch th:case |
4 | Local variable definition | th:object th:with |
5 | General attribute modification | th:attr th:attrprepend th:attrappend |
6 | Specific attribute modification | th:value th:href th:src ... |
7 | Text (tag body modification) | th:text th:utext |
8 | Fragment specification | th:fragment |
9 | Fragment removal | th:remove |
- 标准的HTML/XML注释:
<!-- ... -->
能在 Thymeleaf 模板中任意地方使用,不会被处理。 - Thymeleaf解析器层注释块:
<!--/* ... */-->
部分当解析模板时会被解析器移除。 - Thymeleaf原型仅存注释块:
<!--/*/
和/*/-->
在静态打开时会被注释,而正常解析时会作为正常标签。 - 合成的th:block块:Thymeleaf中唯一元素级别的处理器是
th:block
,它是一个纯粹的属性容器,允许开发人员指定他们想要的属性。Thymeleaf将只执行块中的属性,而不会保留块本身的内容。
Thymeleaf内联表达式 [[...]]
可以使用其他在 th:text
属性中有效的表达式。要想使用这种语法,首先要用 th:inline
属性激活它,分别有三种不同的属性值: text, javascript, none
。需要注意这种用法在静态打开页面会直接显示表达式的内容。示例如下:
<p th:inline="text">Hello, [[${session.user.name}]]!</p>
目前包括两种模式:javascript (th:inline="javascript") and dart (th:inline="dart")。
<script th:inline="javascript">
/*<![CDATA[*/
...
var username = /*[[${session.user.name}]]*/ 'Sebastian';
...
/*]]>*/
</script>
/*[[...]]*/
这种语法有几个好处:
- javascript注释(/.../)会忽略表达式中的内容。
- 内联表达式后的值在静态打开时会被显示出来。
- Thymeleaf解析时会将计算后的值替换掉静态值。
Thymeleaf可以智能地解析以下几种对象:
- Strings
- Numbers
- Booleans
- Arrays
- Collections
- Maps
- Beans(包含getter和setter方法的对象)
示例:
<script th:inline="javascript">
/*<![CDATA[*/
...
var user = /*[[${session.user}]]*/ null;
...
/*]]>*/
</script>
会被转换为:
<script th:inline="javascript">
/*<![CDATA[*/
...
var user = {'age':null,'firstName':'John','lastName':'Apricot',
'name':'John Apricot','nationality':'Antarctica'};
...
/*]]>*/
</script>
/*[+...+]*/
注释语法可以在解析时解除注释:
var x = 23;
/*[+
var msg = 'This is a working application';
+]*/
var f = function() {
...
/*[- */
和 /* -]*/
注释语法可以在解析时动态移除内容:
var x = 23;
/*[- */
var msg = 'This is a non-working template';
/* -]*/
var f = function() {
...
默认情况下Thymeleaf包括一个用于保存解析后的模版的缓存,它保存了读取模版文件后解析出的一些列事件对象。这对于创建Web应用程序方面有以下好处:
- 输入输出几乎是任何应用程序中耗时最长的环节,相比而言在内存中的处理速度是最快的。
- 从内存中克隆一个已经存在的事件序列肯定要比从模版中重新读取、解析后再创建一次要更快。
- Web应用程序通常只有为数不多的模版。
- 模版文件的尺寸通常不大,并且在应用程序运行期间不会被修改。
在模版解析器中打开和关闭缓存:
// 默认 true
templateResolver.setCacheable(false);
templateResolver.getCacheablePatternSpec().addPattern("/users/*");
通过设置缓存管理对象来配置相关参数,缓存管理对象的默认实现是StandardCacheManager:
// 默认 50
StandardCacheManager cacheManager = new StandardCacheManager();
cacheManager.setTemplateCacheMaxSize(100);
...
templateEngine.setCacheManager(cacheManager);
更多配置选项可以参考org.thymeleaf.cache.StandardCacheManager的JavaDoc。
缓存也可以被手工删除:
// 完全删除缓存
templateEngine.clearTemplateCache();
// 从缓存中删除一个指定的模版
templateEngine.clearTemplateCacheFor("/users/userList");
Thymeleaf的DOM选择器借鉴了XPath,CSS和JQuery的语法特性。下面是借鉴XPath的基本语法:
- /x 选择当前节点的名为x的直接子元素。
- //x 选择当前节点下所有子节点(任何层次)的子元素。
- x[@z="v"] 选择节点名称为x 并且包含属性z且z的值为v的元素。
- x[@z1="v1" and @z2="v2"] 表示选择节点名称为x 标签包含z1和z2属性,且它们的值分别为v1和v2的元素。
- x[i] 表示选择名为x的元素中的第i个元素。
- x[@z="v"][i] 表示选择名为x并且其属性z的值为v的第i个元素。
其他语法还包括:
- x 相当于 //x
[@class="oneclass"]
表示选择class属性为oneclass的所有元素。- 比较操作符除了=,还有!=,^=(开始于),$=(结束于)。比如
x[@class^='section']
表示查找x元素,并且其class属性以section开头。 - 符号@ 也可以被省略,比如 x[z='v']等同于x[@z='v']。
- 多个属性选择器的叠加可以通过and,也可以通过链式叠加的方式,比如x[@z1="v1" and @z2="v2"] 等同于x[@z1='v1'][@z2='v2'] 或者x[z1='v1'][z2='v2']。
JQuery风格的选择器:
- x.oneclass 等同 x[class='oneclass']。
- .oneclass 等同 [class='oneclass']。
- x#oneid 等同 x[id='oneid']。
- #oneid 等同 [id='oneid']。
- x%oneref 表示x元素有一个
th:ref="oneref"
属性或者th:fragment="oneref"
属性。 - %oneref 表示任何元素有一个
th:ref="oneref"
属性或者th:fragment="oneref"
属性,与直接使用oneref效果相同。 - 直接的选择器和属性选择器可以混合使用,比如:
a.external[@href^='https']
。
更多接口和其他信息可以参考官方文档附录和Javadocs/API 文档。