(五) SpringBoot起飛之路-Thymeleaf模板引擎整合及基本用法總結

興趣的朋友可以去了解一下前四篇,你的贊就是對我最大的支持,感謝大家!

(一) 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、執行效果

(七) 結尾

如果文章中有什麼不足,歡迎大家留言交流,感謝朋友們的支持!

如果能幫到你的話,那就來關注我吧!如果您更喜歡微信文章的閱讀方式,可以關注我的公衆號

在這裏的我們素不相識,卻都在爲了自己的夢而努力 ❤

一個堅持推送原創開發技術文章的公衆號:理想二旬不止

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