本篇文章是對上篇文章中Thymeleaf標簽的補充。
1.th:each:循環,<tr th:each="user,userStat:${users}">,userStat是狀態變量,有 index,count,size,current,even,odd,first,last等屬性,如果沒有顯示設置狀態變量.thymeleaf會默認給個“變量名+Stat"的狀態變量。
下面大家看下例子:
<form id="login-form" th:action="@{/addStudent}" th:object="${stuReqBean}" method="POST">
<div class="student" th:each="stuIter,rowStat:${stuReqBean.students}">
<input type="text" class="firstName" value="" th:field="*{students[__${rowStat.index}__].firstName}"></input>
<input type="text" class="school" value="" th:field="*{students[__${rowStat.index}__].school}"></input> </div>
</form>
上面的例子中通過選擇表達式*{}既能將表單綁定到后台的StudentRequestBean中的集合屬性students,也能將Servlet上下文中的StudentRequestBean中的List類型的students變量回顯,回顯時通過th:each進行遍歷。
注意1:綁定集合屬性元素下標的用法*{students[__${rowStat.index}__].firstName}
注意2:如果List<Student> students為null,頁面將無法顯示表單,后台必須給students初始化一個值,即:
List<Student > stus = new ArrayList<Student >(); stus .add(new Student ()); StudentRequestBean.setStudents(stus );
注意3:stuIter代表students的迭代器。
還記得我們之前用過的這個例子嗎?
<table>
<tr>
<th>食物名稱</th>
<th>食物價格</th>
<th>可現做</th>
<th>食客評價</th>
</tr>
<tr th:each="prod:${prods}">
<td th:text="${prod.name}">醋溜土豆絲</td>
<td th:text="${#numbers.formatDecimal(prod.price,0,2)}">2.41</td>
<td th:text="${prod.isReady}?#{true}:#{false}">yes</td>
<td>
<span th:text=${#lists.size(prod.comments)}>2</span>個評價 <a href="comments.html" th:href="@{/product/comments(prodId=${prod.id})}" th:if="${not #lists.isEmpty(prod.comments)}">查看</a>
</td>
</tr>
</table>
**prod:\({prods}**屬性值的意思是,迭代\){prods}的每個元素並重復這個模板的這個片段。然后解釋一下這兩部分分別的意思:
- ${prods}被稱為迭代表達式或迭代變量
- prod被稱為重復變量或迭代值
注意:迭代值只可以用在tr節點上面(包括迭代里邊包含的td標簽)。
保持迭代狀態:當使用th:each的時候,Thymeleaf會提供一個跟着迭代狀態的機制:狀態變量。狀態定義被封裝在th:each的屬性中。並包含以下數據:
- 獲取當前迭代的從0開始的下標,使用index屬性
- 獲取當前迭代的從1開始的下標,使用count屬性
- 獲取當前迭代元素的總量,使用size屬性
- 獲取迭代變量中的迭代值,使用current屬性
- 當前迭代值是奇數還是偶數,使用even/odd的布爾值屬性
- 當前的迭代值是不是第一個元素,使用first布爾值屬性
- 當前迭代值是不是最后一個元素,使用last布爾值屬性。
現在將上面的例子稍作修改:
<h1>產品列表</h1>
<table>
<tr>
<th>產品名稱</th>
<th>產品價格</th>
<th>有現貨</th>
</tr>
<tr th:each="prod,iterStat:${prods}" th:class="${iterStat.odd}?'odd'">
<td th:text="${prod.name}">土豆</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="@{/}">返回首頁</a>
</p>
可以看到,狀態變量(即iterStat)的定義:將這個變量的名字作為屬性寫在迭代值之后,用逗號於迭代值隔開。產生了迭代值之后,他的狀態值就可以也僅僅可以在th:each包含的代碼段中使用。我們再來看一個例子:
<ol>
<li>List循環: <table border="1">
<tr>
<th>用戶名</th>
<th>郵箱</th>
<th>管理員</th>
<th>狀態變量:index</th>
<th>狀態變量:count</th>
<th>狀態變量:size</th>
<th>狀態變量:current.userName</th>
<th>狀態變量:even</th>
<th>狀態變量:odd</th>
<th>狀態變量:first</th>
<th>狀態變量:last</th>
</tr>
<tr th:each="user,userStat : ${list}">
<td th:text="${user.userName}">Onions</td>
<td th:text="${user.email}">test@test.com.cn</td>
<td th:text="${user.isAdmin}">yes</td>
<th th:text="${userStat.index}">狀態變量:index</th>
<th th:text="${userStat.count}">狀態變量:count</th>
<th th:text="${userStat.size}">狀態變量:size</th>
<th th:text="${userStat.current.userName}">狀態變量:current</th>
<th th:text="${userStat.even}">狀態變量:even****</th>
<th th:text="${userStat.odd}">狀態變量:odd</th>
<th th:text="${userStat.first}">狀態變量:first</th>
<th th:text="${userStat.last}">狀態變量:last</th>
</tr>
</table>
</li>
<li>Map循環: <div th:each="mapS:${map}">
<div th:text="${mapS}"></div>
</div>
</li>
<li>數組循環: <div th:each="arrayS:${arrays}">
<div th:text="${arrayS}"></div>
</div>
</li>
</ol>
現在對each有理解了嗎?如果還沒有的話,這里還有一個例子:
<div class="item active" th:if="${iterStat.index==0}" th:each="img,iterStat:${pics}"> <img th:src="${img.path}" style="width: 303px;height: 171px;"/> </div>
/*對arrayList對象pics遍歷,使用img作為接受參數接收,使用iterStat作為pics下標值,通過iterStat.index得到當前所處下標值;通過th:src="${img.path}"得到對象中圖片路徑設置圖片顯示圖*/
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'"> <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>
/*判斷下標是否為奇數,設置tr樣式*/
2.th:fragment:我們經常會想讓我們的模板包含一些其他模板,比較常見的用途如頁眉,頁腳,菜單等。為了做到這一點,Thymeleaf需要我們定義一些可用片段,我們能通過th:fragment屬性來實現這一點。
例如:
聲明模板片段/WEBINF/templates/footer. html
<div th: fragment=" copy" > © 2011 The Good Thymes Virtual Grocery </div>
引入模板片段:
<div th: include=" /templates/footer : : copy" ></div>
<div th: replace=" /templates/footer : : copy" ></div>
現在是不是對include replace有有疑問了呢?先看下 th:insert和th:replace的不同點(以及th:include)
- th:insert是將th:fragment標簽的內容納入宿主標簽
- th:replace是使用th:fragment標簽替換宿主標簽
- th:include與th:insert類似,但是他插入的是片段的內容,而不是片段。
還是舉個例子吧:
<div th:fragment="copy">
© 網絡商店 </div>
導入到兩個div標簽中:
<body> ... <div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
</body>
執行結果:
<body> ... <div>
<footer>
© 網絡商店 </footer>
</div>
<footer>
© 網絡商店 </footer>
<div>
© 網絡商店 </div>
</body>
3.th:attr:設置標簽屬性,多個屬性可以用逗號分隔,比如th:attr="src=@{/image/aa.jpg},title=#{logo}" (很多大博客上都說這個標簽不夠優雅,很難看,所以,不常用。)
<form action="subscribe.html" th:attr="action=@{/subscribe}">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="訂閱!" th:attr="value=#{subscribe.submit}"/>
</fieldset>
</form>
用法很簡單:th:attr將是一個值對應一個屬性的表達式,在轉換處理后,將會返回如下結果:
<form action="/gtvg/subscribe">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="subscribe me!"/>
</fieldset>
</form>
除了更新了屬性值,還可以看到,應用的已經自動將url更新為context前綴的url.如果,我們想在同時更新多個屬性呢?xml的規則不允許在一個標簽內設置兩個同名的屬性,所以,可以用逗號來分割th:attr的值,比如:
<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
將轉換為:
<img src="/gtgv/images/gtvglogo.png" title="這里是logo" alt="這里是logo" />
下一章節講介紹一些安裝以及真正在工作當中的使用方法。