Thymeleaf - 使用方法及國際化(超詳細)

Thymeleaf簡介

Thymeleaf是一個和Velocity、FreeMarker 類似的模板引擎,它在有網絡和無網絡的環境下皆可運行。因爲它支持html原型,在html的標籤裏增加了額外的屬性來達到模板+數據的展示方式。瀏覽器解釋html時會忽略未定義的標籤屬性,所以thymeleaf的模板可以靜態地運行。當有數據返回到頁面時,Thymeleaf標籤會動態地替換掉靜態內容,使頁面動態顯示。

它與SpringBoot完美結合,SpringBoot提供了Thymeleaf的默認配置,並且爲Thymeleaf設置了視圖解析器。它可以快速實現表單綁定、屬性編輯器、國際化等功能。

在SpringBoot中的配置

1、添加依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
2、創建模板文件夾

SpringBoot自動爲Thymealf註冊了一個視圖解析器ThymealfViewResolver,並且配置了模板(HTML)的位置,與JSP類似的前綴+視圖名+後綴的風格。我們可以進到它的配置文件(ThymeleafProperties)裏去看:
​​​​​​Thymeleaf配置文件
可以發現,如果我們沒有在yml中進行配置,則它去找的視圖文件默認是在resources配置文件夾下的templates文件夾裏,後綴爲.html。我們也可以在配置文件中進行配置,即圖中所標註的spring.thymeleaf下。
靜態頁面放置的位置
yml配置文件
yml配置文件

Controller層返回頁面示例

在這裏插入圖片描述

Thymeleaf在Html頁面中的基本使用

1.要在html頁面中使用thymeleaf的標籤,必須引入名稱空間。
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2.表達式的使用

在html頁面中,要使用thymealf的標籤,只需在原標籤名前加th:即可,如th:srcth:hrefth:text
${},變量表達式,它可以獲取到Controller層存入Model的值

// 後端Controller層代碼
model.addAttribute("name","柳成蔭");
User user = new User("柳成蔭",22);   // 姓名、年齡
model.addAttribute("user",user);
// html頁面中獲取並顯示
<span th:text="${name}">九月</span>
<span th:text="${user.age}">18</span>

前面說過,當有數據傳遞過來時,則動態數據會替換靜態數據。
*{},選擇變量表達式,可以省略對象名,直接獲取屬性值

<div th:object="${user}">
	<p th:text="*{name}">九月</p>
	<p th:text="*P{age}">18</p>
</div>

#{},Message表達式,它主要是從國際化配置文件中取值,這裏暫不做示例,文章後面將會示例從國際化配置文件中取值。

3、URL的使用

①絕對網址,絕對URL用於創建到其他服務器的鏈接,需要指定協議名稱http或者https,如:

<a th:href="@{https://www.baidu.com}">百度</a>

②上下文相關URL,即與項目根相關聯的URL,這裏假設我們的war包爲app.war,且沒有在tomcat的server.xml配置項目的路徑(Context),則在Tomcat啓動之後,就會在webapps文件下產生一個app文件夾,此時app就是上下文路徑(Context)

<!-- 在頁面這樣寫 -->
<a th:href="@{/blog/search}">跳轉</a>
<!-- Thymeleaf解析之後是這樣的 -->
<a href="/app/blog/search">跳轉</a>

③服務器相關URL,它與上下文路徑很相似,它主要用於一個Tomcat下運行有多個項目的情況。比如說我們當前項目爲app,如果tomcat還運行着一個otherApp,我們就可以通過該方法訪問otherApp的請求路徑。

<!-- 在頁面這樣寫 -->
<a th:href="@{~/otherApp/blog/search}">跳轉</a>
<!-- Thymeleaf解析之後是這樣的 -->
<a href="/otherApp/blog/search">跳轉</a>

④有時候我們需要頁面帶參數傳遞到後端,則可以使用下面這個方法

<!-- 在頁面這樣寫 -->
<a th:href="@{/blog/search(id=3,blogName='Java')}" >跳轉</a>
<!-- Thymeleaf解析之後是這樣的,這裏忽略項目路徑 -->
<a href="/blog/search?id=3&blogName=Java" >跳轉</a>

<!-- 還可以這樣寫,實現restful風格的效果 -->
<a th:href="/blog/{id}/search(id=3&blogName=Java)">跳轉</a>
<!-- Thymeleaf解析之後是這樣的,這裏忽略項目路徑 -->
<a href="/blog/3/search?blogName=java">跳轉</a>
4、字面值

有時候,我們需要在指令中填入基本類型如:字符串、數值、布爾等,不希望Thymeleaf去給我們解析,可以這樣做:
①字符串字面值

