Thymeleaf簡介
Spring官方支持的服務的渲染模板中,并不包含jsp,但是支持一些模板引擎技術,目前官方比較流行的有:Thymeleaf,Freemarker,Mustache…
Thymeleaf官方網站:https://www.thymeleaf.org/index.html

Thymeleaf是用來開發Web和獨立環境專案的現代服務器端Java模板引擎,既適用于 web 環境,也適用于獨立環境,比較適合當前的人員分工問題,其能夠處理HTML、XML、JavaScript、CSS 甚至純文本,提供了一種優雅且高度可維護的模板創建方法,可以直接在瀏覽器中正確顯示,也可以作為靜態原型方便開發團隊協作,
Thymeleaf特點:
- 動靜結合: Thymeleaf 在有網路和無網路的環境下皆可運行,即它可以讓美工在瀏覽器查看頁面的靜態效果,也可以讓程式員在服務器查看帶資料的動態頁面效果,
Thymeleaf支持 html 原型,然后在 html 標簽里增加額外的屬性來達到模板+資料的展示方式,瀏覽器解釋 html 時會忽略未定義的標簽屬性,所以 thymeleaf 的模板可以靜態地運行;當有資料回傳到頁面時,Thymeleaf 標簽會動態地替換掉靜態內容,使頁面動態顯示, - 開箱即用: Thymeleaf提供標準和spring標準兩種方言,可以直接套用模板實作JSTL、 OGNL運算式效果,避免每天套模板、改jstl、改標簽的困擾,同時開發人員也可以擴展和創建自定義的方言,
- 多方言支持: Thymeleaf 提供spring標準方言和一個與 SpringMVC 完美集成的可選模塊,可以快速的實作表單系結、屬性編輯器、國際化等功能,
- 與SpringBoot完美整合,SpringBoot提供了Thymeleaf的默認配置,并且為Thymeleaf設定了視圖決議器,我們可以像操作jsp一樣來操作Thymeleaf,代碼幾乎沒有任何區別,就是在模板語法上有區別,
環境準備
使用Spring Initializr快速創建一個工程:


勾選web和Thymeleaf的依賴:

專案結構:

pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ly</groupId>
<artifactId>thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>thymeleaf</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Thymeleaf默認會開啟頁面快取,提高頁面并發能力,但會導致我們修改頁面不會立即被展現,因此我們關閉快取,
# 關閉Thymeleaf的快取
spring:
thymeleaf:
cache:
false
另外,修改完畢頁面,需要使用快捷鍵:Ctrl + Shift + F9來重繪工程,

快速入門
我們準備一個controller,控制視圖跳轉:
@Controller
public class HelloController {
@GetMapping("hello")
public String show1(Model model){
model.addAttribute("msg", "Hello, Thymeleaf!");
return "index";
}
}
新建一個html模板:
語法說明:
Thymeleaf通過${}來獲取model中的變數,注意這不是el運算式,而是ognl運算式,但是語法非常像,不過區別在于,我們的運算式寫在一個名為:th:text的標簽屬性中,這個叫做指令
<!DOCTYPE html>
<!--把html 的名稱空間,改成:xmlns:th="http://www.thymeleaf.org" 會有語法提示-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<h1 th:text="${msg}">大家好</h1>
</body>
</html>
啟動專案,訪問頁面:

動靜結合:
Thymeleaf崇尚自然模板,意思就是模板是純正的html代碼,脫離模板引擎,在純靜態環境也可以直接運行,現在如果我們直接在html中撰寫 ${}這樣的運算式,顯然在靜態環境下就會出錯,這不符合Thymeleaf的理念,
Thymeleaf中所有的運算式都需要寫在指令中,指令是HTML5中的自定義屬性,在Thymeleaf中所有指令都是以th:開頭,因為運算式${user.name}是寫在自定義屬性中,因此在靜態環境下,運算式的內容會被當做是普通字串,瀏覽器會自動忽略這些指令,這樣就不會報錯了!
th常用標簽
| 標簽 | 作用 | 樣例 |
|---|---|---|
| th:id | 替換id | <input th:id="${user.id}"/> |
| th:text | 文本替換 | <p text:="${user.name}">name</p> |
| th:utext | 支持html的文本替換 | <p utext:="${htmlcontent}">content</p> |
| th:object | 替換物件 | <div th:object="${user}"></div> |
| th:value | 屬性賦值 | <input th:value="${user.name}" > |
| th:with | 變數賦值運算 | <div th:with="isEven=${user.age}%2==0"></div> |
| th:style | 設定樣式 | th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''" |
| th:src | 替換資源 | <script type="text/javascript" th:src="@{index.js}"></script> |
| th:onclick | 點擊事件 | th:onclick="'getCollect()'" |
| th:href | 替換超鏈接 | <a th:href="@{index.html}">url</a> |
| th:each | 迭代 | <tr th:each="student:${user}" > |
| th:if | 判斷條件 | <a th:if="${userId == collect.userId}" > |
| th:unless | 和th:if判斷相反 | <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:inline | 定義js腳本可以使用變數 | <script type="text/javascript" th:inline="javascript"> |
| th:action | 表單提交的地址 | <form action="subscribe.html" th:action="@{/subscribe}"> |
| th:remove | 洗掉某個屬性 | <tr th:remove="all"> all:洗掉所有的孩子、body:洗掉其所有的孩子,不包含標簽、tag:洗掉標簽、all-but-first:洗掉除第一個以外的所有、none:什么也不做 |
變數
新建一個物體類:User
public class User {
private String name;
private int age;
private boolean sex;
private String role;
//Get、Set
}
然后在模型中添加資料
@GetMapping("add")
public String addUser(Model model){
User user = new User();
user.setAge(21);
user.setName("<font color='red'>小明</font>");
model.addAttribute("user", user);
return "user";
}
th:text指令出于安全考慮,會把運算式讀取到的值進行處理,防止html的注入,例如,<p>你好</p>將會被格式化輸出為$lt;p$gt;你好$lt;/p$lt;,如果想要不進行格式化輸出,而是要輸出原始內容,則使用th:utext來代替.
示例:我們在頁面獲取user資料:
<h1>
歡迎您:<span th:utext="${user.name}">---</span>
</h1>
效果:

