-
JSP的问题
(1) JSP及其标签库缺乏良好的格式
(2) JSP与Servlet紧耦合,应用场景受限
-
Thymeleaf
(1) 原生模板,不依赖标签库
(2) 不仅限于Servlet
-
配置Thymeleaf视图解析器
(1) 需要添加3个bean:ThymeleafViewResolver(将逻辑视图名称解析为Thymeleaf模板视图)、SpringTemplateEngine(处理模板并渲染结果)、TemplateResolver(加载Thymeleaf模板)
(2) JavaConfig示例
WebConfig.java
@Configuration @EnableWebMvc @ComponentScan("spittr.web") public class WebConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver(SpringTemplateEngine templateEngine) { ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine); return viewResolver; } @Bean public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver); return templateEngine; } @Bean public TemplateResolver templateResolver() { TemplateResolver templateResolver = new ServletContextTemplateResolver(); templateResolver.setPrefix("/WEB-INF/views/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode("HTML5"); return templateResolver; } ... }
类似于InternalResourceViewResolver,templateResolver同样要设置prefix,suffix,并且要设置templateMode为html5
-
Thymeleaf模板
(1) Thymeleaf很大程度上就是html文件。它没有标签,靠自定义的命名空间,为标准的html标签集合添加Thymeleaf属性实现功能(即声明了xmlns:th="http://www.thymeleaf.org"之后,用th:xxx来使用自定义元素).
(2) Thymeleaf可以按照原始的方式进行编辑和渲染。即便不经过任何特殊的处理,包含了Thymeleaf模板的html文件也可以加载到浏览器上,不会产生和JSP文件一样的"奇怪"效果
(3) 声明Thymeleaf命名空间
home.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> ...
(4) 示例1:home.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>Spitter</title> <link rel="stylesheet" type="text/css" th:href="@{/resources/style.css}"/> </head> <body> <div id="header" th:include="page::header"></div> <div id="content"> <h1>Welcome to Spitter</h1> <a th:href="@{/spittles}">Spittles</a> | <a th:href="@{/spitter/register}">Register</a> <br/> </div> <div id="footer" th:include="page::copy"> </div> </body> </html>
th:href类似于<c:url>和原生的href,代表资源url;它可以包含Thymeleaf表达式,计算动态的值。 @{...}用来计算相对于URL的路径
th:include类似于Apache Tiles的页面布局,对于通用页面page.html,可以引用过来。a::b中的b要在a.html中的 th:fragment 指定
page.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <body> <div th:fragment="header"> <a th:href="@{/}"> <img th:src="@{/resources/images/spitter_logo_50.png}" border="0"/> </a> </div> <div> Content goes here </div> <div th:fragment="copy"> Copyright © Craig Walls </div> </body> </html>
(5) 示例2:spittles.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> ... <body> <div id="header" th:include="page :: header"></div> <div id="content"> ... <div class="listTitle"> <h1>Recent Spittles</h1> <ul class="spittleList"> <li th:each="spittle : ${spittleList}" th:id="'spittle_' + ${spittle.id}"> <div class="spittleMessage" th:text="${spittle.message}">Spittle message </div> <div> <span class="spittleTime" th:text="${spittle.time}">spittle timestamp </span> <span class="spittleLocation" th:text="'{' + ${spittle.latitude} + ', ' + ${spittle.longitude} + ')'">lat, long </span> </div> </li> </ul> </div> </div> <div id="footer" th:include="page :: copy"></div> </body> </html>
{spittleList}会得到model中key为"spittleList"的对象;
<li>标签
上的th:each属性可以从容器中取一个元素(这里面叫做spittle),然后在别的地方可以使用${spittle.xxx};
th:text类似于<c:out>,用于输出文本,并且可以动态输出变量的值;
对于动态字符串拼接,例如 th:text="'{' + {spittle.longitude} + ')'",使用'xxx'代表某个子字符串,并且可以动态拼接变量的值(不一定是字符串,有toString()方法即可)
(5) 示例3: registerForm.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> .... <body> <div id="header" th:include="page::copy"> </div> <div id="content"> <h1>Register</h1> <form method="POST" th:object="${spitter}"> <div class="errors" th:if="${#fields.hasErrors('*')}"> <ul> <li th:each="err : ${#fields.errors('*')}" th:text="${err}"> Input is incorrect </li> </ul> </div> <label th:class="${#fields.hasErrors('firstName')}? 'error'">First Name</label>: <input type="text" th:field="*{firstName}" th:class="${#fields.hasErrors('firstName')}? 'error'"/> <br/> <label th:class="${#fields.hasErrors('lastName')}? 'error'">Last Name</label>: <input type="text" th:field="*{lastName}" th:class="${#fields.hasErrors('lastName')}? 'error'"/> <br/> <label th:class="${#fields.hasErrors('email')}? 'error'">Email</label>: <input type="text" th:field="*{email}" th:class="${#fields.hasErrors('email')}? 'error'"/> <br/> <label th:class="${#fields.hasErrors('username')}? 'error'">Username</label>: <input type="text" th:field="*{username}" th:class="${#fields.hasErrors('username')}? 'error'"/> <br/> <label th:class="${#fields.hasErrors('password')}? 'error'">Password</label>: <input type="password" th:field="*{password}" th:class="${#fields.hasErrors('password')}? 'error'"/> <br/> <input type="submit" value="Register"/> </form> </div> <div id="footer" th:include="page :: copy"> </div> </body> </html>
th:object用于表单form的数据模型绑定,这里绑定了spitter;
*{}是选择表达式,和${}不同,它是基于某一个选中对象计算的,因此
th:field="*{firstName}代表 spitter.firstName;
#fields是
Thymeleaf内置对象,类似的还有HttpSession等,它可以用来检查是否有错误;
<label th:class="${#fields.hasErrors('firstName')}? 'error'">会检查 spitter.firstName是否有错误,如果有错误,当前label的class置为label.error,然后根据css中的label.error渲染成错误显示的效果;
th:field="*{email}"的效果是将value属性设置为spitter.email的值,同时name属性设置为email;
th:if用于判断是否进入内部的渲染部分
网友评论