Thymeleaf 快速入门

Thymeleaf 快速入门

标准方言

标准方言是指 Thymeleaf 定义了一组功能,这些功能应该足以满足大多数情况。可以识别这些标准方言在模板中的使用,因为它将包含以th前缀开头的属性,如<span th:text="...">

表达式

${...} : 变量表达式。

*{...} : 选择表达式。

#{...} : 消息 (i18n) 表达式。

@{...} : 链接 (URL) 表达式。

~{...} : 片段表达式。

变量表达式

变量表达式是 OGNL 表达式 - 如果将 Thymeleaf 与 Spring - 集成在上下文变量上(也称为 Spring 术语中的模型属性),则为 Spring EL。 它们看起来像这样:

1
${session.user.name}

它们作为属性值或作为它们的一部分,取决于属性:

1
<span th:text="${book.author.name}"></span>

上面的表达式与下面是相同的(在 OGNL 和 SpringEL 中):

1
((Book)context.getVariable("book")).getAuthor().getName()

但是不仅在涉及输出的场景中找到变量表达式,而且还可以使用更复杂的处理方式,如:条件,迭代…等等。

1
<li th:each="book : ${books}"></li>

这里${books}从上下文中选择名为books的变量,并在th:each中使用循环将其评估为迭代器。

选择表达式

选择表达式就像变量表达式一样,它们不是整个上下文变量映射上执行,而是在先前选择的对象。 它们看起来像这样:

1
*{customer.name}

它们所作用的对象由th:object属性指定:

1
2
3
4
5
<div th:object="${book}">
...
<span th:text="*{title}">...</span>
...
</div>

所以这相当于:

1
2
3
4
5
6
{
// th:object="${book}"
final Book selection = (Book) context.getVariable("book");
// th:text="*{title}"
output(selection.getTitle());
}

消息(i18n)表达式

消息表达式(通常称为文本外部化,国际化或 i18n)允许从外部源(如:.properties)文件中检索特定于语言环境的消息,通过键来引用这引用消息。

在 Spring 应用程序中,它将自动与 Spring 的 MessageSource 机制集成。如下 -

1
2
#{main.title}
#{message.entrycreated(${entryId})}

以下是在模板中使用它们的方式:

1
2
3
4
5
6
<table>
...
<th th:text="#{header.address.city}">...</th>
<th th:text="#{header.address.country}">...</th>
...
</table>

请注意,如果希望消息键由上下文变量的值确定,或者希望将变量指定为参数,则可以在消息表达式中使用变量表达式:

1
#{${config.adminWelcomeKey}(${session.user.name})} Jsp

链接(URL)表达式

链接表达式在构建 URL 并向其添加有用的上下文和会话信息(通常称为 URL 重写的过程)。
因此,对于部署在 Web 服务器的/myapp上下文中的 Web 应用程序,可以使用以下表达式:

1
<a th:href="@{/order/list}">...</a>

可以转换成如下的东西:

1
<a href="/myapp/order/list">...</a>

甚至,如果需要保持会话,并且 cookie 未启用(或者服务器还不知道),那么生成的格式为:

1
<a href="/myapp/order/list;jsessionid=s2ds3fa31abd241e2a01932">...</a> HTML

网址也可以带参数,如下所示:

1
<a th:href="@{/order/details(id=${orderId},type=${orderType})}">...</a>

这将产生类似以下的结果 -

1
2
<!-- 注意&符号会在标签属性中进行HTML转义... -->
<a href="/myapp/order/details?id=23&type=online">...</a>

链接表达式可以是相对的,在这种情况下,应用程序上下文将不会被加到 URL 的前面:

1
<a th:href="@{../documents/report}">...</a>

也是服务器相对的(同样,没有应用程序上下文的前缀):

1
<a th:href="@{~/contents/main}">...</a>

和协议相关(就像绝对 URL 一样,但浏览器将使用与正在显示的页面相同的 HTTP 或 HTTPS 协议):

1
<a th:href="@{//static.mycompany.com/res/initial}">...</a>

当然,链接表达式也可以是绝对的:

1
<a th:href="@{http://www.mycompany.com/main}">...</a>