<!-- 在頁面中這樣寫 -->
<span th:text="‘Thymealf’ + 3">templates</span>
<!-- Thymeleaf解析後 -->
<span>Thymealf3</span>

②數字字面值

<!-- 在頁面中這樣寫 -->
<span th:text="1 + 3">templates</span>
<!-- Thymeleaf解析後 -->
<span>4</span>

③布爾字面值:爲true和false

5、拼接

傳統拼接需要用''來進行普通字符串和表達式的拼接,Thymeleaf中進行了簡化,只需將拼接的內容塊使用||包裹即可:

<span th:text="|歡迎您,${user.name}|">九月</span>
6、運算符

①因爲html裏會將<>符號進行解析,所以不能直接使用,但是如果在{}內使用,是不需要轉換的

>	      gt    即greater than,大於
<         lt    即less than,小於
>=        ge    即greater equal,大於等於
<=        le    即less equal,小於等於

②三元運算符

<span th:text="${false} ? '' : ''">性別</span>
<>

③空值判斷

<!-- 如果user.name爲空,則顯示 空值顯示 這幾個字 -->
<span th:text="${user.name} ?: ‘空值顯示’"></span>
7、內聯寫法

[()],解析輸出,會解析內容裏的html標籤

<span>[(${user.name})]</span>

[[]],原樣輸出,不會解析內容裏的html標籤

<span>[[${user.name}]]</span>
8、局部變量

可以將後端傳來的數據賦值給一個局部變量,這個局部變量只能在標籤內部使用,外部是不可以的

<div th:with="user=${userList[0]}">
	<span th:text="${user.name}">暱稱</span>
</div>
9、判斷

th:if,滿足條件才顯示標籤包裹的(含標籤)的內容

<span th:if="${true}">顯示</span>
<span th:if="${user.age == 18}">18歲顯示</span>

th:unless,與th:if相反,不滿足條件時顯示

<span th:unless='${true}'>不顯示</span>

th:switch,switch的效果一致

<div th:witch="${user.name}">
	<span th:case="柳成蔭">柳成蔭</span>
	<span th:case="九月">九月</span>
	<span th:case="尋寶">尋寶</span>
</div>
10、迭代

th:each,迭代一個集合/數組,可以使用它的內置對象stat獲取更多的信息。
先列出內置對象stat的用法:

index:角標,從0開始
count:元素的個數,從1開始,當前遍歷到第幾個
size:元素的總個數
current:當前遍歷到的元素
even/odd:是否爲奇/偶,都是返回true或false的布爾結果
first/last:是否第一/最後,都是返回true或false的布爾結果

使用th:each

<tr th:each="user:${userList}">
	<td th:text="${user.name}"></td>
	<td th:text="|當前迭代到第${stat.count}個了|"></td>
</tr>
11、環境相關對象

