第一部分、标准模板语法(Thymeleaf官方文档翻译)

    技术2022-07-16  82

    原文 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>
    Processed: 0.020, SQL: 9