返回介绍

6.4.2 定义 Thymeleaf 模板

发布于 2024-08-17 00:45:50 字数 4177 浏览 0 评论 0 收藏 0

Thymeleaf在很大程度上就是HTML文件,与JSP不同,它没有什么特殊的标签或标签库。Thymeleaf之所以能够发挥作用,是因为它通过自定义的命名空间,为标准的HTML标签集合添加Thymeleaf属性。如下的程序清单展现了home.html,也就是使用Thymeleaf命名空间的首页模板。

程序清单6.6 home.html:使用Thymeleaf命名空间的首页模板引擎

首页模板相对来讲很简单,只使用了th:href属性。这个属性与对应的原生HTML属性很类似,也就是href属性,并且可以按照相同的方式来使用。th:href属性的特殊之处在于它的值中可以包含Thymeleaf表达式,用来计算动态的值。它会渲染成一个标准的href属性,其中会包含在渲染时动态创建得到的值。这是Thymeleaf命名空间中很多属性的运行方式:它们对应标准的HTML属性,并且具有相同的名称,但是会渲染一些计算后得到的值。在本例中,使用th:href属性的三个地方都用到了“@{}”表达式,用来计算相对于URL的路径(就像在JSP页面中,我们可能会使用的JSTL <c:url>标签或Spring<s:url>标签类似)。

尽管home.html是一个相当简单的Thymeleaf模板,但是它依然很有价值,这在于它与纯HTML模板非常接近。唯一的区别之处在于th:href属性,否则的话,它就是基础且功能丰富的HTML文件。

这意味着Thymeleaf模板与JSP不同,它能够按照原始的方式进行编辑甚至渲染,而不必经过任何类型的处理器。当然,我们需要Thymeleaf来处理模板并渲染得到最终期望的输出。即便如此,如果没有任何特殊的处理,home.html也能够加载到Web浏览器中,并且看上去与完整渲染的效果很类似。为了更加清晰地阐述这一点,图6.6对比了home.jsp(上方)和home.html(下方)在Web浏览器中的显式效果。

可以看到,在Web浏览器中,JSP模板的渲染效果很糟糕。尽管我们可以看到一些熟悉的元素,但是JSP标签库的声明也显示了出来。在链接前出现了一些令人费解的未闭合标记,这是Web浏览器没有正常解析<s:url>标签的结果。

与之相反,Thymeleaf模板的渲染效果基本上没有任何错误。稍微有点问题的是链接部分,Web浏览器并不会像处理href属性那样处理th:href,所以链接并没有渲染为链接的样子。除了这些细微的问题,模板的渲染效果与我们的预期完全符合。

像home.jsp这样的模板作为Thymeleaf入门是很合适的。但是Spring的JSP标签所擅长的是表单绑定。如果我们抛弃JSP的话,那是不是也要抛弃表单绑定呢?不必担心。Thymeleaf提供了与之相匹敌的功能。

图6.6 Thymeleaf模板与JSP不同,它是HTML,
可以像HTML那样进行渲染和编辑

借助Thymeleaf实现表单绑定

表单绑定是Spring MVC的一项重要特性。它能够将表单提交的数据填充到命令对象中,并将其传递给控制器,而在展现表单的时候,表单中也会填充命令对象中的值。如果没有表单绑定功能的话,我们需要确保HTML表单域要映射后端命令对象中的属性,并且在校验失败后展现表单的时候,还要负责确保输入域中值要设置为命令对象的属性。

但是,如果有表单绑定的话,它就会负责这些事情了。为了复习一下表单绑定是如何运行的,下面展现了在registration.jsp中的First Name输入域:

在这里,调用了Spring表单绑定标签库的<sf:input>标签,它会渲染出一个HTML <input>标签,并且其value属性设置为后端对象firstName属性的值。它还使用了Spring的<sf:label>标签及其cssErrorClass属性,如果出现校验错误的话,会将文本标记渲染为红色。

但是,我们本节讨论的并不是JSP,而是使用Thymeleaf替换JSP。因此,我们不能使用Spring的JSP标签实现表单绑定,而是使用Thymeleaf的Spring方言。

作为阐述的样例,请参考如下的Thymeleaf模板片段,它会渲染First Name输入域:

在这里,我们不再使用Spring JSP标签中的cssClassName属性,而是在标准的HTML标签上使用th:class属性。th:class属性会渲染为一个class属性,它的值是根据给定的表达式计算得到的。在上面的这两个th:class属性中,它会直接检查firstName域有没有校验错误。如果有的话,class属性在渲染时的值为error。如果这个域没有错误的话,将不会渲染class属性。

<input>标签使用了th:field属性,用来引用后端对象的firstName域。这可能与你的预期有点差别。在Thymeleaf模板中,我们在很多情况下所使用的属性都对应于标准的HTML属性,因此貌似使用th:value属性来设置<input>标签的value属性才是合理的。

其实不然,因为我们是在将这个输入域绑定到后端对象的firstName属性上,因此使用th:field属性引用firstName域。通过使用th:field,我们将value属性设置为firstName的值,同时还会将name属性设置为firstName。

为了阐述Thymeleaf是如何实际运行的,如下的程序清单展示了完整的注册表单模板。

程序清单6.7 注册页面,使用Thymeleaf将一个表单绑定到命令对象上

程序清单6.7使用了相同的Thymeleaf属性和“*{}”表达式,为所有的表单域绑定后端对象。这其实重复了我们在First Name域中所做的事情。

但是,需要注意我们在表单的顶部了也使用了Thymeleaf,它会用来渲染所有的错误。<div>元素使用th:if属性来检查是否有校验错误。如果有的话,会渲染<div>,否则的话,它将不会渲染。

在<div>中,会使用一个无顺序的列表来展现每项错误。<li>标签上的th:each属性将会通知Thymeleaf为每项错误都渲染一个<li>,在每次迭代中会将当前错误设置到一个名为err的变量中。

<li>标签还有一个th:text属性。这个命令会通知Thymeleaf计算某一个表达式(在本例中,也就是err变量)并将它的值渲染为<li>标签的内容体。实际上的效果就是每项错误对应一个<li>元素,并展现错误的文本。

你可能会想知道“${}”和“*{}”括起来的表达式到底有什么区别。“${}”表达式(如${spitter})是变量表达式(variable expression)。一般来讲,它们会是对象图导航语言(Object-Graph Navigation Language,OGNL)表达式(http://commons.apache.org/proper/commons-ognl/)。但在使用Spring的时候,它们是SpEL表达式。在${spitter}这个例子中,它会解析为key为spitter的model属性。

而对于“*{}”表达式,它们是选择表达式(selection expression)。变量表达式是基于整个SpEL上下文计算的,而选择表达式是基于某一个选中对象计算的。在本例的表单中,选中对象就是<form>标签中th:object属性所设置的对象:模型中的Spitter对象。因此,“*{firstName}”表达式就会计算为Spitter对象的firstName属性。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文