服務器渲染技術-Thymeleaf
1.基本介紹
官方在線檔案:Read online 檔案下載:Thymeleaf 3.1 PDF, EPUB, MOBI
Thymeleaf 是什么
-
Thymeleaf是一個現代的服務器端Java模板引擎,適用于Web和獨立環境,能夠處理HTML,XML,JavaScript,CSS甚至純文本
-
Thymeleaf 是一個跟 Velocity、FreeMarker 類似的模板引擎,可完全替代 JSP
-
Thymeleaf 是一個 Java 類別庫,是一個xml/ xhtml/ html5的模板引擎,可以作為 mvc 的 web 應用的 view 層
Thymeleaf 的優點
- 實作 JSTL、OGNL 運算式效果,語法類似,上手快
- Thymeleaf 模板頁面無需服務器渲染,也可以被瀏覽器運行,頁面簡潔
- SpringBoot 支持 FreeMarker、Thymeleaf、Veocity
Thymeleaf 的缺點
- Thymeleaf 并不是一個高性能的引擎,適用于單體應用
- 如果要做一個高并發的應用,選擇前后分離更好,比如 Vue + SpringBoot
2.Thymeleaf機制
Thymeleaf 是服務器渲染技術,頁面資料是在服務端進行渲染的
例如:某個頁面被請求,其中有一段Thymeleaf代碼,則 thymeleaf 模板引擎完成處理之后(在服務端完成),才會將頁面結果回傳,因此使用Thymeleaf,并不是前后端分離,
3.語法
3.1運算式
1.運算式一覽
運算式名稱 | 語法 | 用途 |
---|---|---|
變數取值 | ${...} |
獲取請求域、session域、物件等值 |
選擇變數 | *{...} |
獲取背景關系物件值 |
訊息 | #{...} |
獲取國際化等值 |
鏈接 | @{...} |
生成鏈接 |
片段運算式 | ~{...} |
jsp:include 作用,引入公共頁面片段 |
2.字面量
文本值:'jack', 'hello', ...
數字:10, 5, 36.8, ...
布林值:true,false
空值:null
變數:name, age, ...(變數名不能有空格)
3.文本操作
字串拼接:+
變數替換:|age=${age}|
3.2運算子
1.數學運算
運算子:+,-,*,/,%
2.布爾運算
運算子:and,or
一元運算:!,not
3.比較運算
比較:>,<,>=,<=(gt,lt,ge,le)
等式:==,!=(eq,ne)
4.條件運算
If-then:(if)?(then)
If-then-else:(if)?(then):(else)
Default:(value)?:(defaultvalue)
3.3th屬性
html有的屬性,Thymeleaf基本都有,而常用的屬性大概有七八個,其中th屬性執行的優先級從1~8,數字越小優先級越高,
-
th:fragment
宣告代碼塊,方便被 th:insert 參考,優先級為 order=8
-
th:text
設定當前元素的文本內容,相同功能的還有 th:utext,兩者的區別在于前者不會轉義 html 標簽,而后者會,優先級為 order=7
-
th:value
設定當前元素的 value 值,類似修改指定屬性的還有 th:src,th:href,優先級為 order=6
-
th:attr
修改任意屬性,實際開發中使用較少,因為有豐富的其他th屬性幫忙,類似的還有th:attrappend,th:attrprepend,優先級為 order=5
-
th:object
宣告變數,一般和 *{} 一起配合使用,達到偷懶效果,優先級 order=4
-
th:if
條件判斷,類似的還有 th:unless,th:switch,th:case,優先級為 order=3
-
th:each
遍歷回圈元素,和 th:text 或 th:value 一起使用,注意該屬性修飾的標簽位置,優先級為 order=2
-
th:insert
代碼塊引入,類似的還有 th:replace,th:include,三者的區別較大,若使用不當會破壞html結構,當用于公共代碼塊提取的場景,優先級為 order=1
3.4迭代
教程:使用百里香葉 (thymeleaf.org)
在前端頁面中,總是出現需要遍歷集合中的元素以展示所有資訊的場景,Thymeleaf標準方言為我們提供了一個有用的屬性:th:each,
假設后臺控制器添加了一個商品串列的屬性 prods,然后,我們使用 th:each 在模板中使用來遍歷產品串列:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Good Thymes Virtual Grocery</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="https://www.cnblogs.com/css/gtvg.css" th:href="https://www.cnblogs.com/liyuelian/p/@{/css/gtvg.css}" />
</head>
<body>
<h1>Product list</h1>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
</tr>
<tr th:each="prod : ${prods}">
<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>
</table>
<p>
<a href="https://www.cnblogs.com/liyuelian/home.html" th:href="https://www.cnblogs.com/liyuelian/p/@{/}">Return to home</a>
</p>
</body>
</html>
prod : ${prods} 屬性的含義為:回圈 \({prods} 屬性的每一個元素,\){prods} 為被迭代變數,prod 為迭代變數,即當前回圈的元素,
需要注意的是,prod 為迭代變數的作用域為 <tr>
元素,可用于其內部標記 <td>
,
3.5條件運算
例如:
<a href="https://www.cnblogs.com/liyuelian/p/comments.html"
th:href="https://www.cnblogs.com/liyuelian/p/@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
這將創建一個指向評論頁面(帶有 URL )的鏈接,并將引數設定為產品的引數,但前提是產品有任何評論,/product/comments
prodId
id
還有一種方法可以使用 Java 中的等效開關結構有條件地顯示內容:switch-case-default
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
3.6注意事項
- 使用Thymeleaf語法首先要宣告名稱空間:
xmlns:th="http://www.thymeleaf.org"
- 設定文本 th:text,設定input的值用 th:value,回圈輸出用 th:each,條件判斷用 th:if,插入代碼塊用 th:insert,定義代碼塊用 th:fragment,宣告變數用 th:object
- th:each 的用法需要格外注意,如果你要回圈一個div中的p標簽,則 th:each 屬性必須放在p標簽上,若你將其放在div上,回圈的將是整個div
- 變數運算式中提供了很多的內置方法,該內置方法是用#開頭,不要和#{}混淆,
4.綜合案例
- 需求:使用 SpringBoot+Thymeleaf 完成簡單的用戶登錄-串列功能,
- 如果沒有登錄就訪問管理頁面,提示非法訪問,需要登錄
- 如果登錄成功,顯示登錄名稱,以及用戶串列
- 為了簡化,這里就不連資料庫了,使用Javabean代替資料

