工具集核心教程 | 第三篇: Thymeleaf模板引擎入門到進階

thymeleaf介紹

簡單說, Thymeleaf 是一個跟 Velocity、FreeMarker 類似的模板引擎,它可以完全替代 JSP。相較與其他的模板引擎,它有如下三個極吸引人的特點:

1.Thymeleaf 在有網絡和無網絡的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程序員在服務器查看帶數據的動態頁面效果。這是由於它支持 html 原型,然後在 html 標籤裏增加額外的屬性來達到模板+數據的展示方式。瀏覽器解釋 html 時會忽略未定義的標籤屬性,所以 thymeleaf 的模板可以靜態地運行;當有數據返回到頁面時,Thymeleaf 標籤會動態地替換掉靜態內容,使頁面動態顯示。

2.Thymeleaf 開箱即用的特性。它提供標準和spring標準兩種方言,可以直接套用模板實現JSTL、 OGNL表達式效果,避免每天套模板、該jstl、改標籤的困擾。同時開發人員也可以擴展和創建自定義的方言。

3.Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實現表單綁定、屬性編輯器、國際化等功能。

標準表達式語法

它們分爲四類:

1.變量表達式
2.選擇或星號表達式
3.文字國際化表達式
4.URL表達式

變量表達式

變量表達式即OGNL表達式或Spring EL表達式(在Spring術語中也叫model attributes)。如下所示:
${session.user.name}

它們將以HTML標籤的一個屬性來表示:

<span th:text="${book.author.name}">  
<li th:each="book : ${books}">  

選擇(星號)表達式

選擇表達式很像變量表達式,不過它們用一個預先選擇的對象來代替上下文變量容器(map)來執行,如下:
*{customer.name}

被指定的objectth:object屬性定義:

 <div th:object="${book}">  
     ...  
    <span th:text="*{title}">...</span>  
    ...  
 </div>  

文字國際化表達式

文字國際化表達式允許我們從一個外部文件獲取區域文字信息(.properties),用Key索引Value,還可以提供一組參數(可選).

  #{main.title}  
  #{message.entrycreated(${entryId})}  

可以在模板文件中找到這樣的表達式代碼:

 <table>  
    ...  
   <th th:text="#{header.address.city}">...</th>  
   <th th:text="#{header.address.country}">...</th>  
   ...  
 </table>  

URL表達式

URL表達式指的是把一個有用的上下文或回話信息添加到URL,這個過程經常被叫做URL重寫。

@{/order/list}

URL還可以設置參數:

@{/order/details(id=${orderId})}

相對路徑:

@{../documents/report}

讓我們看這些表達式:

   <form th:action="@{/createOrder}">  
   <a href="main.html" th:href="@{/main}">

變量表達式和星號表達有什麼區別嗎?

如果不考慮上下文的情況下,兩者沒有區別;星號語法評估在選定對象上表達,而不是整個上下文
什麼是選定對象?就是父標籤的值,如下:

  <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
  </div>

這是完全等價於:

  <div th:object="${session.user}">
      <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p>
      <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
      <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
  </div>

當然,美元符號和星號語法可以混合使用:

  <div th:object="${session.user}">
      <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
      <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p>
      <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
  </div>

表達式支持的語法

字面(Literals)

文本文字(Text literals): 'one text', 'Another one!',…
數字文本(Number literals): 0, 34, 3.0, 12.3,…
布爾文本(Boolean literals): true, false
空(Null literal): null
文字標記(Literal tokens): one, sometext, main,…

文本操作(Text operations)

字符串連接(String concatenation): +
文本替換(Literal substitutions): |The name is ${name}|

算術運算(Arithmetic operations)

二元運算符(Binary operators): +, -, *, /, %
減號(單目運算符)Minus sign (unary operator): -

布爾操作(Boolean operations)

二元運算符(Binary operators):and, or
布爾否定(一元運算符)Boolean negation (unary operator):!, not

比較和等價(Comparisons and equality)

比較(Comparators): >, <, >=, <= (gt, lt, ge, le)
等值運算符(Equality operators):==, != (eq, ne)

條件運算符(Conditional operators)

If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)

所有這些特徵可以被組合並嵌套:

'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

常用th標籤都有那些?

