Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。相似JSP,Velocity,FreeMaker等,它也能够轻易的与Spring MVC等Web框架进行集成做为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特色是可以直接在浏览器中打开并正确显示模板页面,而不须要启动整个Web应用。css
Thymeleaf初探
相比于其余的模板引擎,Thymeleaf最大的特色是经过HTML的标签属性渲染标签内容,如下是一个Thymeleaf模板例子:html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <title>Good Thymes Virtual Grocery</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" media="all" href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" /> </head> <body> <p th:text="#{home.welcome}">Welcome to our grocery store!</p> </body> </html>
这是一段标准的HTML代码,这也就意味着经过浏览器直接打开它是能够正确解析它的结构并看到页面的样子。相比去其余的模板引擎在指定的位置经过${}</code>等表达式进行渲染,Thymeleaf则是一种针对HTML/XML定制的模板语言(固然它能够被扩展),它经过标签中的<code>th:text</code>属性来填充该标签的一段内容。上例中,<code><p th:text="#{home.welcome}">Welcome to our grocery store!</p></code>意味着<code><p></code>标签中的内容会被表达式<code>#{home.welcome}</code>的值所替代,不管模板中它的内容是什么,之因此在模板中“画蛇添足“地填充它的内容,彻底是为了它可以做为原型在浏览器中直接显示出来。</p><h2 id="1">标准表达式语法</h2><h3 id="2">变量</h3><p>Thymeleaf模板引擎在进行模板渲染时,还会附带一个Context存放进行模板渲染的变量,在模板中定义的表达式本质上就是从Context中获取对应的变量的值:</p><pre><code><p>Today is: <span th:text="${today}">13 february 2011</span>.</p>
前端
假设today
的值为2015年8月14日
,那么渲染结果为:<p>Today is: 2015年8月14日.</p>
。可见Thymeleaf的基本变量和JSP同样,都使用${.}
表示获取变量的值。java
URL
URL在Web应用模板中占据着十分重要的地位,须要特别注意的是Thymeleaf对于URL的处理是经过语法@{...}
来处理的。Thymeleaf支持绝对路径URL:web
<a th:href="@{http://www.thymeleaf.org}">Thymeleaf</a>
同时也可以支持相对路径URL:spring
- 当前页面相对路径URL——
user/login.html
,一般不推荐这样写。 - Context相关URL——
/static/css/style.css
另外,若是须要Thymeleaf对URL进行渲染,那么务必使用th:href
,th:src
等属性,下面是一个例子后端
<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) --> <a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a> <!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) --> <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a> <!-- Will produce '/gtvg/order/3/details' (plus rewriting) --> <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
几点说明:跨域
- 上例中URL最后的(orderId={o.id})表示将括号内的内容做为URL参数处理,该语法避免使用字符串拼接,大大提升了可读性</li><li><code>@{...}</code>表达式中能够经过<code>{orderId}</code>访问Context中的<code>orderId</code>变量</li><li><code>@{/order}</code>是Context相关的相对路径,在渲染时会自动添加上当前Web应用的Context名字,假设context名字为app,那么结果应该是<code>/app/order</code></li></ul><h3 id="4">字符串替换</h3><p>不少时候可能咱们只须要对一大段文字中的某一处地方进行替换,能够经过字符串拼接操做完成:</p><pre><code><span th:text="'Welcome to our application, ' +{user.name} + ‘!’”>
一种更简洁的方式是:浏览器
<span th:text="|Welcome to our application, ${user.name}!|">
固然这种形式限制比较多,
|...|
中只能包含变量表达式${...}</code>,不能包含其余常量、条件表达式等。</p><h3 id="5">运算符</h3><p>在表达式中可使用各种算术运算符,例如+, -, *, /, %</p><pre><code>th:with="isEven=(${prodStat.count} % 2 == 0)"
spring-mvc逻辑运算符
>
,<
,<=
,>=
,==
,!=
均可以使用,惟一须要注意的是使用<
,>
时须要用它的HTML转义符:th:if="${prodStat.count} > 1" th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')"
循环
渲染列表数据是一种很是常见的场景,例如如今有n条记录须要渲染成一个表格
<table>
,该数据集合必须是能够遍历的,使用th:each
标签:<body> <h1>Product list</h1> <table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr th:each="prod : ${prods}"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> </tr> </table> <p> <a href="../home.html" th:href="@{/}">Return to home</a> </p> </body>
能够看到,须要在被循环渲染的元素(这里是
<tr>
)中加入th:each
标签,其中th:each="prod : ${prods}"</code>意味着对集合变量<code>prods</code>进行遍历,循环变量是<code>prod</code>在循环体中能够经过表达式访问。</p><h2 id="7">条件求值</h2><h3 id="8">If/Unless</h3><p>Thymeleaf中使用<code>th:if</code>和<code>th:unless</code>属性进行条件判断,下面的例子中,<code><a></code>标签只有在<code>th:if</code>中条件成立时才显示:</p><pre><code><a th:href="@{/login}" th:unless=${session.user != null}>Login</a>
th:unless
于th:if
刚好相反,只有表达式中的条件不成立,才会显示其内容。Switch
Thymeleaf一样支持多路选择Switch结构:
<div th:switch="${user.role}"> <p th:case="'admin'">User is an administrator</p> <p th:case="#{roles.manager}">User is a manager</p> </div>
默认属性default能够用
*
表示:<div th:switch="${user.role}"> <p th:case="'admin'">User is an administrator</p> <p th:case="#{roles.manager}">User is a manager</p> <p th:case="*">User is some other thing</p> </div>
Utilities
为了模板更加易用,Thymeleaf还提供了一系列Utility对象(内置于Context中),能够经过
#
直接访问:#dates
#calendars
#numbers
#strings
arrays
lists
sets
maps
- …
下面用一段代码来举例一些经常使用的方法:
#dates
/* * Format date with the specified pattern * Also works with arrays, lists or sets */ ${#dates.format(date, 'dd/MMM/yyyy HH:mm')} ${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')} ${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')} ${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')} /* * Create a date (java.util.Date) object for the current date and time */ ${#dates.createNow()} /* * Create a date (java.util.Date) object for the current date (time set to 00:00) */ ${#dates.createToday()}
#strings
/* * Check whether a String is empty (or null). Performs a trim() operation before check * Also works with arrays, lists or sets */ ${#strings.isEmpty(name)} ${#strings.arrayIsEmpty(nameArr)} ${#strings.listIsEmpty(nameList)} ${#strings.setIsEmpty(nameSet)} /* * Check whether a String starts or ends with a fragment * Also works with arrays, lists or sets */ ${#strings.startsWith(name,'Don')} // also array*, list* and set* ${#strings.endsWith(name,endingFragment)} // also array*, list* and set* /* * Compute length * Also works with arrays, lists or sets */ ${#strings.length(str)} /* * Null-safe comparison and concatenation */ ${#strings.equals(str)} ${#strings.equalsIgnoreCase(str)} ${#strings.concat(str)} ${#strings.concatReplaceNulls(str)} /* * Random */ ${#strings.randomAlphanumeric(count)}
页面即原型
在Web开发过程当中一个绕不开的话题就是前端工程师与后端工程师的写做,在传统Java Web开发过程当中,前端工程师和后端工程师同样,也须要安装一套完整的开发环境,而后各种Java IDE中修改模板、静态资源文件,启动/重启/从新加载应用服务器,刷新页面查看最终效果。
但实际上前端工程师的职责更多应该关注于页面自己而非后端,使用JSP,Velocity等传统的Java模板引擎很难作到这一点,由于它们必须在应用服务器中渲染完成后才能在浏览器中看到结果,而Thymeleaf从根本上颠覆了这一过程,经过属性进行模板渲染不会引入任何新的浏览器不能识别的标签,例如JSP中的
<form:input>
,不会在Tag内部写表达式。整个页面直接做为HTML文件用浏览器打开,几乎就能够看到最终的效果,这大大解放了前端工程师的生产力,它们的最终交付物就是纯的HTML/CSS/JavaScript文件。进一步阅读