Thymeleaf

Thymeleaf 3.1:有什么新功能以及如何迁移

最新版本是 Thymeleaf3.1.3.RELEASE.

有什么新功能

支持 Servlet API 5.0 以及jakarta.*类命名空间

Thymeleaf 3.1 增加了对自版本 5.0 以来在 Servlet API 中引入的新jakarta.*类命名空间的支持,同时并未移除对之前版本中javax.*类的支持。

对 Spring 6.0 的支持

Thymeleaf 3.1 添加了一个新的thymeleaf-spring6核心库以集成 Spring Framework 6.0。

对早于 Spring 5.0 的 Spring 版本的支持已被移除。

对 Spring Security 6.0 的支持

Thymeleaf 3.1 添加了一个新的thymeleaf-extras-springsecurity6核心库以集成 Spring Security 6.0。

对早于 Spring Security 5.0 的 Spring Security 版本的支持已被移除。

java.timeextras 模块的核心支持已整合进 Thymeleaf 核心:

这个thymeleaf-extras-java8time表达式工具对象现在始终可用。#temporalsJava 兼容性

现在最低通常需要的 JDK 版本为 JDK 8。

现在 JDK 8 是最低通常要求的版本。

核心库所需的最低 JDK 版本为 JDK 17。thymeleaf-spring6thymeleaf-extras-springsecurity6核心库所需的最低版本为 JDK 17。

移除了基于 Web API 的表达式工具对象

这个#request, #response, #session访问,并且#servletContext在 Thymeleaf 3.1 的表达式中不再可用。

对表达式中类使用更严格的限制

Thymeleaf 3.1 建立了一般性的限制,禁止使用核心包中的类:java.*, javax.*, jakarta.*, jdk.*, org.ietf.jgss.*, org.omg.*, org.w3c.dom.*, org.xml.sax.*, com.sun.*sun.*.

这些包中的类的方法/构造函数调用现在被禁止,静态引用也是如此。