ognl運算式的語法糖:
剛才獲取變數值,我們使用的是經典的物件.屬性名方式,但有些情況下,我們的屬性名可能本身也是變數,怎么辦?ognl提供了類似js的語法方式:
例如:${user.name} 可以寫作${user['name']}
自定義變數
看下面的案例:
<h2>
<p>Name: <span th:text="${user.name}">Jack</span>.</p>
<p>Age: <span th:text="${user.age}">21</span>.</p>
</h2>
我們獲取用戶的所有資訊,分別展示,當資料量比較多的時候,頻繁的寫user.就會非常麻煩,因此,Thymeleaf提供了自定義變數來解決:
<h2 th:object="${user}">
<p>Name: <span th:text="*{name}">Jack</span>.</p>
<p>Age: <span th:text="*{age}">21</span>.</p>
</h2>
- 首先在
h2上 用th:object="${user}"獲取user的值,并且保存 - 然后,在
h2內部的任意元素上,可以通過*{屬性名}的方式,來獲取user中的屬性,這樣就省去了大量的user.前綴了
方法呼叫
ognl運算式本身就支持方法呼叫,例如:
<h2 th:object="${user}">
<p>FirstName: <span th:text="*{name.split(' ')[0]}">first</span>.</p>
<p>LastName: <span th:text="*{name.split(' ')[1]}">last</span>.</p>
</h2>
這里我們呼叫了name(是一個字串)的split方法,
Thymeleaf內置物件
Thymeleaf中提供了一些內置物件,并且在這些物件中提供了一些方法,方便我們來呼叫,獲取這些物件,需要使用#物件名來參考,
環境相關物件:
| 物件 | 作用 |
|---|---|
#ctx | 獲取Thymeleaf自己的Context物件 |
#requset | 如果是web程式,可以獲取HttpServletRequest物件 |
#response | 如果是web程式,可以獲取HttpServletReponse物件 |
#session | 如果是web程式,可以獲取HttpSession物件 |
#servletContext | 如果是web程式,可以獲取HttpServletContext物件 |
Thymeleaf提供的全域物件:
| 物件 | 作用 |
|---|---|
#dates | 處理java.util.date的工具物件 |
#calendars | 處理java.util.calendar的工具物件 |
#numbers | 用來對數字格式化的方法 |
#strings | 用來處理字串的方法 |
#bools | 用來判斷布林值的方法 |
#arrays | 用來護理陣列的方法 |
#lists | 用來處理List集合的方法 |
#sets | 用來處理set集合的方法 |
#maps | 用來處理map集合的方法 |
- 舉例
我們在環境變數中添加日期型別物件
@GetMapping("date")
public String date(Model model){
model.addAttribute("today", new Date());
return "date";
}
在頁面中處理
<p>
今天是: <span th:text="${#dates.format(today,'yyyy-MM-dd')}">2020-03-30</span>
</p>
效果:

字面值
有的時候,我們需要在指令中填寫基本型別如:字串、數值、布爾等,并不希望被Thymeleaf決議為變數,這個時候稱為字面值,
字串字面值:
使用一對'參考的內容就是字串字面值了:
<h1 th:text="'${msg}'">大家好</h1>
th:text中的${msg}并不會被認為是變數,而是一個字串:

數字字面值:
數字不需要任何特殊語法, 寫的什么就是什么,而且可以直接進行算術運算
<p>今年是 <span th:text="2021">1999</span>.</p>
<p>兩年后將會是 <span th:text="2021 + 2">2001</span>.</p>