關鍵字 功能介紹 案例
th:id 替換id <input th:id="'xxx' + ${collect.id}"/>
th:text 文本替換 <p th:text="${collect.description}">description</p>
th:utext 支持html的文本替換 <p th:utext="${htmlcontent}">conten</p>
th:object 替換對象 <div th:object="${session.user}">
th:value 屬性賦值 <input th:value="${user.name}" />
th:with 變量賦值運算 <div th:with="isEven=${prodStat.count}%2==0"></div>
th:style 設置樣式 th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''"
th:onclick 點擊事件 th:onclick="'getCollect()'"
th:each 屬性賦值 tr th:each="user,userStat:${users}">
th:if 判斷條件 <a th:if="${userId == collect.userId}" >
th:unless th:if判斷相反 <a th:href="@{/login}" th:unless=${session.user != null}>Login</a>
th:href 鏈接地址 <a th:href="@{/login}" th:unless=${session.user != null}>Login</a> />
th:switch 多路選擇 配合th:case 使用 <div th:switch="${user.role}">
th:case th:switch的一個分支 <p th:case="'admin'">User is an administrator</p>
th:fragment 佈局標籤,定義一個代碼片段,方便其它地方引用 <div th:fragment="alert">
th:include 佈局標籤,替換內容到引入的文件 <head th:include="layout :: htmlhead" th:with="title='xx'"></head> />
th:replace 佈局標籤,替換整個標籤到引入的文件 <div th:replace="fragments/header :: title"></div>
th:selected selected選擇框 選中 th:selected="(${xxx.id} == ${configObj.dd})"
th:src 圖片類地址引入 <img class="img-responsive" alt="App Logo" th:src="@{/img/logo.png}" />
th:inline 定義js腳本可以使用變量 <script type="text/javascript" th:inline="javascript">
th:action 表單提交的地址 <form action="subscribe.html" th:action="@{/subscribe}">
th:remove 刪除某個屬性 <tr th:remove="all"> 1.all:刪除包含標籤和所有的孩子。2.body:不包含標記刪除,但刪除其所有的孩子。3.tag:包含標記的刪除,但不刪除它的孩子。4.all-but-first:刪除所有包含標籤的孩子,除了第一個。5.none:什麼也不做。這個值是有用的動態評估。
th:attr 設置標籤屬性,多個屬性可以用逗號分隔 比如 th:attr="src=@{/image/aa.jpg},title=#{logo}",此標籤不太優雅,一般用的比較少。

還有非常多的標籤,這裏只列出最常用的幾個,由於一個標籤內可以包含多個th:x屬性,其生效的優先級順序爲:

include,each,if/unless/switch/case,with,attr/attrprepend/attrappend,value/href,src ,etc,text/utext,fragment,remove。

幾種常用的使用方法

1、賦值、字符串拼接

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

字符串拼接還有另外一種簡潔的寫法

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

2、條件判斷 If/Unless

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

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

th:unlessth:if恰好相反,只有表達式中的條件不成立,纔會顯示其內容。

也可以使用 (if) ? (then) : (else) 這種語法來判斷顯示的內容

3、for 循環

  <tr  th:each="collect,iterStat : ${collects}"> 
     <th scope="row" th:text="${collect.id}">1</th>
     <td >
        <img th:src="${collect.webLogo}"/>
     </td>
     <td th:text="${collect.url}">Mark</td>
     <td th:text="${collect.title}">Otto</td>
     <td th:text="${collect.description}">@mdo</td>
     <td th:text="${terStat.index}">index</td>
 </tr>

iterStat稱作狀態變量,屬性有:

index:當前迭代對象的index(從0開始計算)
count: 當前迭代對象的index(從1開始計算)
size:被迭代對象的大小
current:當前迭代變量
even/odd:布爾值,當前循環是否是偶數/奇數(從0開始計算)
first:布爾值,當前循環是否是第一個
last:布爾值,當前循環是否是最後一個

4、URL

URLWeb應用模板中佔據着十分重要的地位,需要特別注意的是Thymeleaf對於URL的處理是通過語法@{...}來處理的。
如果需要ThymeleafURL進行渲染,那麼務必使用th:href,th:src等屬性,下面是一個例子

<!-- Will produce 'http://localhost:8080/standard/unread' (plus rewriting) -->
 <a  th:href="@{/standard/{type}(type=${type})}">view</a>

<!-- Will produce '/gtvg/order/3/details' (plus rewriting) -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>

設置背景

<div th:style="'background:url(' + @{/<path-to-image>} + ');'"></div>

根據屬性值改變背景

 <div class="media-object resource-card-image"  th:style="'background:url(' + @{(${collect.webLogo}=='' ? 'img/favicon.png' : ${collect.webLogo})} + ')'" ></div>

幾點說明:

