一、Thymeleaf模版簡介
官方文檔:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-a-expression-basic-objects
中文文檔:
https://www.e-learn.cn/thymeleaf/thymeleaf-instroduce
SpringBoot提供了大量的模版引擎,包括FreeMarker、Groovy、Thymeleaf、Velcoity和Mustache,SpringBoot中推薦使用Thymeleaf作為模版引擎,因為Thymeleaf提供了完美的SpringMVC支持。
Thymeleaf是一個java類庫,它是一個xml/xthml/html5的模版引擎,可以作為MVC的Web應用的View層。
- 通過xmlns:th=”http://www.thymeleaf.org”命名空間,將頁面轉換為動態試圖,需要進行動態處理的元素使用“th:”作為前綴。
- 通過th:text=”${person.name}”訪問model中的屬性。
- 通過th:each=”person:${people}”來做循環迭代。
- 通過th:if=”${not #lists.isEmpty(people)}”來判斷people是否為空。
5 .通過th:src=”@{jquery-3.3.1.min.js}”來訪問Web中的靜態資源。 - 通過th:inline=”javascript”來添加script標簽,這樣在JavaScript代碼中即可訪問model中的屬性值。
- 通過“[[${}]]”格式來獲得實際值。
在傳統的SpringMVC中,若我們需要集成一個模版引擎的話,需要定義ViewResolver。而Thymeleaf提供了一個SpringTemplateEngine的類,用來驅動SpringMVC下使用Thymeleaf模版引擎。而在SpringBoot中對Thymeleaf進行了自動配置,可以在application中以spring.thymeleaf開發來進行配置,不配置的情況下模版的默認目錄是templates。
在src/main/resource/static中放入需要引入的靜態資源:Bootstrap和jQuery。根據默認的原則在src/main/resource/templates下創建index.html文件。
二、SpringBoot整合Thymeleaf
- Maven依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
靜態資源
SpringBoot默認的幾個靜態頁面的目錄:
/static、/public、/resources 、/META-INF/resources配置Thymeleaf,在application.properties下配置
#thymelea模板配置
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.cache
是否開啟模板緩存,默認true
spring.thymeleaf.check-template-location
是否檢查模板路徑是否存在,默認true
spring.thymeleaf.content-type
指定Content-Type,默認為: text/html
spring.thymeleaf.enabled
是否允許MVC使用Thymeleaf,默認為: true
spring.thymeleaf.encoding
指定模板的編碼,默認為: UTF-8
spring.thymeleaf.excluded-view-names
指定不使用模板的視圖名稱,多個以逗號分隔.
spring.thymeleaf.mode
**指定模板的模式,具體查看StandardTemplateModeHandlers,默認為: HTML5
spring.thymeleaf.mode = LEGACYHTML5
spring.thymeleaf.mode的默認值是HTML5,其實是一個很嚴格的檢查,改為LEGACYHTML5可以得到一個可能更友好親切的格式要求。
**
spring.thymeleaf.prefix
指定模板的前綴,默認為:classpath:/templates/
spring.thymeleaf.suffix
指定模板的后綴,默認為:.html
spring.thymeleaf.template-resolver-order
指定模板的解析順序,默認為第一個.
spring.thymeleaf.view-names
指定使用模板的視圖名,多個以逗號分隔.
- 編寫Controller
@Controller
public class IndexController {
@GetMapping("/index")
public ModelAndView test(ModelAndView mv) {
//視圖文件名
mv.setViewName("index");
mv.addObject("name","歡迎使用Thymeleaf!");
return mv;
}
}
- 編寫html
在src/main/resources/templates目錄下創建:index.html
<!--引入命名空間-->
<html xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>thymeleaf示例</title>
</head>
<body>
<h1>Hello thymeleaf</h1>
<h2 th:text="'名稱:'+${name}">默認值</h2>
</body>
</html>
文本需要th:text屬性來設置。我們可以在文本元素中添加默認值,這樣當Thymeleaf引擎處理失敗的時候頁面會顯示默認值。${...}是變量表達式,將括號中的變量替換為其值。
三、基礎語法
th屬性:
常用th屬性解讀
html有的屬性,Thymeleaf基本都有,而常用的屬性大概有七八個。其中th屬性執行的優先級從1~8,數字越低優先級越高。
1)th:text :設置當前元素的文本內容,相同功能的還有th:utext,兩者的區別在于前者不會轉義html標簽,后者會。優先級不高:order=7
2)th:value:設置當前元素的value值,類似修改指定屬性的還有th:src,th:href。優先級不高:order=6
3)th:each:遍歷循環元素,和th:text或th:value一起使用。注意該屬性修飾的標簽位置,詳細往后看。優先級很高:order=2
4)th:if:條件判斷,類似的還有th:unless,th:switch,th:case。優先級較高:order=3
5)th:insert:代碼塊引入,類似的還有th:replace,th:include,三者的區別較大,若使用不恰當會破壞html結構,常用于公共代碼塊提取的場景。優先級最高:order=1
6)th:fragment:定義代碼塊,方便被th:insert引用。優先級最低:order=8
7)th:object:聲明變量,一般和*{}一起配合使用,達到偷懶的效果。優先級一般:order=4
8)th:attr:修改任意屬性,實際開發中用的較少,因為有豐富的其他th屬性幫忙,類似的還有th:attrappend,th:attrprepend。優先級一般:order=5
- 變量表達式
{}" 獲取對象屬性 。例如:
<form id="userForm">
<input id="id" name="id" th:value="${user.id}"/>
<input id="username" name="username" th:value="${user.username}"/>
<input id="password" name="password" th:value="${user.password}"/>
</form>
<div th:text="hello"></div>
<div th:text="${user.username}"></div>
- 選擇變量表達式 {}
使用方法:首先通過th:object 獲取對象,然后使用th:xx = "{}"獲取對象屬性。
這種簡寫風格極為清爽,推薦大家在實際項目中使用。 例如:
<form id="userForm" th:object="${user}">
<input id="id" name="id" th:value="{id}"/>
<input id="username" name="username" th:value="{username}"/>
<input id="password" name="password" th:value="*{password}"/>
</form> - 鏈接表達式 @{}
使用方法:通過鏈接表達式@{}直接拿到應用路徑,然后拼接靜態資源路徑。例如:
<script th:src="@{/webjars/jquery/jquery.js}"></script>
<link th:href="@{/webjars/bootstrap/css/bootstrap.css}" rel="stylesheet" type="text/css">
- 片段表達式 ~{}
Thymeleaf 3.0 引入了一個新的片段表達式。形如:~{commons::footer}。
該特性十分有用(比如解決定義通用的header和footer的問題)
base.html
片段表達式是Thymeleaf的特色之一,細粒度可以達到標簽級別,這是JSP無法做到的。
片段表達式擁有三種語法:
~{ viewName } 表示引入完整頁面
~{ viewName ::selector} 表示在指定頁面尋找片段 其中selector可為片段名、jquery選擇器等
~{ ::selector} 表示在當前頁尋找
使用方法:首先通過th:fragment定制片段 ,然后通過th:replace 填寫片段路徑和片段名。例如:
<!-- /views/common/head.html-->
<head th:fragment="static">
<script th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
</head>
<!-- /views/your.html -->
<div th:replace="~{common/head::static}"></div>
在實際使用中,我們往往使用更簡潔的表達,去掉表達式外殼直接填寫片段名。例如:
<!-- your.html -->
<div th:replace="common/head::static"></div>
值得注意的是,使用替換路徑th:replace 開頭請勿添加斜杠,避免部署運行的時候出現路徑報錯。(因為默認拼接的路徑為spring.thymeleaf.prefix = classpath:/templates/)
支持兩種語法結構
推薦:~{templatename::fragmentname}
支持:~{templatename::#id}
templatename:模版名,Thymeleaf會根據模版名解析完整路徑:/resources/templates/templatename.html,要注意文件的路徑。
fragmentname:片段名,Thymeleaf通過th:fragment聲明定義代碼塊,即:th:fragment="fragmentname"
id:HTML的id選擇器,使用時要在前面加上#號,不支持class選擇器。
代碼塊表達式的使用
代碼塊表達式需要配合th屬性(th:insert,th:replace,th:include)一起使用。
th:insert:將代碼塊片段整個插入到使用了th:insert的HTML標簽中,
th:replace:將代碼塊片段整個替換使用了th:replace的HTML標簽中,
th:include:將代碼塊片段包含的內容插入到使用了th:include的HTML標簽中,
用一個官方例子來區分三者的不同,第三部分會通過實戰再次用到該知識。
<!--th:fragment定義代碼塊標識-->
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--三種不同的引入方式-->
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
<!--th:insert是在div中插入代碼塊,即多了一層div-->
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<!--th:replace是將代碼塊代替當前div,其html結構和之前一致-->
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--th:include是將代碼塊footer的內容插入到div中,即少了一層footer-->
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
- 消息表達式
即通常的國際化屬性:#{msg} 用于獲取國際化語言翻譯值。例如:
<title th:text="#{user.title}"></title>
- 其它表達式
在基礎語法中,默認支持字符串連接、數學運算、布爾邏輯和三目運算等。例如:
<input name="name" th:value="${'I am '+(user.name!=null?user.name:'NoBody')}"/>
- 注釋
Thymeleaf 注釋:
1、<!--/* This code will be removed at Thymeleaf parsing time! */-->
2、<!--/*-->
<div>
you can see me only before Thymeleaf processes me!
</div>
<!--*/-->
3、<!--/*/
<div th:text="${...}">
...
</div>
/*/-->
四、迭代循環
想要遍歷List集合很簡單,配合th:each 即可快速完成迭代。例如遍歷用戶列表:
<div th:each="user:${userList}">
賬號:<input th:value="${user.username}"/>
密碼:<input th:value="${user.password}"/>
</div>
在集合的迭代過程還可以獲取狀態變量,只需在變量后面指定狀態變量名即可,狀態變量可用于獲取集合的下標/序號、總數、是否為單數/偶數行、是否為第一個/最后一個。例如:
<div th:each="user,stat:${userList}" th:class="${stat.even}?'even':'odd'">
下標:<input th:value="${stat.index}"/>
序號:<input th:value="${stat.count}"/>
賬號:<input th:value="${user.username}"/>
密碼:<input th:value="${user.password}"/>
</div>
如果缺省狀態變量名,則迭代器會默認幫我們生成以變量名開頭的狀態變量 xxStat, 例如:
<div th:each="user:${userList}" th:class="${userStat.even}?'even':'odd'">
下標:<input th:value="${userStat.index}"/>
序號:<input th:value="${userStat.count}"/>
賬號:<input th:value="${user.username}"/>
密碼:<input th:value="${user.password}"/>
</div>
th:remove
th:remove的值如下:
1.all:刪除包含標簽和所有的孩子。
2.body:不包含標記刪除,但刪除其所有的孩子。
3.tag:包含標記的刪除,但不刪除它的孩子。
4.all-but-first:刪除所有包含標簽的孩子,除了第一個。
5.none:什么也不做。這個值是有用的動態評估。
五、條件判斷
條件判斷通常用于動態頁面的初始化,例如:
<div th:if="${userList}">
<div>的確存在..</div>
</div>
如果想取反則使用unless 例如:
<div th:unless="${userList}">
<div>不存在..</div>
</div>
六、日期格式化
使用默認的日期格式(toString方法) 并不是我們預期的格式:Mon Dec 03 23:16:50 CST 2018
<input type="text" th:value="${user.createTime}"/>
此時可以通過時間工具類#dates來對日期進行格式化:2018-12-03 23:16:50
<input type="text" th:value="${#dates.format(user.createTime,'yyyy-MM-dd HH:mm:ss')}"/>
七、內聯寫法
(1)為什么要使用內聯寫法?·答:因為 JS無法獲取服務端返回的變量。
(2)如何使用內聯表達式?答:標準格式為:[[${xx}]] ,可以讀取服務端變量,也可以調用內置對象的方法。例如獲取用戶變量和應用路徑:
<script th:inline="javascript">
var user = [[${user}]];`
var APP_PATH = [[${#request.getContextPath()}]];
var LANG_COUNTRY = [[${#locale.getLanguage()+'_'+#locale.getCountry()}]];
</script>
(3)標簽引入的JS里面能使用內聯表達式嗎?答:不能!內聯表達式僅在頁面生效,因為Thymeleaf只負責解析一級視圖,不能識別外部標簽JS里面的表達式。
八、七大基礎對象:
${#ctx} 上下文對象,可用于獲取其它內置對象。
${#vars}: 上下文變量。
${#locale}:上下文區域設置。
${#request}: HttpServletRequest對象。
${#response}: HttpServletResponse對象。
${#session}: HttpSession對象。
${#servletContext}: ServletContext對象。
常用的工具類:
#strings:字符串工具類
#lists:List 工具類
#arrays:數組工具類
#sets:Set 工具類
#maps:常用Map方法。
#objects:一般對象類,通常用來判斷非空
#bools:常用的布爾方法。
#execInfo:獲取頁面模板的處理信息。
#messages:在變量表達式中獲取外部消息的方法,與使用#{...}語法獲取的方法相同。
#uris:轉義部分URL / URI的方法。
#conversions:用于執行已配置的轉換服務的方法。
#dates:時間操作和時間格式化等。
#calendars:用于更復雜時間的格式化。
#numbers:格式化數字對象的方法。
#aggregates:在數組或集合上創建聚合的方法。
#ids:處理可能重復的id屬性的方法。
九、常見問題
-
去掉IDE thymeleaf Html顯示紅色波浪線
打開IDE的file->setting->左上角搜索inspections,然后在右邊的搜索欄輸入thy,就會顯示如下頁面,將Expression variables validation的√去掉,然后點擊確定。
紅色波浪線 - 日期格式處理
添加:
@Column
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date createtime;
顯示:
//java代碼:
@GetMapping("/index")
public String test(Model model) {
model.addAttribute("date",new Date());
//視圖文件名
return "index";
}
//H5界面
<span th:text="${#dates.format(date, 'yyyy-MM-dd')}">2018-05-06</span>
或者
<span th:text="${#dates.format(date,'yyyy-MM-dd HH:mm:ss')}">2019-05-06 00:00:00</span>