- 作者简介
- 内容提要
- 关于本书
- 路线图
- 代码规范与下载
- 作者在线
- 封面插图简介
- 前言
- 译者序
- 致谢
- 第1部分 Spring 的核心
- 第1章 Spring 之旅
- 第2章 装配 Bean
- 第3章 高级装配
- 第4章 面向切面的 Spring
- 第2部分 Web 中的 Spring
- 第5章 构建 Spring Web 应用程序
- 第6章 渲染 Web 视图
- 第7章 Spring MVC 的高级技术
- 第8章 使用 Spring Web Flow
- 第9章 保护 Web 应用
- 第3部分 后端中的 Spring
- 第10章 通过 Spring 和 JDBC 征服数据库
- 第11章 使用对象-关系映射持久化数据
- 第12章 使用 NoSQL 数据库
- 第13章 缓存数据
- 第14章 保护方法应用
- 第4部分 Spring 集成
- 第15章 使用远程服务
- 第16章 使用 Spring MVC 创建 REST API
- 第17章 Spring消息
- 第18章 使用 WebSocket 和 STOMP 实现消息功能
- 第19章 使用 Spring 发送 Email
- 第20章 使用 JMX 管理 Spring Bean
- 第21章 借助 Spring Boot 简化 Spring 开发
6.4.2 定义 Thymeleaf 模板
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论