1、${#ctx}:上下文對象,可用於獲取其他內置對象
2、${#vars}:上下文變量。
3、${#locale}:上下文區域設置。
4、${#request}:HttpServletRequest對象。
5、${#response}:HttpServletResponse對象。
6、${#session}:HttpSession對象。
7、${#servletContext}:ServletContext對象。
具體怎麼使用,可以自行百度,這裏以session爲例:

<span th:text="${session.user.name}">存儲在session的User對象</span>
12、全局對象功能

1、#strings:字符串工具類
2、#lists:List 工具類
3、#arrays:數組工具類
4、#sets:Set 工具類
5、#maps:常用Map方法。
6、#objects:一般對象類,通常用來判斷非空
7、#bools:常用的布爾方法。
8、#execInfo:獲取頁面模板的處理信息。
9、#messages:在變量表達式中獲取外部消息的方法,與使用#{…}語法獲取的方法相同。
10、#uris:轉義部分URL / URI的方法。
11、#conversions:用於執行已配置的轉換服務的方法。
12、#dates:時間操作和時間格式化等。
13、#calendars:用於更復雜時間的格式化。
14、#numbers:格式化數字對象的方法。
15、#aggregates:在數組或集合上創建聚合的方法。
16、#ids:處理可能重複的id屬性的方法。
具體怎麼使用,可以自行百度,這裏僅以#dates爲例,格式化時間:

<span th:text="${#dates.format(blog.updateTime)},'yyyy-MM-dd HH:mm:ss'"></span>
13、class屬性增加

使用th:classappend,可以增加class元素類名。通常用在如導航欄上,當導航欄上某個標籤被選中,它會與其他沒有被選中的有不同的樣式。

<a class="item m-mobile-hide’ th:classappend='${n==1} ? ‘active’">首頁</a>
<!-- 如果n==1成立,則解析如下 -->
<a class="item m-mobile-hide active’">首頁</a>

Thymeleaf在Html頁面中的佈局使用

定義片段引入片段是非常好的功能,在一個項目中的各個頁面裏,通常他們大部分導航欄和底部是相同的。我們可以創建一個頁面專門用來定義重複使用片段,然後在其他頁面做引入。

1、定義片段

①使用th:fragment定義通用片段 - 普通片段

<nav th:fragment="header">
	<a href="#">首頁</a>
	<a href="#">分類</a>
</nav>

②使用th:fragment定義通用片段 - 帶參片段
如下代碼,如果我們當前是在首頁,則首頁這個標籤就會多一個樣式,而分類就沒有。我們只需要在引入這塊片段的代碼裏傳遞一個參數過來進行判斷即可。

<nav th:fragment="header(n)">
	<a class="item’ th:classappend='${n==1} ? ‘active’">首頁</a>
	<a class="item’ th:classappend='${n==2} ? ‘active’">分類</a>
</nav>

③使用id來定義片段 - 不推薦

<nav id="header">
	<a href="#">首頁</a>
	<a href="#">分類</a>
</nav>
2、引入片段 - 下文中的_fragment爲定義片段的html頁面

①將公共的標籤插入到指定標籤中 - 該方法不可以省略~{}

<div th:insert="~{_fragment::header}">
	<!-- 被引入的片段會插入到div標籤內部 -->
</div>

②將公共的標籤替換指定的標籤 - 該方法可以省略~{}
推薦使用該引入方式,這樣做,可以保證在沒有網絡(動態數據)的情況下,其他頁面也有內容可以顯示。

<!-- 被引入的片段會替換div標籤的內容(含div) -->
<div th:replace="~{_fragment::header}">
	<a href="#">鏈接</a>
</div>

③將公共的標籤包含到指定的標籤 - 該方法可以省略~{}

<div th:include="~{_fragment::header}">
	<!-- 
		被引入的片段會被包含到div標籤內部
		但是最外層的標籤不會被包含進來,即只包含th:fragment所在標籤內部的內容
	-->
</div>

④上訴三種方法,可以用來引入使用id定義片段的 - 不推薦

<nav th:insert="~{_fragment::#header}">
	<!-- 不推薦id定義片段和引入這種片段 -->
</nav>

⑤引入帶參片段 - 重要

<nav th:replace="header(2)">
	<a class="item’ th:classappend='${n==1} ? ‘active’">首頁</a>
	<a class="item’ th:classappend='${n==2} ? ‘active’">分類</a>
</nav>
3、th:fragment更新數據

很多時候,在頁面裏我們需要使用Ajax異步請求數據,我們希望只更新某一塊的數據,其他地方不變。這時,就需要th:fragment來做了,文章前面有提到return "index :: blogList"這種方式,它就是配合th:fragment來做的。

<!-- 其他代碼 -->
<div th:fragment="userInfo">
	<span th:text="${user.name}">九月</span>
	<span th:text="${user.age}">18</span>
</div>
<!-- 其他代碼 -->
public String userInfo(Model model){
	model.addAttribute(user,new User("柳成蔭",22));
	return "index :: userInfo";
}

th:fragmentth:replace是用在合適的地方非常好用,常見的css塊、js塊、導航欄、底部區域。

4、塊級標籤th:block

th:block是thymeleaf提供的塊級標籤,其特殊性在於Thymeleaf模板引擎在處理<th:block>的時候會刪掉它本身,標籤本身不顯示,而保留其內容
①常見用法 - HTML部分

<!-- 控制幾個標籤是否一起顯示/不顯示 -->
<th:block th:if="...">
	<div id="div1">我和div2一起</div>
	<div id="div2">我和div1一起</div>
</th:block>
<!-- 循環統計標籤 -->
<table>
	<th:block th:each="...">
		<tr>...</tr>
		<tr>...</tr>
	</th:block>
</table>

②常見用法 - JS部分
有時候js的引入可能也是其他頁面公有的,我們想定義一個js片段,然後在其他頁面引入。可以使用<div>js片段包裹起來,然後將這個<div>定義成一個片段,但這種做法並不好。這時就用到了th:block

<!-- JS公用部分 - 定義片段 -->
<th:block th:fragment="script">
    <script src="../static/js/jquery-3.3.1.min.js" th:src="@{/js/jquery-3.3.1.min.js}"></script>
    <script src="../static/js/semantic.min.js" th:src="@{/js/semantic.min.js}"></script>
</th:block>
<th:block th:replace="_fragment::script">
	<!-- 這樣就解決了JS共用的問題了 -->
	<script src="../static/js/jquery-3.3.1.min.js"></script>
</th:block>

可能有人會問,這個th:block會不會影響靜態頁面?實際上,它是不會影響靜態頁面的。如果你實在是擔心,我們可以用可以使用下面這種方法

<!--/*/<th:block th:replace="_fragments :: script">/*/-->
	<!-- 這樣就解決了JS共用的問題了 -->
	<script src="../static/js/jquery-3.3.1.min.js"></script>
<!--/*/<th:block th:replace="_fragments :: script">/*/-->

註釋的使用

可以看到,上面我們使用了<!-- -->的方式將th:block註釋掉了,但是你也發現,我們在裏面使用了/*/ /*/來包裹了標籤。它是thymeleaf註釋的一種,它在運行時,就不會把上面那些註釋了的代碼看做是註釋,而是當做正常的處理。
/*是另外一種,它的作用就是thymeleaf運行時,把包裹起來的內容註釋掉。
/*/註釋

<!-- 下面這行代碼再靜態頁面中確實是被註釋了,但是動態運行時,則不會被註釋 -->
<!--/*/<th:block th:replace="_fragments :: script">/*/-->

/*註釋

<!--
    下面的註釋在靜態頁面的確註釋了,但是請注意,它註釋的是/*和*/ 
	而動態運行時,被/*和*/包裹的都要被註釋掉
	這樣做的目的是保證靜態運行時可以看到靜態效果,動態運行時看到動態效果
-->
<div>
	<span th:each="blog:${blogList}" th:text="${blog.name}">博客1</span>
	<!-- /* -->
	<span th:each="blog:${blogList}">博客2</span>
	<span th:each="blog:${blogList}">博客3</span>
	<span th:each="blog:${blogList}">博客4</span>
	<!-- */ -->
</div>

JS模板預處理

模板引擎不僅可以渲染html,也可以對JS中的進行預處理。而且爲了在純靜態環境下可以運行。在script標籤中通過th:inline="javascript"來聲明這是要特殊處理的js腳本。

<script th:inline="javascript">
	var username = /*[[${user.name}]]*/ ‘默認’;
	var age = /*[[${user.age}]]*/18;
	console.log(username);
	console.log(age);
</script>

國際化

在SpringBoot項目裏面做國際化,只需要在resources/i18n路徑下創建xxx.propertiesxxx_en_US.propertiesxxx_zh_CN.properties即可。具體怎麼做,將在下文進行演示。
在SpringBoot中有一個messageSourceAutoConfiguration,它會自動管理國際化資源文件。
messageSourceAutoConfiguration
也就是說,我們在resources/i18n創建的國際化配置文件前綴名爲message時,SpringBoot會自動加載。
MessageSourceProperties
當然,我們也可以自己定義國際化文件名稱,這裏我們將國際化配置文件命名爲login
1、去yml配置文件中配置國際化

spring
  messages: i18n.login

2、要確保文件編碼是UTF-8,可以到idea的設置裏去設置並讓其自動轉換,Editor->File Encodings
文件編碼
3、創建i18n文件夾及3個國際化配置文件,如圖
其中login.properties是基礎配置文件(默認),如果你的瀏覽器它是其他語言比如法語,是沒有辦法國際化的,所以它就會採用login.properties
國際化配置文件
在idea裏只要創建兩個國際化的配置文件就會自動加入到Resource Bundle 'xxx',當然我們還是需要創建三個properties配置文件。後綴必須按格式寫,_en_US就是英文,_zh_CN就是中文。
4、編寫國際化
我們直接點進login.properties,可以看到下方有個切換到Resource Bundle的按鈕,點擊切換,添加國際化,然後分別在右側寫上對應國際化語言
國際化
想添加多少,就可以添加多少。
5、可以在Thymeleaf頁面進行獲取了,用到前面所說的#{}

<button type="submit" th:text="#{login.btn}"></button>

6、一般來說我們在頁面會做個切換中英文的按鈕來進行切換

<a th:href="@{/login(lan='zn_CN')}">中文</a>
<a th:href="@{/login(lan='en_US')}">英文</a>

7、做完上訴步驟,我們還需要編寫一個本地解析器來進行解析

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        // 接收語言的參數 - 傳進來的就是形如'zh_CN'這樣的參數
        String lan = request.getParameter("lan");
        // 使用默認的語言 - 在文中就是login.properties文件裏配置的
        Locale locale = Locale.getDefault();
        // 判斷接收的參數是否爲空,不爲空就設置爲該語言
        if(!StringUtils.isEmpty(lan)){
            // 將參數分隔 - 假設傳進來的是'zh_CN'
            String[] s = lan.split("_");
            // 語言編碼:zh   地區編碼:CN
            locale = new Locale(s[0],s[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

8、我們還需要寫一個配置文件來表明國際化解析器是用的我們自己寫的

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
	@Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

國際化就這樣完成了,通過上面定義的切換語言按鈕就可以切換了。

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