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-spring6和thymeleaf-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 simplytemplate :: fragment.
Also, artifacts previously deprecated in 3.0 have been removed:
- Removed
th:substituteby, deprecated previously in favour ofth:replace. - Removed deprecated use of
execInfoas a context variable (${execInfo}), available since 3.0 as an expression utility object (${#execInfo})。
Other minor improvements
- General update of dependency versions.
- Allow
#temporalsexpression utility object to format temporals in non-default locales. - Support iterating (e.g.
th:each) directly on java streams (java.util.stream.Stream)。 - Allow
SpringTemplateEngineinstances 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 基础的示例应用。
- 新的 Thymeleaf BOM (
- 创建一个大型 Maven 多模块配置,用于构建完整的 Thymeleaf 模块树。
- 配置示例应用程序,以便可以从 Maven 命令行执行非基于 Spring Boot 的 Web 应用程序。
- 创建更完整的分发包
.zip形式,现在不仅包括库文件,还包括二进制和(可构建的)源代码形式的示例应用程序。 - 将所有测试基础设施迁移到 JUnit 5。
迁移到 Thymeleaf 3.1
JDK 版本
Thymeleaf 3.1 将其最低兼容级别提升到了 JDK 8,但是thymeleaf-spring6和thymeleaf-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-spring5或thymeleaf-extras-springsecurity5依赖项替换为新的thymeleaf-spring6或thymeleaf-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:insert和th: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:insert和th:replace属性中填充值。
值中。th:insert或th: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>