但是绝对(或协议相对)URL ,在 Thymeleaf 链接表达式中应该添加什么值? 很简单:由响应过滤器定义 URL 重写:在基于 Servlet 的 Web 应用程序中,对于每个输出的 URL(上下文相对,相对,绝对…),在显示 URL 之前,Thymeleaf 总是调用HttpServletResponse.encodeUrl(...)机制。 这意味着一个过滤器可以通过包装 HttpServletResponse 对象来为应用程序执行自定义的 URL 重写。

片段表达式

片段表达式是一种简单的方法用来表示标记的片段并将其移动到模板中。 由于这些表达式,片段可以被复制,传递给其他模板的参数等等。

最常见的是使用th:insertth:replace来插入片段:

1
<div th:insert="~{commons :: main}">...</div>

但是它们可以在任何地方使用,就像任何其他变量一样:

1
2
3
<div th:with="frag=~{footer :: #main/text()}">
<p th:insert="${frag}"></p>
</div>

片段表达式可以有参数。

表达式预处理

关于表达式的最后一件事是知道表达式预处理,在__之间指定,如下所示:

1
#{selection.__${sel.code}__}

上面代码中,第一个被执行的变量表达式是:${sel.code},并且将使用它的结果作为表达式的一部分(假设${sel.code}的结果为:ALL),在此处执行国际化的情况下(这将查找与关键selection.ALL消息)。

文字和操作

有很多类型的文字和操作可用,它们分别如下:

  • 文字
    • 文本文字,例如:'one text', 'Another one!',
    • 数字文字,例如:0,10, 314, 31.01, 112.83,
    • 布尔文字,例如:true,false
    • Null 文字,例如: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)

基本属性

下面来看看标准方言中的几个最基本的属性。 从th:文本开始,它代替了标签的主体:

1
<p th:text="#{msg.welcome}">Welcome everyone!</p>

现在,th:each重复它所在元素的次数,由它的表达式返回的数组或列表所指定的次数,为迭代元素创建一个内部变量,其语法与 Java 的 foreach 表达式相同:

1
2
3
<li th:each="book : ${books}" th:text="${book.title}">
En las Orillas del Sar
</li>

最后,Thymeleaf 为特定的 XHTML 和 HTML5 属性提供了许多th属性,这些属性只评估它们的表达式,并将这些属性的值设置为结果。

1
2
3
4
<form th:action="@{/createOrder}">
<input type="button" th:value="#{form.submit}" />
<a th:href="@{/admin/users}"></a>
</form>

标准 URL

Thymeleaf 标准方言(称为 Standard 和 SpringStandard)提供了一种在 Web 应用程序中轻松创建 URL 的方法,以便它们包含任何所需的 URL 工件。 这是通过连接表达方式来完成的,这是一种类似于 Thymeleaf 标准的表现:@{...}

绝对网址