布爾字面值:
布爾型別的字面值是true或false:
<div th:if="true">
你填的是true
</div>
這里參考了一個th:if指令,跟vue中的v-if類似
拼接
我們經常會用到普通字串與運算式拼接的情況:
<span th:text="'歡迎您:' + ${user.name} + '!'"></span>
字串字面值需要用'',拼接起來非常麻煩,Thymeleaf對此進行了簡化,使用一對|即可:
<span th:utext="|歡迎您:${user.name}!|"></span>
與上面是完全等效的,這樣就省去了字串字面值的書寫,

運算
需要注意:${}內部的是通過OGNL運算式引擎決議的,外部的才是通過Thymeleaf的引擎決議,因此運算子盡量放在${}外進行,例如: <span th:text="${user.age}+2"></span>,
算術運算:
支持的算術運算子:+ - * / %
比較運算:
支持的比較運算:>, <, >= , <= ,但是>, <不能直接使用,因為xml會決議為標簽,要使用別名,
注意 == and !=不僅可以比較數值,類似于equals的功能,
可以使用的別名:gt (>), lt (<), ge (>=), le (<=), not (!). Also eq (==), neq/ne (!=).
三元運算:
<span th:text="${user.sex} ? '男':'女'"></span>
三元運算子的三個部分:conditon ? then : else
condition:條件then:條件成立的結果else:不成立的結果
其中的每一個部分都可以是Thymeleaf中的任意運算式,有的時候,我們取一個值可能為空,這個時候需要做非空判斷,可以使用 運算式 ?: 默認值簡寫: <span th:text="${user.name} ?: '小紅' "></span>,當前面的運算式值為null時,就會使用后面的默認值, 注意:?:之間沒有空格,
回圈
回圈也是非常頻繁使用的需求,我們使用th:each指令來完成:
假如有用戶的集合:users在Context中,
<tr th:each="user : ${users}">
<td th:text="${user.name}">name</td>
<td th:text="${user.age}">age</td>
</tr>
${users}是要遍歷的集合,可以是以下型別:- Iterable,實作了Iterable介面的類
- Enumeration,列舉
- Interator,迭代器
- Map,遍歷得到的是Map.Entry
- Array,陣列及其它一切符合陣列結果的物件
在迭代的同時,我們也可以獲取迭代的狀態物件:
<tr th:each="user,stat : ${users}">
<td th:text="${user.name}">name</td>
<td th:text="${user.age}">age</td>
</tr>
stat物件包含以下屬性:
- index,從0開始的角標
- count,元素的個數,從1開始
- size,總元素個數
- current,當前遍歷到的元素
- even/odd,回傳是否為奇偶,boolean值
- first/last,回傳是否為第一或最后,boolean值
邏輯判斷
Thymeleaf中使用th:if 或者 th:unless ,兩者的意思恰好相反,
<span th:if="${user.age} < 24">小鮮肉</span>
如果運算式的值為true,則標簽會渲染到頁面,否則不進行渲染,
以下情況被認定為true:
- 運算式值為true
- 運算式值為非0數值
- 運算式值為非0字符
- 運算式值為字串,但不是
"false","no","off" - 運算式不是布爾、字串、數字、字符中的任何一種
其它情況包括null都被認定為false
分支控制switch
這里要使用兩個指令:th:switch 和 th:case
<div th:switch="${user.role}">
<p th:case="'admin'">用戶是管理員</p>
<p th:case="'manager'">用戶是經理</p>
<p th:case="*">用戶是別的玩意</p>
</div>
需要注意的是,一旦有一個th:case成立,其它的則不再判斷,與java中的switch是一樣的,
另外th:case="*"表示默認,放最后,
URL運算式
URL運算式指的是把一個有用的背景關系或回話資訊添加到URL,這個程序經常被叫做URL重寫:@{/user}
URL還可以設定引數: @{/user/find(id=${userId})}
相對路徑: @{../aaa/bbb}
案例:引入css樣式
在static目錄下新建一個app.css檔案

設定樣式:
.app{
height: 200px;
width: 200px;
background-color: darkblue;
}
代碼:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>hello</title>
<link rel="stylesheet" th:href="@{app.css}">
</head>
<body>
<div class="app"></div>
</body>
</html>
運行結果:

JS模板
模板引擎不僅可以渲染html,也可以對JS中的進行預處理,而且為了在純靜態環境下可以運行,其Thymeleaf代碼可以被注釋起來:
<script th:inline="javascript">
const user = /*[[${user}]]*/ {};
const age = /*[[${user.age}]]*/ 20;
console.log(user);
console.log(age)
</script>
行內文本:[[...]]行內文本的表示方式, 在script標簽中通過th:inline="javascript"來宣告這是要特殊處理的js腳本,th:inline可以在父級標簽內使用,甚至作為body的標簽,
語法結構:
const user = /*[[Thymeleaf運算式]]*/ "靜態環境下的默認值";
因為Thymeleaf被注釋起來,因此即便是靜態環境下, js代碼也不會報錯,而是采用運算式后面跟著的默認值,
看看頁面的原始碼:

我們的User物件被直接處理為json格式了,非常方便,
控制臺:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/271587.html
標籤:其他
上一篇:關于JS中target屬性
