原文 4 Standard Expression Syntax
1.标准模板语法
- 下面使用xmlns的目的是防止IDE软件提示缺少th:*的命名空间,可以不用xmlns
<html xmlns:th="http://www.thymeleaf.org">
- 在HTML5文档里,下面的两种语法完全等效,即th:*与data-th-*等效。唯一的不同是data-th-*的语法只能在HTML5文档中使用
<p data-th-text="#{home.welcome}">Welcome to our grocery store!</p>
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
- 特殊的模板:
${x} will return a variable x stored into the Thymeleaf context or as a request attribute.
${param.x} will return a request parameter called x (which might be multivalued).
${session.x} will return a session attribute called x.
${application.x} will return a servlet context attribute called x.
- th:text=“#{home.welcome}”。th:text表示表达式#{home.welcome}的值为文本格式。#{home.welcome}的值会替换<p>标签的内容(Welcome to our grocery store!)。#{home.welcome}的默认值默认保存在properties文件中,例如
home.welcome=欢迎!
- th:utext=“#{home.welcome}”。th:utext (for “unescaped text”),意思就是非转义文本。假如home.welcome=<p>Welcome to our <b>fantastic</b> grocery store!</p>,那么使用这个属性时特殊字符不会被转义。
- 表达式简介:
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: _
1.1 消息表达式#{…}的用法
- 使用参数
//下面的{0}表示一个参数
home.welcome=欢迎, {0}!
//在HTML里可以这样使用,并传入参数替换{0}:
<p th:utext="#{home.welcome(${session.user.name})}">
Welcome to our grocery store, Sebastian Pepper!
</p>
// {0}被${session.user.name}的值替换
1.2 参数表达式${…}的用法
/*
* 使用点(.)访问属性。和调用属性的getter方法等效
*/
${person.father.name}
/*
* 使用中括号([])访问属性, 并且用单引号''写入属性名
*/
${person['father']['name']}
/*
* 如果是个map对象, 点语法和中括号语法可以结合使用,并与调用属性的get方法是等价的
*/
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}
/*
* 使用下标访问arrays或collections对象
*/
${personsArray[0].name}
/*
* 调用对象方法
*/
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}
- 表达式基本对象:当使用的是OGNL表达式时,下面的变量代表了特定的对象:
#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.
我们可以这样使用这些变量:
Established locale country: <span th:text="${#locale.country}">US</span>.
#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).
1.3 选择表达式*{…}的用法
${…}和*{…}都是变量表达式,但是有一点不同是:*{…}表达式是对被选中的对象进行求值。如果没有被选中的对象,那么这两个表达式是等效的。
那什么是被选中的对象呢?看下面的例子。其中${session.user}就是被选中的对象,*{firstName}就是获取user对象的firstName属性
<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>
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>
When an object selection is in place, the selected object will also be available to dollar expressions as the #object expression variable: <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>
1.4 链接表达式@{…}
URL的类型有:
- 绝对URL:http://www.thymeleaf.org
- 相对URL:
- 页面相对: user/login.html
- 上下文相对: user/login.html服务器的上下文会自动添加到URL上
- 服务器相对:~/billing/processInvoice允许请求同一台服务器上不同上下文(也就是应用)
- 协议相对://code.jquery.com/jquery-2.0.3.min.js
th:href属性修饰符的用法:
<!-- 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>
1.5 字面量
- 文本字面量:使用单引号括起来的字符串。如:
<p> Now you are looking at a <span th:text="'working web application'">template file</span>. </p>
- 数值字面量:单纯的数字:
<p>The year is <span th:text="2013">1492</span>.</p> <p>In two years, it will be <span th:text="2013 + 2">1494</span>.</p> ···
- 布尔型字面量:true 和 false
<div th:if="${user.isAdmin()} == false"> Thymeleaf takes care of == false <div th:if="${user.isAdmin() == false}"> OGNL/SpringEL engines takes care of == false
- null
<div th:if="${variable.something} == null"> ...
- 字面量符号:不使用’’表示的字面量,可以是字母(A-Z and a-z)、数字 (0-9)、括号 ([ and ])、点(.)、连字符(.)、下划线 (_).
<div th:class="content">注意th:class后面的值没有用单引号,这也是字面量的一种声明方式</div>
1.6 连接值
使用+连接
<span th:text="'The name of the user is ' + ${user.name}">
1.7 Literal substitutions 字面量替换?
使用竖线(|),将多个值替换为一个,免去了使用+连接值的繁琐。
<span th:text="|Welcome to our application, ${user.name}!|">
等价于下面的这个:
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">
也可以和其他表达式混着用
<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">
只有变量/消息表达式: ${…}, *{…}, #{…} 能在 |…| 符号里使用.
1.8 算数操作符
<div th:with="isEven=(${prodStat.count} % 2 == 0)">
<div th:with="isEven=${prodStat.count % 2 == 0}">
1.9 比较符
由于XML语法中<和>的特殊性,在使用大于和小于时,需要使用其转义符:<
and >
<div th:if="${prodStat.count} > 1">
<span th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')">
更简洁的写法是直接使用比较符的转义符:gt
(>
), lt
(<
), ge
(>=
), le
(<=
), not
(!
). Also eq
(==
), neq
/ne
(!=
).
1.10 条件判断
<tr th:class="${row.even}? 'even' : 'odd'">
...
</tr>
th:class中的条件判断语句由三个部分组成:condition
, then
和else
。这三个部分都是独立的表达式,可以是 variables (${…}
, *{…}
), messages (#{…}
), URLs (@{…}
) or literals (’…’
).
表达式可以内嵌:
<tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'">
...
</tr>
也可以省略else
<tr th:class="${row.even}? 'alt'">
row.even是false的话条件返回null值
</tr>
1.11 设置默认值
<div th:object="${session.user}">
...
<p>Age: <span th:text="*{age}?: '(no age specified)'">27</span>.</p>
</div>
如上所示我们可以使用?:
来设置默认值。上面的例子中如果*{age}是null,那么年龄27就会被默认值替换
表达式同时支持内嵌:
<p>
Name:
<span th:text="*{firstName}?: (*{admin}? 'Admin' : #{default.username})">Sebastian</span>
</p>
1.12 无操作符
使用下划线(_
)表示不做任何操作。举个例子:
<span th:text="${user.name} ?: 'no user authenticated'">...</span>
可以替换为:
<span th:text="${user.name} ?: _">no user authenticated</span>
当user.name为null时,什么都不做,那么span标签里还是no user authenticated。
1.13 数据转换/格式化
为了给数据定义不同的转化规则,Thymeleaf给变量(${…}
) 和选择selection (*{…}
) 表达式定义了双括号语法,就像这样:
<td th:text="${{user.lastAccessDate}}">...</td>
${{…}}语法命令Thymeleaf把user.lastAccessDate的值传到专门的conversion service里,然后这个转换服务把user.lastAccessDate的值格式化为字符串。
Thymeleaf里默认的conversion service 的实现类是IStandardConversionService,默认使用对象的.toString()方法进行格式化。用户也可以自定义转换服务,详情见More on Configuration
♦ Spring实现了自己的conversion service ,所以Spring也支持这个语法
1.14 预处理
预处理可以在正常的表达式之前完成表达式的执行,它允许指定要被执行的表达式。举个例子:
下面是Messages_fr.properties文件里的某个属性,这个article.text属性时一个OGNL表达式,它调用了myapp.translator.Translator类的translateToFrench静态方法,并传入一个参数。
article.text=@myapp.translator.Translator@translateToFrench({0})
同时Messages_ch.properties文件里是这样定义的:
article.text=@myapp.translator.Translator@translateToChinese({0})
可以看到,两个properties文件中需要执行不同的方法,Thymeleaf可以预先执行些方法并拿到方法的返回值,对应的表达式是__${expression}__。在这个例子中可以使用如下的预处理过程:
<p th:text="${__#{article.text('textVar')}__}">Some text here...</p>
最后在本地是中文的情况下,Thymeleaf会首先选择对应的article.text,然后执行方法,拿到返回值,最后替换<p>标签的内容。和下面的预处理表达式是等效的:
<p th:text="${@myapp.translator.Translator@translateToChinese(textVar)}">Some text here...</p>