作为此限制的例外,这些包中的某些类始终被允许:

  • 基础java.lang.*java.math.*类:java.lang.Boolean, java.lang.Byte, java.lang.Character, java.lang.Double, java.lang.Enum, java.lang.Float, java.lang.Integer, java.lang.Long, java.lang.Math, java.lang.Number, java.lang.Short, java.lang.String, java.math.BigDecimal, java.math.BigInteger, java.math.RoundingMode.

  • 集合类和接口:java.util.Collection, java.util.Enumeration, java.util.Iterable, java.util.Iterator, java.util.List, java.util.ArrayList, java.util.LinkedList, java.util.Set, java.util.HashSet, java.util.LinkedHashSet, java.util.Map, java.util.Map.Entry, java.util.HashMap, java.util.LinkedHashMap注意:接口方法(例如Map#get(key))通常允许任何实现,但此处列出的具体实现还可以被构造并进行静态引用。

  • 在其他常用类中java.util.*: java.util.Properties, java.util.Optional, java.util.stream.Stream, java.util.Locale, java.util.Date, java.util.Calendar.

某些构件已被弃用,并移除了先前已经被弃用的构件

在 Thymeleaf 3.1 中,一些构件已被弃用。

  • 已弃用th:include推荐使用th:insert。请注意th:insert的语义与th:include.
  • 有些不同~{template :: fragment} should always be used instead of simply template :: fragment.

Also, artifacts previously deprecated in 3.0 have been removed:

  • Removed th:substituteby, deprecated previously in favour of th:replace.
  • Removed deprecated use of execInfo as a context variable (${execInfo}), available since 3.0 as an expression utility object (${#execInfo})。

Other minor improvements

  • General update of dependency versions.
  • Allow #temporals expression utility object to format temporals in non-default locales.
  • Support iterating (e.g. th:each) directly on java streams (java.util.stream.Stream)。
  • Allow SpringTemplateEngine instances to be configured a custom (even non-Spring) message resolver.

(对于开发者)项目源代码仓库结构的全面改版

Thymeleaf 3.1 包括对(以前多个)源代码仓库的全面改版,并从开发的角度大大改进了示例应用程序的处理方式:

  • 将大部分之前的 Thymeleaf 代码仓库整合到thymeleafGitHub 仓库中,该仓库现在包含:
    • 新的 Thymeleaf BOM (thymeleaf-parent) 整合并统一了所有 thymeleaf 依赖项和构建配置。
    • 所有 Thymeleaf 核心库,包括与 Spring 和 Spring Security 的集成。
    • 所有 Thymeleaf 测试库及其集成。
    • 所有 Thymeleaf 测试仓库。
    • 所有 Thymeleaf 官方示例应用程序,包括核心、Spring、Spring Security 和 Spring Boot 基础的示例应用。
  • 创建一个大型 Maven 多模块配置,用于构建完整的 Thymeleaf 模块树。
  • 配置示例应用程序,以便可以从 Maven 命令行执行非基于 Spring Boot 的 Web 应用程序。
  • 创建更完整的分发包.zip形式,现在不仅包括库文件,还包括二进制和(可构建的)源代码形式的示例应用程序。
  • 将所有测试基础设施迁移到 JUnit 5。

迁移到 Thymeleaf 3.1

JDK 版本

Thymeleaf 3.1 将其最低兼容级别提升到了 JDK 8,但是thymeleaf-spring6thymeleaf-extras-springsecurity6需要 JDK 17,因为这是 Spring 6.0 所需的 JDK 版本。

Spring 6.0和Spring Security 6.0(以及Spring Boot 3.0)

Thymeleaf与Spring 6.0及Spring Security 6.0的新集成配置方式与之前Spring 5.x中的方式相同(并且仍然适用)。

除了将之前的thymeleaf-spring5thymeleaf-extras-springsecurity5依赖项替换为新的thymeleaf-spring6thymeleaf-extras-springsecurity6属性标记。

之外,不需要进行其他更改。如果是基于Spring Boot的应用程序,则无需任何更改。当添加Thymeleaf Spring Boot启动器时,新的Spring Boot 3.0已经配置并使用Thymeleaf 3.1。

表达式限制

为了提高模板的安全性,Thymeleaf 3.1对变量表达式(${...}*{...})采取了一系列限制措施,这可能会对你现有的代码产生影响。

“新增功能”部分所解释的那样,表达式工具对象#request, #response, #session#servletContext在模板中的表达式中将不再可用。

推荐的替代方法是,在控制器级别上将模板所需的信息以模型属性的形式添加到模型中。可以通过model#addAttribute(...)控制器代码中显式添加,或者通过@ModelAttribute甚至@ControllerAdvice注解方式完成。

@ModelAttribute("contextPath")
public String contextPath(final HttpServletRequest request) {
    return request.getContextPath();
}

另外,还如“新增功能”部分详细说明的那样,对于属于JDK和Jakarta EE核心类的一些类建立了严格的使用限制,部分类除外。从Thymeleaf 3.1开始,变量表达式中将不能使用禁用类的对象。

如果你的某些模板确实需要在禁用类的对象上执行表达式,你可以创建一个包装类(位于你自己的应用程序包中),该类将其方法委托给原始对象,这样就可以在变量表达式中使用它了。

th:include 的弃用

如果你的模板使用了th:include属性,请注意这在Thymeleaf 3.1中仍然允许,但将在库的未来版本中移除。强烈建议你尽快将所有th:include元素th:insert替换为th:insert或th:replace,但要注意它们的工作方式并不完全相同。

因为th:includeth:insert仅插入片段的内容,使得以下代码:生成这样的结果:

<div id="main" th:include="~{::frag}">...</div>
...
<p th:fragment="frag" class="content">
    something
</p>

……结果变成这样:

<div id="main">
      something
</div>

而使用th:insertth:replace则会插入整个片段,包括定义它的标签,所以这样写:

<div id="main" th:insert="~{::frag}">...</div>
...
<p th:fragment="frag" class="content">
    something
</p>

……结果变成这样:

<div id="main">
  <p class="content">
      something
  </p>
</div>

如果你需要特别获得与th:include相同的结果,你需要结合使用th:insertth:remove,类似如下方式:

<div id="main" th:insert="~{::frag}">...</div>
...
<p th:fragment="frag" th:remove="tag" class="content">
    something
</p>

……这样就会得到以下结果:

<div id="main">
      something
</div>

同时请记住,也可以使用<th:block>标签来定义片段,该标签在求值后总是会被隐藏,从而提供更高的灵活性:

<div id="main" th:insert="~{::frag}">...</div>
...
<th:block th:fragment="frag">
    something
</th:block>

结果将是:

<div id="main">
      something
</div>

不包裹的片段表达式的弃用

Thymeleaf中的片段表达式表示为~{...},它们可以用在许多类型的属性和表达式中,尽管通常出现在th:insertth:replace属性中填充值。

值中。th:insertth:replace在Thymeleaf 3.1之前,诸如th:include(或已弃用的~{...} )这样的属性允许指定不带:

<div id="top" th:insert="common :: header">...</div>

包裹语法的片段表达式。但从Thymeleaf 3.1开始,这种语法虽然仍能工作,但被视为已弃用,并计划在未来的版本中删除。现在应像下面这样书写:

<div id="top" th:insert="~{common :: header}">...</div>
无噪 Logo
无噪文档
中文文档 · 复刻官网
查看所有 ↗