興趣的朋友可以去了解一下前四篇,你的贊就是對我最大的支持,感謝大家!
(一) SpringBoot起飛之路-HelloWorld
(二) SpringBoot起飛之路-入門原理分析
(三) SpringBoot起飛之路-YAML配置小結(入門必知必會)
(四) SpringBoot起飛之路-靜態資源處理
說明:
- 太忙啦,同時全放到一起,后來感覺移動端篇幅太長,閱讀體驗太差了,就打算分成幾篇來發
- 才疏學淺,就會點淺薄的知識,大家權當一篇工具文來看啦,不喜勿憤哈 ~
(一) 模板引擎引入
(1) 開發方式
在往常的開發中,一旦涉及到一個完整的前后端項目,有兩種辦法:
-
一種就是前后端分離,也就是說,約定好接口,通過異步方式,以 Json 字符串作為內容傳遞,后台進行一些業務邏輯,前台負責界面,以及通過 js 等進行數據的處理以及頁面的美化。
-
還有一種方式就是模板引擎的方式,這種方式也沒什么太新奇的,你可以簡單的理解為 JSP 的那種模式
現在來說,前后端分離開始更加流行,但是很多舊的項目,或者自己一個人寫東西,我感覺使用模板引擎也是非常不錯的選擇,還有時候去找一些后台的開源模板,有一些也都用了Thymeleaf, 何況出於學習的態度,學哪種技術都是可以的
針對第二種方式繼續說一下,JSP 大家應該是熟悉的,比如前端傳來一個 html 的頁面,我們就會去將這個頁面改寫為 JSP 頁面,我們可以用 JSP 比較容易的實現數據的顯示,那么為什么不繼續用 JSP 而要用別的模板引擎呢?
注:Thymeleaf 和 Freemarker 等各有特點,用熟悉后,可能會對另一種的使用方式感覺很別扭,沒必要爭論哪種更好,自己喜歡就行
(2) 為什么用模板引擎
以 Springboot 來說,官方就不推薦使用 JSP ,來看一下官方的解釋
Springboot 2.2.7
地址:https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/reference/html/spring-boot-features.html#boot-features-jsp-limitations
Springboot:7.1.10. Template Engines
As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. Spring MVC supports a variety of templating technologies, including Thymeleaf, FreeMarker, and JSPs. Also, many other templating engines include their own Spring MVC integrations.
Spring Boot includes auto-configuration support for the following templating engines:
FreeMarker、Groovy、Thymeleaf、Mustache
If possible, JSPs should be avoided. There are several known limitations when using them with embedded servlet containers.
上面一段話,總的來說,就是告訴我們,如果我們想要動態的展示HTML內容,就可以用一些模板的技術,例如 FreeMarker、Groovy、Thymeleaf、Mustache
最后有一句話說道點子上了,Springboot 建議我們盡可能的規避 JSP,並且提供了一些說法
Springboot:7.4.5. JSP Limitations
When running a Spring Boot application that uses an embedded servlet container (and is packaged as an executable archive), there are some limitations in the JSP support.
-
With Jetty and Tomcat, it should work if you use war packaging. An executable war will work when launched with java -jar, and will also be deployable to any standard container. JSPs are not supported when using an executable jar.
-
Undertow does not support JSPs.
-
Creating a custom error.jsp page does not override the default view for error handling. Custom error pages should be used instead.
第二點是說,Undertow 支持 JSP,而第三點,則是關於error錯誤頁面的覆蓋問題
前兩點都不是我想說的,我們主要看第一點:當你把一個使用了 JSP 的項目打 war 包放到了 tomcat 或者其他容器中是可以運行的,當然你使用 java -jar 也是可以運行的,但是如果你直接執行 jar 包是不可以的
也就是說,打包的類型決定了JSP可不可以被正常解析使用,同時 SpringBoot 中 Tomcat 是嵌入式的,而 SpringBoot 程序往往又是脫離容器獨立運行的,如果用 JSP ,就需要額外的地址去存生成的 Servlet ,可能會存在一定的安全問題,所默認是不支持jsp的
(3) SpringBoot推薦Thymeleaf嗎?
網絡上的文章都在傳,SpringBoot 官方推薦 Thymeleaf,我看了一下 SpringBoot 2.2.7 版本的文檔(看了下貌似2.3.0也掛成GA了,這部分沒啥改變)我自己是沒找到一個關於推薦確切的說法
Springboot:7.1.10. Template Engines
- 在Springboot——Spring Boot Features —— 7.1.10. Template Engines 中有提到,SpringBoot 提供了關於Thymeleaf 的自動裝配的支持,但是同樣的也提供對 FreeMarker、Groovy、Mustache 自動裝配的支持,此處並沒有看到推薦某一款的說法
SpringMVC:1.10.1. Thymeleaf
Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML templates that can be previewed in a browser by double-clicking, which is very helpful for independent work on UI templates (for example, by a designer) without the need for a running server. If you want to replace JSPs, Thymeleaf offers one of the most extensive set of features to make such a transition easier. Thymeleaf is actively developed and maintained. For a more complete introduction, see the Thymeleaf project home page.
SpringMVC:1.10.2. FreeMarker
Apache FreeMarker is a template engine for generating any kind of text output from HTML to email and others. The Spring Framework has built-in integration for using Spring MVC with FreeMarker templates.
- 再看一下 SpringMVC 5.2.6.RELEASE 的文檔,關於模板也沒有提到支持或者推薦,而對於幾種常見的例如 Thymeleaf、FreeMarker 等作出了一定的說明
所以,我個人覺得,SpringBoot 也只是提供了幾種替代 JSP 的方案,並沒有指定的推薦什么,當然了如果是我自己沒注意到,大家也可以留言和我交流分享啊哈~
(4) 此部分小結
說了一大堆,就一個結論,SpringBoot 中不推薦 JSP 是肯定的,但是也沒有指定推薦什么引擎模板,大家可以根據需要自行選擇(FreeMarker、Groovy、Thymeleaf、Mustache)
(二) JSP 真的有點麻煩
如果,你真的想要在 SpringBoot 中使用 JSP,通過一些額外的配置,也是可以的,一起感受一下
(1) 導入依賴
初始化的時候,我選了基本的 web 還涉及到熱部署的 devtools ,簡單體驗一下只勾選 web 也成
spring-boot-starter-web,已經內置了,spring-boot-starter-tomcat,其下有tomcat-embed-core、tomcat-embed-el 等,前者包含servlet-api和內置 servlet 容器,后者為el表達式包,所以我們體驗的時候,只需要引入 jstl 以及與編譯jsp相關的 tomcat-embed-jasper 就可以了
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</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>
<!-- jsp begin-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- jsp end-->
</dependencies>
(2) 編寫后台代碼
實體類
首先創建一個 User實體,簡單寫三個成員
public class User {
private String username;
private Integer age;
private String address;
...... get set toString 方法
}
控制層
這段代碼夠淺顯了,返回這個 List 前台遍歷就行了
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/list")
public String list(Model model) {
System.out.println("查詢所有");
User u1 = new User();
u1.setUsername("Steven");
u1.setAge(20);
u1.setAddress("北京");
User u2 = new User();
u2.setUsername("Jack");
u2.setAge(30);
u2.setAddress("上海");
List<User> users = new ArrayList<User>();
users.add(u1);
users.add(u2);
model.addAttribute("users", users);
return "list";
}
}
(3) 編寫 JSP
首先在 main 文件夾下,創建webapp文件夾,其下創建 WEB-INF 文件夾用來存放jsp文件(我在其下又多創建了一個pages文件夾,看個人習慣就可),而靜態文件夾仍然放在resources下的靜態資源文件夾例如 static public 等
位置:src/main/webapp/WEB-INF/pages/list.jsp
下面也就是一個遍歷到表格的 Demo
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list all</title>
</head>
<body>
<table border="1">
<c:forEach items="${users}" var="user">
<tr>
<td>${user.username}</td>
<td>${user.age}</td>
<td>${user.address}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
(4) 修改配置
上面做完了,如果不配置的話,這些頁面根本是找不到的,所以需要配置 JSP 映射路徑和后綴
spring.mvc.view.prefix=/WEB-INF/pages/
spring.mvc.view.suffix=.jsp
(5) 測試
直接運行啟動類訪問
可以訪問得到
打成 jar 運行訪問
Maven Projects --> Lifecycle --> clean --> package
我們的 JSP 頁面訪問不到了
(6) 多模塊項目404問題
主要的原因是無法找到正確的路徑,所以需要將啟動的Working directory設置為模塊工作文件夾$MODULE_WORKING_DIR$
,
設置方式:打開 Run/Dedug Configurations,然后修改
關於 JSP 我自己也沒怎么在 SpringBoot 中用過,也沒細研究過,之前看到有一個篇文章有總結過關於 JSP 的坑,大家有興趣或許可以了解一下
https://juejin.im/post/5ad21eb5f265da23945feb62
(三) 來試試 Thymeleaf
(1) 簡單評價
A:優點
首先,配置很簡單,SpringBoot 對於 Thymeleaf 在內的幾種模板引擎,都提供了自動裝配的支持,所以簡單的引入依賴就可以快速使用
其次,Thymeleaf "很優雅" ,因為綁定或者控制的時候,都是以屬性的方式,所以 HTML 的原有結構,沒有被破壞掉,這樣,就有了一個其他模板引擎所沒有的優點:可以被瀏覽器正常渲染,也就是說,直接就可以訪問(例如 JSP 是沒有辦法脫離容器直接訪問的)
B:缺點
標簽檢查很嚴格,有時候會發瘋....
表達式和標簽種類繁多 {} 花括號前面不同的符號代表不同的意思,例如 ${...}
變量表達式 、 *{...}
選擇表達式
如果習慣了 freemarker 這種類型的寫法,寫 Thymeleaf 會感覺很麻煩,因為兩者的書寫角度或者說思路是不同的
C:關於性能
關於性能,在 3.x 后 Thymeleaf 已經有了很大的提升,但是我查過一下數據,貌似仍不一定有那么理想,不過就我個人而言,我一個后端狗寫頁面,一堆亂七八糟的 js、css 各種增大開銷,Thymeleaf 帶來的一些影響,貌似與我和沒有很大關系(菜是原罪)
(2) 引入Thymeleaf
用之前,肯定得引入相關的依賴對吧,可以去 Thymeleaf 官網,或者 Springboot 的官網,這里我更加推薦后者
Thymeleaf 官網:https://www.thymeleaf.org
Springboot 官網:
官網在 2.3.0 的版本中,你現在去看還是沒有更出來Pom的,不過可以去看 2.2.7 的
Version | Name | Description | Pom |
---|---|---|---|
2.3.0 | spring-boot-starter-thymeleaf |
Starter for building MVC web applications using Thymeleaf views | 暫未提供 |
2.2.7 | spring-boot-starter-thymeleaf |
Starter for building MVC web applications using Thymeleaf views | Pom |
2.2.7 Pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
這樣引入是一種方式,但是這些相關的東西,Springboot 都已經幫我們打包好了,開箱即用
所以最終的引入方式就是:
A:Pom 增加依賴
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
B:初始化時勾選相關組件
(3) 模板頁面存放位置
引入了依賴之后,先確定一下頁面給放哪里,前面演示的 JSP 好不折騰,又是創建 webapp WEB-INF ,又是配置,而 Thymeleaf 等模板,則可以直接將頁面放到自動生成的 templates 文件夾中就可以了
具體路徑為:src -- main -- resources -- template
如果想了解一下具體原因:可以去看一下 ThymeleafProperties 這個配置類,前后綴都已經指定好了
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
// 是否在呈現模板之前檢查模板是否存在
private boolean checkTemplate = true;
// 是否檢查模板位置是否存在
private boolean checkTemplateLocation = true;
// 在構建URL時以查看名稱作為前綴
private String prefix = DEFAULT_PREFIX;
// 在構建URL時附加到視圖名稱的后綴
private String suffix = DEFAULT_SUFFIX;
// 要應用於模板的模板模式
private String mode = "HTML";
// 模板文件編碼
private Charset encoding = DEFAULT_ENCODING;
(4) 入門程序體驗
1、編寫 Controller
@Controller
public class TestController {
@RequestMapping("test")
public String test(Model model){
String hello = "Hello Thymeleaf";
model.addAttribute("hello",hello);
return "test.html";
}
}
2、編寫頁面
頁面其實可以看到就是一個普通的 html 頁面,有幾個不同的地方就是,上方引入了一個命名空間的約束,使用了 th:xxx 這樣的語法 例如,th:text,然后 ${hello}
引入了控制層帶來的 hello
接受到的數據這一行上面的注釋可以不加,不過 ${hello}
應該會報紅,不過也可以運行,具體原因看下面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<h2>測試成功</h2>
<!--/*@thymesVar id="hello" type="java.lang.String"*/-->
<p th:text="'接收到的數據: ' + ${hello}"></p>
</body>
</html>
3、測試結果
(5) 標簽報紅
<p th:text="'接收到的數據: ' + ${hello}"></p>
例如上面這么一行代碼,如果不加任何處理,${hello}
必然是要報紅的,其下會有一個紅色波浪線
原因:后端 model 中雖然添加了數據,但是由於並沒有運行程序,前端的文件也不知道,所以這個時候就會有紅色波浪線存在了,其實正常運行是沒有問題的,就是看起來很煩
解決方式有三種:
- 自動補全快捷鍵,自動寫出上面的注釋,然后自己寫入類型
<!--/*@thymesVar id="hello" type="java.lang.String"*/-->
-
<!DOCTYPE html>
下加上<!--suppress ALL-->
抑制所有警告,不過需要的每個 HTML 都得加 -
在 IDEA 中,進行一個全局的忽略
(6) Thymeleaf 特點及說明
經過了一個簡單的例程,很顯然,大家也有一定的感覺了,而在入門程序之前,我們已經說過一些其優缺點呀,但是說實話也沒啥特殊的感覺,我們正好循着這個例子,給大家簡單說一說其特點還有一些注意的點
1、首先,我們談到了,Thymeleaf "很優雅" ,因為綁定或者控制的時候,都是以屬性的方式,例如下面這段
<p th:text="'接收到的數據: ' + ${hello}"></p>
如果你直接在 HTML 中寫 ${hello}
那肯定是會出幺蛾子的,但是 Thymeleaf 這種寫法,表達式都寫在了自定義屬性中,所以在靜態環境下表達式的內容會被當做普通字符串,瀏覽器就不會報錯
2、同時看到, HTML 的原有結構,沒有被破壞掉,一眼望去還是 HTML 的那般模樣
3、根據上面的特點,所以也就使得 Thymeleaf 在靜態環境下也可以直接用瀏覽器運行,在靜態環境下 th 指令內的內容不會被識別,但是也不會報錯
(四) Thymeleaf 基本語法
(1) 引入命名空間約束
可以看到我們下面都是用 th:*
這種形式書寫,如果想要正常使用,就必須在 <head>
前面引入約束
<html xmlns:th="http://www.thymeleaf.org">
上面例程中已經用過了,下面開始正式的說一些常用的語法
(2) 變量語法及 th:text
A:舉例說明
一個簡單變量去看上面,的入門例程就行了,其實非常簡單,下面我們通過對象中的變量取值來看一下
1、編寫實體
首先創建兩個實體,學生類和課程類,在學生類中,引用課程類
public class Student {
private String name;
private Integer age;
private Course course;
...... 省略 get set toString
}
public class Course {
private String name;
private String teacher;
...... 省略 get set toString
}
2、編寫 Conteoller
@Controller
public class TestController {
@RequestMapping("testStudent")
public String testStudent(Model model){
// 兩個對象 分別賦值
Student stu = new Student();
Course course = new Course();
course.setName("JavaEE課程");
course.setTeacher("傑克老師");
stu.setName("張三");
stu.setAge(25);
stu.setCourse(course);
model.addAttribute("student",stu);
return "test.html";
}
}
3、編寫頁面
-
我們存入的是一個學生的對象,名為 student 我們通過
${}
的格式,來獲取model中的變量,代碼中所用 例如:student.name
就是ognl 表達式,可以去了解一下,形式就是xxx.屬性名
-
而表達式寫在一個名為:
th:text
的標簽屬性中,叫做指令 -
一般總會出現
th:xxx
的形式,這些常見的指令,會在后面把常見的給出,現在用的這個th:text
叫做文本替換,作用就是對表達式或變量求值,然后將結果顯示在其被包含的 html 標簽體內,替換掉原來的文本 -
所以可以在標簽中,寫上一些默認值,方便靜態的時候對比效果,運行后,那些文本就被后台的數據替換掉了
<p>學生姓名: <span th:text="${student.name}"></span> </p>
<p>學生年齡: <span th:text="${student.age}"></span> </p>
<p>課程名: <span th:text="${student.course.name}"></span> </p>
<p>授課老師: <span th:text="${student.course.teacher}"></span> </p>
4、執行效果
B:補充 th:utext
還有一個 th:utext
,與上面用的 th:text
很相似區別就是:
-
th:text
以純文本顯示且不解析內容里的HTML標簽或元素 -
th:utext
則把整個內容當成是HTML來解析並展示,也就是說,例如取到的值為<h2>測試</h2>
會按照二級標題來進行顯示
C:減少變量書寫次數方式
當我們涉及到的數據過多的時候,我們每寫一個就需要寫一次 student,我們同樣可以將其寫成一個自定義的變量
-
th:object="${student}"
獲取到值 -
引用時只需要通過
*{屬性名}
的方式,來獲取student中的這些屬性
<h5 th:object="${student}">
<p>學生姓名: <span th:text="*{name}"></span> </p>
<p>學生年齡: <span th:text="*{age}"></span> </p>
<p>課程名: <span th:text="*{course.name}"></span> </p>
<p>授課老師: <span th:text="*{course.teacher}"></span> </p>
</h5>
(3) 字符串拼接表達式
上面說完了變量,但是我們還有很多時候,還有一些內容是不希望被當做變量解析的,也就是我們所說的字面值,常見的類型例如:字符串、或者數值等都是這樣的,例如字符串 只需要在書寫時加上單引號,就可以了,而數字不需要什么處理,直接就可以用,還可以進行算數運算
當然很多時候,我們取到的數據,要配合頁面的一些字符串來進行顯示,一種做法就是直接在外面寫好內容例如
<p>學生姓名: <span th:text="${student.name}"></span> </p>
還有一種常見的,就是字符串與表達式的拼接,先說一下普通的方式:
- ① 把上面的 p 標簽中的內容移到 th:text 中來,用單引號引入即可
<p> <span th:text=" '學生姓名: ' + ${student.name}"></span> </p>
- ② 如果涉及到大量的拼接,使用單引號拼接,書寫以及可讀上會很混亂,所以,可以進行簡化:
<p> <span th:text=" |姓名: ${student.name}|"></span> </p>
多提一句,這種方式,在靜態環境運行的時候,是沒有字符串顯示的,只有用 SpringBoot 運行時才可以
(4) 運算符
運算符這一塊,我都是照着 Thymeleaf 官方文檔 ,第4大節,Standard Expression Syntax 中寫的,摘了一部分感覺還算常用的,不一定所有的例子我都給了測試,給了一些有代表性的
A:算數運算
1、支持的運算符
- 二元操作:+, - , * , / , %
- 一元操作: - (負)
2、測試代碼
注意:運算符最好放在外面,因為 運算符放在了 {} 內部, 表達式使用的是 ognl 引擎進行計算;,如果運算符放在外部, 那么 表達式使用的是 thymeleaf 引擎進行計算
<p>學生年齡 = <span th:text="${student.age} "></span> </p>
<p>學生年齡 / 2 = <span th:text="${student.age} / 2 "></span> </p>
<p>學生年齡 % 2 = <span th:text="${student.age} % 2 "></span> </p>
3、執行效果
B:布爾運算
1、支持的運算符
- 一元運算符 : and, or
- 二元運算符 : !, not
C:比較運算
1、支持的運算符
- 比較:> , < , >= , <= ( gt , lt , ge , le )
- 等於:== , != ( eq , ne )
2、說明:
-
> 和 <
會被當做標簽,所以不能直接使用,可以用括號內的別名代替使用 -
== 和 !=
除比較數值外,還有類似 equals 的作用
3、測試代碼
<p>學生姓名: <span th:text="${student.name}"></span> </p>
<p>學生姓名為張三 = <span th:text="${student.name} == '張三'"></span> </p>
<p>學生年齡為 25 = <span th:text="${student.age} == 25 "></span> </p>
<p>學生年齡 % 2 為 0 = <span th:text="${student.age} % 2 == 0 "></span> </p>
4、執行效果
D:條件運算
- If-then: (if) ? (then)
- If-then-else: (if) ? (then) : (else)
- Default: (value) ?: (defaultvalue)
2、測試代碼
<p>學生姓名 = <span th:text="${student.name} == '張三' ? '是張三':'不是張三'"></span> </p>
3、執行效果
(5) 條件運算再補充
上面講條件運算是放到了運算符中,演示了一下三元運算,因為邏輯判斷是非常常用的,所以我們再補充一下
A:if
沒什么好說的,就是一個簡單的判斷
1、測試代碼
<p>學生是否成年: <span th:if="${student.age} >= 18 ">成年</span> </p>
只有當年齡 > 18 歲的時候,才會顯示成年這兩個字,比較簡單,就不測試了
B:unless
unless 與 if 是截然相反的兩個概念,if 是滿足條件則執行,而 unless 是不滿足則執行
1、測試代碼
<p>學生是否成年: <span th:unless="${student.age} >= 18 ">成年</span> </p>
自己測試感受一下
C:switch
一個分支語句的語法,也很好理解,注意:th:case="*"
表示默認,放最后面就可以了
1、測試代碼
<div th:switch="${student.name}">
<p th:case="張三">姓名: 張三</p>
<p th:case="李四">姓名: 李四</p>
<p th:case="王五">姓名: 王五</p>
<p th:case="*">姓名: 未找到</p>
</div>
2、執行效果
改了下controller,把學生姓名賦值成了李四,看一下頁面的顯示
(6) 循環語法
循環也是非常常用的一種用法,通過 th:each
指令,來進行實現,我們下邊循着一個小 Demo 學習一下
A:演示 Demo
1、創建用戶類
public class User {
private String nickname;
private Integer age;
...... get set toString 方法
}
2、controller 添加方法
總之就是返回一個用戶的 List 集合
@RequestMapping("testUser")
public String testUser(Model model){
User user1 = new User();
user1.setNickname("飛翔的企鵝");
user1.setAge(30);
User user2 = new User();
user2.setNickname("傷心小男孩");
user2.setAge(25);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
model.addAttribute("userList",list);
return "test.html";
}
3、頁面代碼
此處注意:${userList}
中的 userLisr 就是我們返回的那個集合,user 是我們遍歷到的每一個用戶,和 Java 里面的增強 for 感覺是相似的
<table border="1">
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr th:each="user : ${userList}">
<td th:text="${user.nickname}">NULL</td>
<td th:text="${user.age}">0</td>
</tr>
</table>
4、執行效果
B:補充說明
① 迭代類型
關於要被遍歷的值,也就例如我們上面的 ${userList}
實際上有很多種可以接受的類型
- Enumeration,枚舉
- Map 集合
- List、數組及其它一切符合數組結果的對象
上面 Demo 的演示,更像 Java 中的增強 for,增強 for 雖然遍歷很方便,但是也有比之普通 for 的缺點,那就是沒有了例如一些狀態量,例如開始結束等等,有了一定的局限,所以 Thymeleaf 給我們提供了 stat對象,幫助我們彌補這一點
② stat對象的屬性
- index,當前迭代對象的index,從0開始的角標
- count,元素的個數,從1開始
- size,總元素個數
- current,當前遍歷到的元素
- even/odd,布爾值,當前循環是否是偶數/奇數,boolean值
- first/last,返回是否為第一或最后,boolean值
1、測試代碼
<table border="1">
<tr>
<th>昵稱</th>
<th>年齡</th>
<th>index</th>
<th>count</th>
<th>size</th>
<th>current.nickname</th>
<th>even</th>
<th>odd</th>
<th>first</th>
<th>last</th>
</tr>
<tr th:each="user,userStat : ${userList}">
<td th:text="${user.nickname}">nickname</td>
<td th:text="${user.age}">age</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.nickname}">current.nickname</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>
2、執行效果
(五) 內置方法
(1) 環境、上下文有關
Thymeleaf 還提供了一些內置的方法,供我們調用,不過我也不推薦過多的使用下列方法,前端頁面中,盡量還是減少邏輯,下面是從官方文檔中截的一張圖,我下面在表格中選了幾個翻譯了一下
對象 | 作用 |
---|---|
#ctx |
獲取 Thymeleaf 自己的 Context對象 |
#requset |
是web程序的情況下,用來獲取HttpServletRequest對象 |
#response |
是web程序的情況下,用來獲取HttpServletReponse對象 |
#session |
是web程序的情況下,用來獲取HttpSession對象 |
#servletContext |
是web程序的情況下,用來獲取HttpServletContext對象 |
(2) 工具類方法
還有一些,工具性質的內置對象,方便使用,還是先看下官方的截圖,當然了我沒截全所有的,有需要可以自己去看一下哈
對象 | 作用 |
---|---|
#dates |
用來處理時間(java.util.date)的對象 |
#calendars |
處理日歷中日期(java.util.calendar) 的對象 |
#numbers |
格式化數字 |
#strings |
處理字符串 |
#bools |
判斷布爾值 |
#arrays |
處理數組 |
#lists |
處理 List 集合 |
#sets |
處理 set 集合 |
#maps |
處理 map 集合 |
(3) 演示一下
1、編寫 controller 方法
@RequestMapping("testDate")
public String testDate(Model model){
model.addAttribute("currentTime",new Date());
return "test.html";
}
2、編寫頁面
<p>現在時間: <span th:text="${#dates.format(currentTime,'yyyy-MM-dd hh:mm:ss')}">2020-05-19 00:00:00</span></p>
3、執行效果
(六) 常用標簽
-
標簽中只做一個類似提綱目錄的用處,更詳細的用法還需要進行查閱與實踐
補充:
${...}
: 變量表達式*{...}
: 選擇表達式#{...}
: 消息 (i18n) 表達式@{...}
: 鏈接 (URL) 表達式~{...}
: 片段表達式
(1) th:text
文本替換:主要用於文本的顯示
第一種:
<p th:text="'接收到的數據: ' + ${hello}"></p>
第二種:
<p>學生姓名: <span th:text="${student.name}"></span> </p>
(2) th:utext
支持 HTML 的文本替換,可以用於富文本編輯器編輯后的內容顯示到前端的頁面上
th:utext
則把整個內容當成是HTML來解析並展示,也就是說,例如取到的值為<h2>測試</h2>
會按照二級標題來進行顯示
<p th:utext="'接收到的含有HTML標簽數據: ' + ${test}"></p>
(3) th:if / th:unless
th:if 用於判斷條件,滿足則執行,而 th:unless 與前者正好相反
th:if
<p>學生是否成年: <span th:if="${student.age} >= 18 ">成年</span> </p>
th:unless
<p>學生是否成年: <span th:unless="${student.age} >= 18 ">成年</span> </p>
(4) th:switch / th:case
用於多個同等級判斷,即多選一
<div th:switch="${student.name}">
<p th:case="張三">姓名: 張三</p>
<p th:case="李四">姓名: 李四</p>
<p th:case="王五">姓名: 王五</p>
<p th:case="*">姓名: 未找到</p>
</div>
注意:th:case="*"
表示默認,放最后面就可以了
(5) th:each
用於遍歷集合中的對象,和 JSTL 中的 <c:forEach>
基本是一致的
除此之外,還能獲取到一些狀態量 stat ,請翻閱上面關於循環語法的講解
<table border="1">
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr th:each="user : ${userList}">
<td th:text="${user.nickname}">NULL</td>
<td th:text="${user.age}">0</td>
</tr>
</table>
(6) th:action
用於表單的提交時,相當於 <form>
標簽的action屬性。
<form th:action="@{user/login}" method="post"></form>
(7) th:src
用於引入例如圖片或者 js 等外部資源
<img th:src="@{../images/test.jpg}"/>
或者
<script th:src="@{../static/register.js}"></script>
(8) th:href
用於定義超鏈接,相當於<a></a>
標簽的href屬性
傳統拼接傳遞
<a th:href="/showStudent?id=123456&name=張三"></a>
帶一個參數傳遞
<a th:href="@{/student/details(studentId=${student.id})}" ></a>
(9) th:value
用於屬性賦值
<input th:value = "${student.name}" />
(10) th:object / th:field
th:object 和 th:field 常搭配之用,用來表單參數綁定,看一個例子就大概明白了
1、編寫實體
public class LoginUser {
private String username;
private String password;
......
}
2、編寫 controller 方法
@RequestMapping("/testLogin")
public String testLogin(@ModelAttribute(value = "loginUser")LoginUser loginUser, ModelMap modelMap){
String username = loginUser.getUsername();
String password = loginUser.getPassword();
System.out.println(username);
System.out.println(password);
if ("admin".equals(username) && "admin888".equals(password)){
modelMap.addAttribute("msg","登陸成功");
return "test.html";
}
modelMap.addAttribute("msg","登陸失敗");
return "test.html";
}
3、編寫頁面
<form id="login" th:action="@{/testLogin}" th:object="${loginUser}">
<input type="text" value="" th:field="*{username}"></input>
<input type="text" value="" th:field="*{password}"></input>
<input type="submit" value="提交" />
<span th:text="${msg}"></span>
</form>
4、執行效果
(七) 結尾
如果文章中有什么不足,歡迎大家留言交流,感謝朋友們的支持!
如果能幫到你的話,那就來關注我吧!如果您更喜歡微信文章的閱讀方式,可以關注我的公眾號
在這里的我們素不相識,卻都在為了自己的夢而努力 ❤
一個堅持推送原創開發技術文章的公眾號:理想二旬不止