上例中`URL`最後的`(orderId=${o.id})` 表示將括號內的內容作爲`URL`參數處理,該語法避免使用字符串拼接,大大提高了可讀性
`@{...}`表達式中可以通過`{orderId}`訪問`Context`中的`orderId`變量
`@{/order}`是`Context`相關的相對路徑,在渲染時會自動添加上當前`Web`應用的`Context`名字,假設`Context`名字爲`app`,那麼結果應該是`/app/order`

5、內聯js

內聯文本:[[...]]內聯文本的表示方式,使用時,必須先用th:inline="text/javascript/none"激活,th:inline可以在父級標籤內使用,甚至作爲body的標籤。內聯文本儘管比th:text的代碼少,不利於原型顯示。

<script th:inline="javascript">
/*<![CDATA[*/
...
var username = /*[[${sesion.user.name}]]*/ 'Sebastian';
var size = /*[[${size}]]*/ 0;
...
/*]]>*/
</script>

js附加代碼:

/*[+
var msg = 'This is a working application';
+]*/

js移除代碼:

/*[- */
var msg = 'This is a non-working template';
/* -]*/

6、內嵌變量

爲了模板更加易用,Thymeleaf還提供了一系列Utility對象(內置於Context中),可以通過#直接訪問:

 `dates` : `java.util.Date`的功能方法類。
 `calendars` : 類似`#dates`,面向`java.util.Calendar`
 `numbers` : 格式化數字的功能方法類
 `strings` : 字符串對象的功能類,`contains,startWiths,prepending/appending`等等。
 `objects`: 對`objects`的功能類操作。
 `bools`: 對布爾值求值的功能方法。
 `arrays`:對數組的功能類方法。
 `lists`: 對`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)}

使用thymeleaf佈局

使用thymeleaf佈局非常的方便

定義代碼片段:

<footer th:fragment="copy"> 
&copy; 2016
</footer>

在頁面任何地方引入:

<body> 
  <div th:include="footer :: copy"></div>
  <div th:replace="footer :: copy"></div>
 </body>

th:includeth:replace區別,include只是加載,replace是替換

返回的HTML如下:

<body> 
   <div> &copy; 2016 </div> 
  <footer>&copy; 2016 </footer> 
</body>

下面是一個常用的後臺頁面佈局,將整個頁面分爲頭部,尾部、菜單欄、隱藏欄,點擊菜單隻改變content區域的頁面

<body class="layout-fixed">
  <div th:fragment="navbar"  class="wrapper"  role="navigation">
    <div th:replace="fragments/header :: header">Header</div>
    <div th:replace="fragments/left :: left">left</div>
    <div th:replace="fragments/sidebar :: sidebar">sidebar</div>
    <div layout:fragment="content" id="content" ></div>
    <div th:replace="fragments/footer :: footer">footer</div>
  </div>
</body>

任何頁面想使用這樣的佈局值只需要替換中見的 content模塊即可

 <html xmlns:th="http://www.thymeleaf.org" layout:decorator="layout">
   <body>
      <section layout:fragment="content">
    ...

也可以在引用模版的時候傳參

<head th:include="layout :: htmlhead" th:with="title='Hello'"></head>

layout 是文件地址,如果有文件夾可以這樣寫 fileName/layout:htmlhead
htmlhead 是指定義的代碼片段 如th:fragment="copy"

參考

新一代Java模板引擎Thymeleaf
Thymeleaf基本知識
thymeleaf總結文章
Thymeleaf 模板的使用
thymeleaf 學習筆記

寫在最後

歡迎關注喜歡、和點贊後續將推出更多的工具集教程,敬請期待。
歡迎關注我的微信公衆號獲取更多更全的學習資源,視頻資料,技術乾貨!
歡迎掃碼關注

公衆號回覆“學習”,拉你進程序員技術討論羣乾貨資源第一時間分享。

公衆號回覆“視頻”,領取800GJava視頻學習資源。
java學習全套
820G資源

公衆號回覆“全棧”,領取1T前端Java產品經理微信小程序Python等資源合集大放送。
全棧資料
java
python
機器學習
產品經理
接近1T資源

公衆號回覆“慕課”,領取1T慕課實戰學習資源。
慕課實戰大全
php
python
測試
後端
前端
前端
微信
1061G資源

公衆號回覆“實戰”,領取750G項目實戰學習資源。
前後端實戰項目
750實戰資源

公衆號回覆“面試”,領取8G面試實戰學習資源。
JAVA面試實戰視頻

傳智面試講解
8G面試資源

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