绝对 URL 用于创建到其他服务器的链接。它们需要指定一个协议名称(http://https://)开头。

1
<a th:href="@{https://www.yiibai.com/thymeleaf/}"></a>

上面链接不会被修改,除非在服务器上配置了 URL 重写过滤器,并在HttpServletResponse.encodeUrl(...)方法中执行修改。最后生成的 HTML 代码如下:

1
<a href="https://www.yiibai.com/thymeleaf/"></a>

上下文相关 URL

最常用的 URL 类型是上下文相关的。 这些 URL 是一旦安装在服务器上,就会与 Web 应用程序根相关联 URL。 例如,如果将一个名称为myapp.war的文件部署到一个 Tomcat 服务器中,那么应用程序一般是通过 URL:http://localhost:8080/myapp来访问,myapp就是上下文名称。

与上下文相关的 URL 以/字符开头:

1
<a th:href="@{/order/list}"></a>

如果应用程序访问 URL 为:http://localhost:8080/myapp,则此 URL 将输出:

1
<a href="/myapp/order/list"></a>

与服务器相关 URL

服务器相关的 URL 与上下文相关的 URL 非常相似,只是它们不假定 URL 要链接到应用程序上下文中的资源,因此允许链接到同一服务器中的不同上下文:

1
<a th:href="@{~/billing-app/showDetails.html}"></a>

当前应用程序的上下文将被忽略,因此尽管应用程序部署在http:// localhost:8080 / myapp,但该 URL 将输出:

1
<a href="/billing-app/showDetails.html"></a>

协议相关 URL

与协议相关的 URL 实际上是绝对的 URL,它将保持用于显示当前页面的协议(HTTP,HTTPS)。 它们通常用于包括样式,脚本等外部资源:

1
2
3
<script th:src="@{//scriptserver.example.net/myscript.js}">
...
</script>

它将呈现与上面一致的 URL(URL 重写除外),如:

1
2
3
<script src="//scriptserver.example.net/myscript.js">
...
</script>

添加参数

如何向使用@{...}表达式创建的 URL 添加参数? 这也很简单:

1
<a th:href="@{/order/details(id=3)}"></a>

上面示例代码,最终将输出为:

1
<a href="/order/details?id=3"></a>

也可以添加几个参数,用逗号分隔它们:

1
<a th:href="@{/order/details(id=3,action='show_all')}"></a>

上面代码将输出结果为:

1
2
<!-- 注意&符号在标签属性中进行HTML转义... -->
<a href="/order/details?id=3&action=show_all"></a>

还可以使用正常参数的路径变量的形式包含参数,但在 URL 的路径中指定一个占位符:

1
<a th:href="@{/order/{id}/details(id=3,action='show_all')}"></a>

上面输出结果为:

1
<a href="/order/3/details?action=show_all"></a>

网址片段标识符

片段标识符可以包含在 URL 中,包含参数和不包含参数。 它们将始终包含在网址的基础上,参考以下代码:

1
<a th:href="@{/home#all_info(action='show')}"></a>

执行输出结果如下 -

1
<a href="/home?action=show#all_info">

URL 重写

Thymeleaf 允许在应用程序中配置 URL 重写过滤器,它通过调用 Thymeleaf 模板生成的每个 URL 的 Servlet API 的javax.servlet.http.HttpServletResponse类中的response.encodeURL()方法来实现。

下面在 Java Web 应用程序中支持 URL 重写操作的标准方式,并允许 URL:

  • 自动检测用户是否启用了 Cookie,如果未启用或者如果它是第一个请求并且 cookie 配置仍未知。则将;jsessionid=...片段添加到 URL。
  • 在需要时自动将代理配置应用于 URL。
  • 使用不同的 CDN 设置,以便链接到分布在多个服务器中的内容。

URL 其它属性

不要以为在@{...}表达式中只有th:href属性来表示 URL 。 事实上,它们可以像变量表达式(${...})或消息外部化/国际化(#{...})一样用于任何地方。

例如,表单提交时,可使用以下写法 -

1
<form th:action="@{/order/processOrder}"></form>

或作为其他表达的一部分。 如下作为外部化/国际化字符串的参数:

1
2
3
<p
th:text="#{orders.explanation('3', @{/order/details(id=3,action='show_all')})}"
></p>

在 URL 中使用表达式

下面来看看,如下所示的 URL 表达式:

1
<a th:href="@{/order/details(id=3,action='show_all')}"></a>

3'show_all'都不能是文字值,因为只有在运行时才能知道它们的值,怎么办?

1
2
3
<a
th:href="@{/order/details(id=${order.id},action=(${user.admin} ? 'show_all' : 'show_public'))}"
></a>

下面看看另一个 URL 表达式,如下所示:

1
<a th:href="@{/order/details(id=${order.id})}"></a>

它其实是下面 URL 的一个快捷方式:

1
<a th:href="@{'/order/details'(id=${order.id})}"></a>

这意味着 URL 基本身可以被指定为一个表达式,例如一个变量表达式:

1
<a th:href="@{${detailsURL}(id=${order.id})}"></a>

或外部化/国际化的文本:

1
<a th:href="@{#{orders.details.localized_url}(id=${order.id})}"></a>

甚至可以使用复杂的表达式,包括条件表达式,例如:

1
2
3
<a
th:href="@{(${user.admin}? '/admin/home' : ${user.homeUrl})(id=${order.id})}"
></a>

如果要更清洁,那么可以使用th:with :

1
2
3
4
<a
th:with="baseUrl=(${user.admin}? '/admin/home' : ${user.homeUrl})"
th:href="@{${baseUrl}(id=${order.id})}"
></a>

又或者 -

1
2
3
4
5
<div th:with="baseUrl=(${user.admin}? '/admin/home' : ${user.homeUrl})">
...
<a th:href="@{${baseUrl}(id=${order.id})}">...</a>
...
</div>

扩展

TODO

参考资料