新一代Java模板引擎Thymeleaf

本文由Ricky創作,文章出自:《新一代Java模板引擎Thymeleaf》

Thymeleaf是一款用於渲染XML/XHTML/HTML5內容的模板引擎。類似JSP,Velocity,FreeMaker等,它也可以輕易的與Spring MVC等Web框架進行集成作爲Web應用的模板引擎。與其它模板引擎相比,Thymeleaf最大的特點是能夠直接在瀏覽器中打開並正確顯示模板頁面,而不需要啓動整個Web應用。

Thymeleaf初探

相比於其他的模板引擎,Thymeleaf最大的特點是通過HTML的標籤屬性渲染標籤內容,以下是一個Thymeleaf模板例子:

<!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代碼,這也就意味着通過瀏覽器直接打開它是可以正確解析它的結構並看到頁面的樣子。相比去其他的模板引擎在指定的位置通過${}等表達式進行渲染,Thymeleaf則是一種針對HTML/XML定製的模板語言(當然它可以被擴展),它通過標籤中的th:text屬性來填充該標籤的一段內容。上例中,<p th:text="#{home.welcome}">Welcome to our grocery store!</p>意味着<p>標籤中的內容會被表達式#{home.welcome}的值所替代,無論模板中它的內容是什麼,之所以在模板中“多此一舉“地填充它的內容,完全是爲了它能夠作爲原型在瀏覽器中直接顯示出來。

標準表達式語法

變量

Thymeleaf模板引擎在進行模板渲染時,還會附帶一個Context存放進行模板渲染的變量,在模板中定義的表達式本質上就是從Context中獲取對應的變量的值:

<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一樣,都使用${.}表示獲取變量的值。

URL

URL在Web應用模板中佔據着十分重要的地位,需要特別注意的是Thymeleaf對於URL的處理是通過語法@{...}來處理的。Thymeleaf支持絕對路徑URL:

<a th:href="@{http://www.thymeleaf.org}">Thymeleaf</a>

同時也能夠支持相對路徑URL:

  • 當前頁面相對路徑URL——user/login.html,通常不推薦這樣寫。
  • Context相關URL——/static/css/style.css

另外,如果需要Thymeleaf對URL進行渲染,那麼務必使用th:hrefth: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參數處理,該語法避免使用字符串拼接,大大提高了可讀性
  • @{...}表達式中可以通過{orderId}訪問Context中的orderId變量
  • @{/order}是Context相關的相對路徑,在渲染時會自動添加上當前Web應用的Context名字,假設context名字爲app,那麼結果應該是/app/order

字符串替換

很多時候可能我們只需要對一大段文字中的某一處地方進行替換,可以通過字符串拼接操作完成:

<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

一種更簡潔的方式是:

<span th:text="|Welcome to our application, ${user.name}!|">

當然這種形式限制比較多,|...|中只能包含變量表達式${...},不能包含其他常量、條件表達式等。

運算符

在表達式中可以使用各類算術運算符,例如+, -, *, /, %

th:with="isEven=(${prodStat.count} % 2 == 0)"

邏輯運算符><<=,>===,!=都可以使用,唯一需要注意的是使用<,>時需要用它的HTML轉義符:

th:if="${prodStat.count} &gt; 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}"意味着對集合變量prods進行遍歷,循環變量是prod在循環體中可以通過表達式訪問。

條件求值

If/Unless

Thymeleaf中使用th:ifth:unless屬性進行條件判斷,下面的例子中,<a>標籤只有在th:if中條件成立時才顯示:

<a th:href="@{/login}" th:unless=${session.user != null}>Login</a>

th:unlessth: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文件。

進一步閱讀

版權聲明

本文由Ricky創作,轉載需署名作者且註明文章出處

參考代碼

要獲取本文的參考代碼,請訪問: https://www.tianmaying.com/tutorial/using-thymeleaf/repo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章