注意:這里的thymeleaf的templates目錄不能直接訪問,是因為SpringBoot默認可以訪問的靜態資源路徑沒有templates,因此除了上面請求轉發到資源的方法外,也可以配置靜態資源的訪問路徑:
spring:
web:
resources:
static-locations: [classpath:/static/,classpath:/templates/]
或者在配置類中配置(略),
4.1代碼實作

(1)創建 SpringBoot 專案,引入基本的庫檔案
<!--匯入SpringBoot父工程-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.3</version>
</parent>
<dependencies>
<!--匯入場景啟動器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--引入thymeleaf-starter:專案會自動完成配置,相關類會自動注入容器中-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
(2)創建 login.html 和 manage.html 和靜態圖片到指定目錄(templates目錄,該目錄不能直接訪問)
login.html
<!DOCTYPE html>
<!--引入命名空間-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登錄</title>
</head>
<body bgcolor="#CED3FE">
<div style="text-align: center">
<h1>用戶登錄</h1>
<hr/>
<img src="https://img.uj5u.com/2023/03/21/343778212001523.jpg" />
<!--th:action="@{/login}"可以替換#-->
<form action="#" th:action="@{/login}" method="post">
<label style="color: red" th:text="${msg}"></label><br/>
用戶名:<input type="text" style="width: 150px" name="name"/><br/><br/>
密 碼:<input type="password" style="width: 150px" name="password"/><br/><br/>
<input type="submit" value="https://www.cnblogs.com/liyuelian/p/登錄"/>
<input type="reset" value="https://www.cnblogs.com/liyuelian/p/重新填寫"/>
</form>
</div>
</body>
</html>
manage.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>管理后臺</title>
</head>
<body bgcolor="#CED3FE">
<a href="https://www.cnblogs.com/liyuelian/p/#" th:href="https://www.cnblogs.com/liyuelian/p/@{/}">安全退出</a>
<!--行內取法,使用雙層中括號-->
歡迎您:[[${session.loginAdmin.name}]]
<hr/>
<h1>管理雇員</h1>
<div style="position: center ">
<table border="1px" cellspacing="0" bordercolor="green" style="width: 700px">
<tr bgcolor="pink">
<td>id</td>
<td>name</td>
<td>age</td>
<td>pwd</td>
<td>email</td>
</tr>
<!--回圈展示-->
<tr bgcolor="#ffc0cb" th:each="user:${users}">
<td th:text="${user.id}">a</td>
<td th:text="${user.name}">b</td>
<td th:text="${user.age}">c</td>
<td th:text="${user.password}">d</td>
<td th:text="${user.email}">e</td>
</tr>
</table>
<br/>
</div>
<hr/>
</body>
</html>
(3)Javabean
Admin.java
package com.li.thymeleaf.bean;
import lombok.Data;
/**
* @author 李
* @version 1.0
*/
@Data
public class Admin {
private String name;
private String password;
}
User.java
package com.li.thymeleaf.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 李
* @version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private Integer age;
private String password;
private String email;
}
(4)控制器Controller
IndexController
package com.li.thymeleaf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author 李
* @version 1.0
*/
@Controller
public class IndexController {
//撰寫方法,轉發到登錄頁
@GetMapping(value = https://www.cnblogs.com/liyuelian/p/{"/", "/login"})
public String login() {
//因為我們引入了starter-thymeleaf,這里會直接
//使用視圖決議到thymeleaf模板檔案下的adminLogin.html
return "adminLogin";
}
}
AdminController
package com.li.thymeleaf.controller;
import com.li.thymeleaf.bean.Admin;
import com.li.thymeleaf.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
/**
* @author 李
* @version 1.0
*/
@Controller
public class AdminController {
/**
* 回應用戶登錄請求
*
* @param admin 自定義物件引數
* @param session 將獲取的admin資訊放入session中(登錄成功)
* @param model model的資料會自動放入request域中傳給下一個頁面(登錄失敗)
* @return
*/
@PostMapping("/login")//從請求方式區分,不會沖突
public String login(Admin admin, HttpSession session, Model model) {
//驗證用戶是否合法
if (StringUtils.hasText(admin.getName()) && "666".equals(admin.getPassword())) {//合法
//將登陸用戶保存到session中
session.setAttribute("loginAdmin", admin);
//應使用重定向(用請求轉發重繪頁面會重復提交表單),這里的重定向是到mainPage方法,而不是直接到頁面,
return "redirect:manage.html";
} else {//不合法,回傳重新登錄
model.addAttribute("msg", "用戶名或密碼錯誤!");
return "adminLogin";
}
}
//處理用戶請求到manage.html
@GetMapping("/manage.html")
public String mainPage(Model model, HttpSession session) {
//先校驗(這里暫時使用session驗證,后面可以統一使用攔截器)
Object loginAdmin = session.getAttribute("loginAdmin");
if (loginAdmin != null) {//說明登陸過
//模擬用戶資料
List<User> users = new ArrayList<>();
users.add(new User(1, "關羽", 555, "1234", "[email protected]"));
users.add(new User(2, "張飛", 455, "12345", "[email protected]"));
users.add(new User(3, "趙云", 344, "12346", "[email protected]"));
users.add(new User(4, "馬超", 300, "12347", "[email protected]"));
users.add(new User(5, "黃忠", 666, "12348", "[email protected]"));
//放入到request域中(model中的資料會自動放入到request域中)
model.addAttribute("users", users);
return "manage";//這里才是真正視圖決議到 templates/manage.html
} else {//說明沒有登錄過,拒絕訪問manage頁面
model.addAttribute("msg", "你沒有登錄/請登錄!");
return "adminLogin";
}
}
}
(5)啟動類
package com.li.thymeleaf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 李
* @version 1.0
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
(6)測驗
- 未經登錄直接訪問manage.html

- 登錄測驗

4.2練習
-
把前面接收引數相關注解、自定義轉換器、處理JSON、內容協商相關代碼和案例過一遍
-
將Thymeleaf用戶管理改為妖怪串列,欄位做相應的改變,進行練習
- Monster [id,name,skill,age,salary,birth]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/547616.html
標籤:Java
上一篇:Maven 中<optional>true</optional>和<scope>provided</scope>之間的區別
下一篇:C++入門