1. 程式人生 > 其它 >Spring Boot:入門

Spring Boot:入門

註解和反射

springboot 是基於註解的框架,因此先複習一下註解,瞭解註解如何通過反射獲取註解的值、

package Reflection;

import java.lang.annotation.*;
import java.lang.reflect.Field;

/**
 * author liulei
 * data  5.22
 * since 1.8
 * version 1.0
 * Description  反射獲取註解
 */
public class Test10 {
    public static void main(String[] args) throws Exception {
        Class aClass = Class.forName("Reflection.student2");
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation a:annotations){
            System.out.println(a);//屬性是私有的,所以沒有輸出屬性的註解
        }
        //獲得註解的value的值
        table t = (table) aClass.getAnnotation(table.class);
        String value = t.value();
        System.out.println(value);
        //獲得類指定的註解
        Field name = aClass.getDeclaredField("name");
        zidingyi annotation = name.getAnnotation(zidingyi.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}
@table("db_student")
class student2{
    @zidingyi(columnName = "db_id",type = "int",length = 10)
    private int id;
    @zidingyi(columnName = "db_id",type = "int",length = 10)
    private int age;
    @zidingyi(columnName = "db_id",type = "int",length = 10)
    private String name;

    public student2() {
    }

    public student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface zidingyi{
    String columnName();
    String type();
    int length();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface table{
    String value();
}

Class.getAnnotations() 獲取所有的註解,包括自己宣告的以及繼承的
Class.getAnnotation(Class< A > annotationClass) 獲取指定的註解,該註解可以是自己宣告的,也可以是繼承的
Class.getDeclaredAnnotations() 獲取自己宣告的註解

**springboot簡介**

回顧什麼是Spring

Spring是一個開源框架,2003 年興起的一個輕量級的Java 開發框架,作者:Rod Johnson 。

Spring是為了解決企業級應用開發的複雜性而建立的,簡化開發。

Spring是如何簡化Java開發的

為了降低Java開發的複雜性,Spring採用了以下4種關鍵策略:

1、基於POJO的輕量級和最小侵入性程式設計,所有東西都是bean;

2、通過IOC,依賴注入(DI)和麵向介面實現鬆耦合;

3、基於切面(AOP)和慣例進行宣告式程式設計;

4、通過切面和模版減少樣式程式碼,RedisTemplate,xxxTemplate

什麼是SpringBoot

  學過javaweb的同學就知道,開發一個web應用,從最初開始接觸Servlet結合Tomcat, 跑出一個Hello Wolrld程式,是要經歷特別多的步驟;後來就用了框架Struts,再後來是SpringMVC,到了現在的SpringBoot,過一兩年又會有其他web框架出現;你們有經歷過框架不斷的演進,然後自己開發專案所有的技術也在不斷的變化、改造嗎?建議都可以去經歷一遍;言歸正傳,什麼是SpringBoot呢,就是一個javaweb的開發框架,和SpringMVC類似,對比其他javaweb框架的好處,官方說是簡化開發,約定大於配置, you can "just run",能迅速的開發web應用,幾行程式碼開發一個http介面。

  所有的技術框架的發展似乎都遵循了一條主線規律:從一個複雜應用場景 衍生 一種規範框架,人們只需要進行各種配置而不需要自己去實現它,這時候強大的配置功能成了優點;發展到一定程度之後,人們根據實際生產應用情況,選取其中實用功能和設計精華,重構出一些輕量級的框架;之後為了提高開發效率,嫌棄原先的各類配置過於麻煩,於是開始提倡“約定大於配置”,進而衍生出一些一站式的解決方案。

  是的這就是Java企業級應用->J2EE->spring->springboot的過程。

  隨著 Spring 不斷的發展,涉及的領域越來越多,專案整合開發需要配合各種各樣的檔案,慢慢變得不那麼易用簡單,違背了最初的理念,甚至人稱配置地獄。Spring Boot 正是在這樣的一個背景下被抽象出來的開發框架,目的為了讓大家更容易的使用 Spring 、更容易的整合各種常用的中介軟體、開源軟體;

  Spring Boot 基於 Spring 開發,Spirng Boot 本身並不提供 Spring 框架的核心特性以及擴充套件功能,只是用於快速、敏捷地開發新一代基於 Spring 框架的應用程式。也就是說,它並不是用來替代 Spring 的解決方案,而是和 Spring 框架緊密結合用於提升 Spring 開發者體驗的工具。Spring Boot 以約定大於配置的核心思想,預設幫我們進行了很多設定,多數 Spring Boot 應用只需要很少的 Spring 配置。同時它集成了大量常用的第三方庫配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 應用中這些第三方庫幾乎可以零配置的開箱即用。

  簡單來說就是SpringBoot其實不是什麼新的框架,它預設配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架 。

  Spring Boot 出生名門,從一開始就站在一個比較高的起點,又經過這幾年的發展,生態足夠完善,Spring Boot 已經當之無愧成為 Java 領域最熱門的技術。

Spring Boot的主要優點:

  • 為所有Spring開發者更快的入門

  • 開箱即用,提供各種預設配置來簡化專案配置

  • 內嵌式容器簡化Web專案

  • 沒有冗餘程式碼生成和XML配置的要求

真的很爽,我們快速去體驗開發個介面的感覺吧!



Hello,World

準備工作

我們將學習如何快速的建立一個Spring Boot應用,並且實現一個簡單的Http請求處理。通過這個例子對Spring Boot有一個初步的瞭解,並體驗其結構簡單、開發快速的特性。

我的環境準備:

  • java version "1.8.0_181"

  • Maven-3.6.1

  • SpringBoot 2.x 最新版

開發工具:

  • IDEA

建立基礎專案說明

Spring官方提供了非常方便的工具讓我們快速構建應用

Spring Initializr:https://start.spring.io/

專案建立方式一:使用Spring Initializr 的 Web頁面建立專案

1、開啟 https://start.spring.io/

2、填寫專案資訊

3、點選”Generate Project“按鈕生成專案;下載此專案

4、解壓專案包,並用IDEA以Maven專案匯入,一路下一步即可,直到專案匯入完畢。

5、如果是第一次使用,可能速度會比較慢,包比較多、需要耐心等待一切就緒。

專案建立方式二:使用 IDEA 直接建立專案

1、建立一個新專案

2、選擇spring initalizr , 可以看到預設就是去官網的快速構建工具那裡實現

3、填寫專案資訊

4、選擇初始化的元件(初學勾選 Web 即可)

5、填寫專案路徑

6、等待專案構建成功

專案結構分析:

通過上面步驟完成了基礎專案的建立。就會自動生成以下檔案。

1、程式的主啟動類

2、一個 application.properties 配置檔案

3、一個 測試類

4、一個 pom.xml

pom.xml 分析

開啟pom.xml,看看Spring Boot專案的依賴:

<!-- 父依賴 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- web場景啟動器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- springboot單元測試 -->
    <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>

編寫一個http介面

1、在主程式的同級目錄下,新建一個controller包,一定要在同級目錄下,否則識別不到

2、在包中新建一個HelloController類

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello() {
        return "Hello World";
    }
    
}

3、編寫完畢後,從主程式啟動專案,瀏覽器發起請求,看頁面返回;控制檯輸出了 Tomcat 訪問的埠號!

簡單幾步,就完成了一個web介面的開發,SpringBoot就是這麼簡單。所以我們常用它來建立我們的微服務專案!

將專案打成jar包,點選 maven的 package

如果遇到以上錯誤,可以配置打包時 跳過專案執行測試用例

<!--
    在工作中,很多情況下我們打包是不想執行測試用例的
    可能是測試用例不完事,或是測試用例會影響資料庫資料
    跳過測試用例執
    -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!--跳過專案執行測試用例-->
        <skipTests>true</skipTests>
    </configuration>
</plugin>

如果打包成功,則會在target目錄下生成一個 jar 包

打成了jar包後,就可以在任何地方運行了!OK

彩蛋

如何更改啟動時顯示的字元拼成的字母,SpringBoot呢?也就是 banner 圖案;

只需一步:到專案下的 resources 目錄下新建一個banner.txt 即可。

圖案可以到:https://www.bootschool.net/ascii這個網站生成,然後拷貝到檔案中即可!

yaml配置注入

配置檔案

SpringBoot使用一個全域性的配置檔案 , 配置檔名稱是固定的

  • application.properties

    • 語法結構 :key=value

  • application.yml

    • 語法結構 :key:空格 value

配置檔案的作用 :修改SpringBoot自動配置的預設值,因為SpringBoot在底層都給我們自動配置好了;

比如我們可以在配置檔案中修改Tomcat 預設啟動的埠號!測試一下!

server.port=8081

yaml概述

YAML是 "YAML Ain't a Markup Language" (YAML不是一種標記語言)的遞迴縮寫。在開發的這種語言時,YAML 的意思其實是:"Yet Another Markup Language"(仍是一種標記語言)

這種語言以資料為中心,而不是以標記語言為重點!

以前的配置檔案,大多數都是使用xml來配置;比如一個簡單的埠配置,我們來對比下yaml和xml

傳統xml配置:

<server>    <port>8081<port></server>

yaml配置:

server:  prot: 8080

yaml基礎語法

說明:語法要求嚴格!

1、空格不能省略

2、以縮排來控制層級關係,只要是左邊對齊的一列資料都是同一個層級的。

3、屬性和值的大小寫都是十分敏感的。

字面量:普通的值 [ 數字,布林值,字串 ]

字面量直接寫在後面就可以 , 字串預設不用加上雙引號或者單引號;

k: v

注意:

  • “ ” 雙引號,不會轉義字串裡面的特殊字元 , 特殊字元會作為本身想表示的意思;

    比如 :name: "kuang \n shen" 輸出 :kuang 換行 shen

  • '' 單引號,會轉義特殊字元 , 特殊字元最終會變成和普通字元一樣輸出

    比如 :name: ‘kuang \n shen’ 輸出 :kuang \n shen

物件、Map(鍵值對)

#物件、Map格式k:     v1:    v2:

在下一行來寫物件的屬性和值得關係,注意縮排;比如:

student:    name: qinjiang    age: 3

行內寫法

student: {name: qinjiang,age: 3}

陣列( List、set )

用 - 值表示陣列中的一個元素,比如:

pets: - cat - dog - pig

行內寫法

pets: [cat,dog,pig]

修改SpringBoot的預設埠號

配置檔案中新增,埠號的引數,就可以切換埠;

server:  port: 8082


yaml檔案更強大的地方在於,他可以給我們的實體類直接注入匹配值!

yaml注入配置檔案

1、在springboot專案中的resources目錄下新建一個檔案 application.yml

2、編寫一個實體類 Dog;

package com.kuang.springboot.pojo;

@Component  //註冊bean到容器中
public class Dog {
    private String name;
    private Integer age;
    
    //有參無參構造、get、set方法、toString()方法  
}

3、思考,我們原來是如何給bean注入屬性值的!@Value,給狗狗類測試一下:

@Component //註冊bean
public class Dog {
    @Value("阿黃")
    private String name;
    @Value("18")
    private Integer age;
}

4、在SpringBoot的測試類下注入狗狗輸出一下

@SpringBootTest
class DemoApplicationTests {

    @Autowired //將狗狗自動注入進來
    Dog dog;

    @Test
    public void contextLoads() {
        System.out.println(dog); //列印看下狗狗物件
    }

}

結果成功輸出,@Value注入成功,這是我們原來的辦法對吧。

5、我們在編寫一個複雜一點的實體類:Person 類

@Component //註冊bean到容器中
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
    
    //有參無參構造、get、set方法、toString()方法  
}

6、我們來使用yaml配置的方式進行注入,大家寫的時候注意區別和優勢,我們編寫一個yaml配置!

person:
  name: qinjiang
  age: 3
  happy: false
  birth: 2000/01/01
  maps: {k1: v1,k2: v2}
  lists:
   - code
   - girl
   - music
  dog:
    name: 旺財
    age: 1

7、我們剛才已經把person這個物件的所有值都寫好了,我們現在來注入到我們的類中!

/*
@ConfigurationProperties作用:
將配置檔案中配置的每一個屬性的值,對映到這個元件中;
告訴SpringBoot將本類中的所有屬性和配置檔案中相關的配置進行繫結
引數 prefix = “person” : 將配置檔案中的person下面的所有屬性一一對應
*/
@Component //註冊bean
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}

8、IDEA 提示,springboot配置註解處理器沒有找到,讓我們看文件,我們可以檢視文件,找到一個依賴!

<!-- 匯入配置檔案處理器,配置檔案進行繫結就會有提示,需要重啟 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

9、確認以上配置都OK之後,我們去測試類中測試一下:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    Person person; //將person自動注入進來

    @Test
    public void contextLoads() {
        System.out.println(person); //列印person資訊
    }

}

結果:所有值全部注入成功!

yaml配置注入到實體類完全OK!

課堂測試:

1、將配置檔案的key 值 和 屬性的值設定為不一樣,則結果輸出為null,注入失敗

2、在配置一個person2,然後將 @ConfigurationProperties(prefix = "person2") 指向我們的person2;

載入指定的配置檔案

@PropertySource :載入指定的配置檔案;

@configurationProperties:預設從全域性配置檔案中獲取值;

1、我們去在resources目錄下新建一個person.properties檔案

name=kuangshen

2、然後在我們的程式碼中指定載入person.properties檔案

@PropertySource(value = "classpath:person.properties")
@Component //註冊bean
public class Person {

    @Value("${name}")
    private String name;

    ......  
}

配置檔案佔位符

配置檔案還可以編寫佔位符生成隨機數

person:
    name: qinjiang${random.uuid} # 隨機uuid
    age: ${random.int}  # 隨機int
    happy: false
    birth: 2000/01/01
    maps: {k1: v1,k2: v2}
    lists:
      - code
      - girl
      - music
    dog:
      name: ${person.hello:other}_旺財
      age: 1

回顧properties配置

我們上面採用的yaml方法都是最簡單的方式,開發中最常用的;也是springboot所推薦的!那我們來嘮嘮其他的實現方式,道理都是相同的;寫還是那樣寫;配置檔案除了yml還有我們之前常用的properties , 我們沒有講,我們來嘮嘮!

【注意】properties配置檔案在寫中文的時候,會有亂碼 , 我們需要去IDEA中設定編碼格式為UTF-8;

settings-->FileEncodings 中配置;

測試步驟:

1、新建一個實體類User

@Component //註冊beanpublic class User {    private String name;    private int age;    private String sex;}

2、編輯配置檔案 user.properties

user1.name=kuangshenuser1.age=18user1.sex=男

3、我們在User類上使用@Value來進行注入!

@Component //註冊bean@PropertySource(value = "classpath:user.properties")public class User {    //直接使用@value    @Value("${user.name}") //從配置檔案中取值    private String name;    @Value("#{9*2}")  // #{SPEL} Spring表示式    private int age;    @Value("男")  // 字面量    private String sex;}

4、Springboot測試

@SpringBootTestclass DemoApplicationTests {
@Autowired User user;
@Test public void contextLoads() { System.out.println(user); }
}

結果正常輸出:

對比小結

@Value這個使用起來並不友好!我們需要為每個屬性單獨註解賦值,比較麻煩;我們來看個功能對比圖

1、@ConfigurationProperties只需要寫一次即可 , @Value則需要每個欄位都新增

2、鬆散繫結:這個什麼意思呢? 比如我的yml中寫的last_name,這個和lastName是一樣的, - 後面跟著的字母預設是大寫的。這就是鬆散繫結。可以測試一下

3、JSR303資料校驗 , 這個就是我們可以在欄位是增加一層過濾器驗證 , 可以保證資料的合法性

4、複雜型別封裝,yml中可以封裝物件 , 使用value就不支援

結論:

配置yml和配置properties都可以獲取到值 , 強烈推薦 yml;

如果我們在某個業務中,只需要獲取配置檔案中的某個值,可以使用一下 @value;

如果說,我們專門編寫了一個JavaBean來和配置檔案進行一一對映,就直接@configurationProperties,不要猶豫!

JSR303資料校驗及多環境切換

JSR303資料校驗

先看看如何使用

Springboot中可以用@validated來校驗資料,如果資料異常則會統一丟擲異常,方便異常中心統一處理。我們這裡來寫個註解讓我們的name只能支援Email格式;

@Component //註冊bean
@ConfigurationProperties(prefix = "person")
@Validated  //資料校驗
public class Person {

    @Email(message="郵箱格式錯誤") //name必須是郵箱格式
    private String name;
}

執行結果 :default message [不是一個合法的電子郵件地址];

使用資料校驗,可以保證資料的正確性;

引入註解

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.4.5</version>
</dependency>

常見引數

@NotNull(message="名字不能為空")
private String userName;
@Max(value=120,message="年齡最大不能查過120")
private int age;
@Email(message="郵箱格式錯誤")
private String email;

空檢查
@Null       驗證物件是否為null
@NotNull    驗證物件是否不為null, 無法查檢長度為0的字串
@NotBlank   檢查約束字串是不是Null還有被Trim的長度是否大於0,只對字串,且會去掉前後空格.
@NotEmpty   檢查約束元素是否為NULL或者是EMPTY.
    
Booelan檢查
@AssertTrue     驗證 Boolean 物件是否為 true  
@AssertFalse    驗證 Boolean 物件是否為 false  
    
長度檢查
@Size(min=, max=) 驗證物件(Array,Collection,Map,String)長度是否在給定的範圍之內  
@Length(min=, max=) string is between min and max included.

日期檢查
@Past       驗證 Date 和 Calendar 物件是否在當前時間之前  
@Future     驗證 Date 和 Calendar 物件是否在當前時間之後  
@Pattern    驗證 String 物件是否符合正則表示式的規則

.......等等
除此以外,我們還可以自定義一些資料校驗規則


多環境切換

profile是Spring對不同環境提供不同配置功能的支援,可以通過啟用不同的環境版本,實現快速切換環境;

多配置檔案

我們在主配置檔案編寫的時候,檔名可以是 application-{profile}.properties/yml , 用來指定多個環境版本;

例如:

application-test.properties 代表測試環境配置

application-dev.properties 代表開發環境配置

但是Springboot並不會直接啟動這些配置檔案,它預設使用application.properties主配置檔案

我們需要通過一個配置來選擇需要啟用的環境:

#比如在配置檔案中指定使用dev環境,我們可以通過設定不同的埠號進行測試;#我們啟動SpringBoot,就可以看到已經切換到dev下的配置了;spring.profiles.active=dev

yaml的多文件塊

和properties配置檔案中一樣,但是使用yml去實現不需要建立多個配置檔案,更加方便了 !

server:
  port: 8081
#選擇要啟用那個環境塊
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置環境的名稱


---

server:
  port: 8084
spring:
  profiles: prod  #配置環境的名稱

注意:如果yml和properties同時都配置了埠,並且沒有啟用其他環境 , 預設會使用properties配置檔案的!


配置檔案載入位置

外部載入配置檔案的方式十分多,我們選擇最常用的即可,在開發的資原始檔中進行配置!

官方外部配置檔案說明參考文件

springboot 啟動會掃描以下位置的application.properties或者application.yml檔案作為Spring boot的預設配置檔案:

優先順序1:專案路徑下的config資料夾配置檔案
優先順序2:專案路徑下配置檔案
優先順序3:資源路徑下的config資料夾配置檔案
優先順序4:資源路徑下配置檔案

優先順序由高到底,高優先順序的配置會覆蓋低優先順序的配置;

SpringBoot會從這四個位置全部載入主配置檔案;互補配置;

我們在最低階的配置檔案中設定一個專案訪問路徑的配置來測試互補問題;

#配置專案的訪問路徑server.servlet.context-path=/kuang

拓展,運維小技巧

指定位置載入配置檔案

我們還可以通過spring.config.location來改變預設的配置檔案位置

專案打包好以後,我們可以使用命令列引數的形式,啟動專案的時候來指定配置檔案的新位置;這種情況,一般是後期運維做的多,相同配置,外部指定的配置檔案優先順序最高

java -jar spring-boot-config.jar --spring.config.location=F:/application.propert

Web開發靜態資源處理

簡介

好的,同學們,那麼接下來呢,我們開始學習SpringBoot與Web開發,從這一章往後,就屬於我們實戰部分的內容了;

其實SpringBoot的東西用起來非常簡單,因為SpringBoot最大的特點就是自動裝配。

使用SpringBoot的步驟:

1、建立一個SpringBoot應用,選擇我們需要的模組,SpringBoot就會預設將我們的需要的模組自動配置好

2、手動在配置檔案中配置部分配置專案就可以執行起來了

3、專注編寫業務程式碼,不需要考慮以前那樣一大堆的配置了。

要熟悉掌握開發,之前學習的自動配置的原理一定要搞明白!

比如SpringBoot到底幫我們配置了什麼?我們能不能修改?我們能修改哪些配置?我們能不能擴充套件?

  • 向容器中自動配置元件 :*** Autoconfiguration

  • 自動配置類,封裝配置檔案的內容:***Properties

沒事就找找類,看看自動裝配原理!

我們之後來進行一個單體專案的小專案測試,讓大家能夠快速上手開發

首先,我們搭建一個普通的SpringBoot專案,回顧一下HelloWorld程式!

寫請求非常簡單,那我們要引入我們前端資源,我們專案中有許多的靜態資源,比如css,js等檔案,這個SpringBoot怎麼處理呢?

如果我們是一個web應用,我們的main下會有一個webapp,我們以前都是將所有的頁面導在這裡面的,對吧!但是我們現在的pom呢,打包方式是為jar的方式,那麼這種方式SpringBoot能不能來給我們寫頁面呢?當然是可以的,但是SpringBoot對於靜態資源放置的位置,是有規定的!

我們先來聊聊這個靜態資源對映規則:

SpringBoot中,SpringMVC的web配置都在 WebMvcAutoConfiguration 這個配置類裡面;

我們可以去看看 WebMvcAutoConfigurationAdapter 中有很多配置方法;有一個方法:addResourceHandlers新增資源處理

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (!this.resourceProperties.isAddMappings()) {
        // 已禁用預設資源處理
        logger.debug("Default resource handling disabled");
        return;
    }
    // 快取控制
    Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
    CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
    // webjars 配置
    if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
                                             .addResourceLocations("classpath:/META-INF/resources/webjars/")
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
    // 靜態資源配置
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
                                             .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
}

讀一下原始碼:比如所有的 /webjars/** , 都需要去 classpath:/META-INF/resources/webjars/ 找對應的資源;

什麼是webjars 呢?

Webjars本質就是以jar包的方式引入我們的靜態資源 , 我們以前要匯入一個靜態資原始檔,直接匯入即可。

使用SpringBoot需要使用Webjars,我們可以去搜索一下:

網站:https://www.webjars.org

要使用jQuery,我們只要要引入jQuery對應版本的pom依賴即可!

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.4.1</version>
</dependency>

匯入完畢,檢視webjars目錄結構,並訪問Jquery.js檔案!

訪問:只要是靜態資源,SpringBoot就會去對應的路徑尋找資源,我們這裡訪問:http://localhost:8080/webjars/jquery/3.4.1/jquery.js

第二種靜態資源對映規則

那我們專案中要是使用自己的靜態資源該怎麼匯入呢?我們看下一行程式碼;

我們去找staticPathPattern發現第二種對映規則 :/** , 訪問當前的專案任意資源,它會去找 resourceProperties 這個類,我們可以點進去看一下分析:

// 進入方法
public String[] getStaticLocations() {
    return this.staticLocations;
}
// 找到對應的值
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
// 找到路徑
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { 
    "classpath:/META-INF/resources/",
  "classpath:/resources/", 
    "classpath:/static/", 
    "classpath:/public/" 
};

ResourceProperties 可以設定和我們靜態資源有關的引數;這裡面指向了它會去尋找資源的資料夾,即上面陣列的內容。

所以得出結論,以下四個目錄存放的靜態資源可以被我們識別

"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

我們可以在resources根目錄下新建對應的資料夾,都可以存放我們的靜態檔案;

比如我們訪問http://localhost:8080/1.js, 他就會去這些資料夾中尋找對應的靜態資原始檔;

在下面檔案裡面放靜態資原始檔

/**是classpath下面的所有檔案包括子檔案。

優先訪問resource下的檔案,找到了其他的目錄就不再去找了

一般public優先順序最低只放公共的資源,static放圖片

我們可以修改靜態資源的預設位置,修改後之前位置的資源就不能再被訪問到了

自定義靜態資源路徑

private Optional<Resource> getWelcomePage() {
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    // ::是java8 中新引入的運算子
    // Class::function的時候function是屬於Class的,應該是靜態方法。
    // this::function的funtion是屬於這個物件的。
    // 簡而言之,就是一種語法糖而已,是一種簡寫
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
// 歡迎頁就是一個location下的的 index.html 而已
private Resource getIndexHtml(String location) {
    return this.resourceLoader.getResource(location + "index.html");
}

我們也可以自己通過配置檔案來指定一下,哪些資料夾是需要我們放靜態資原始檔的,在application.properties中配置;

一旦自己定義了靜態資料夾的路徑,原來的自動配置就都會失效了!

首頁處理

靜態資原始檔夾說完後,我們繼續向下看原始碼!可以看到一個歡迎頁的對映,就是我們的首頁!點進去繼續看

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                                                           FormattingConversionService mvcConversionService,
                                                           ResourceUrlProvider mvcResourceUrlProvider) {
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), // getWelcomePage 獲得歡迎頁
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    return welcomePageHandlerMapping;
}

歡迎頁,靜態資原始檔夾下的所有 index.html 頁面;被 /** 對映。

比如我訪問 http://localhost:8080/,就會找靜態資原始檔夾下的 index.html

新建一個 index.html ,在我們上面的3個目錄中任意一個;然後訪問測試 http://localhost:8080/看結果!

關於網站圖示說明

與其他靜態資源一樣,Spring Boot在配置的靜態內容位置中查詢 favicon.ico。如果存在這樣的檔案,它將自動用作應用程式的favicon。

1、關閉SpringBoot預設圖示

#關閉預設圖示
spring.mvc.favicon.enabled=false

2、自己放一個圖示在靜態資源目錄下,我放在 public 目錄下

3、清除瀏覽器快取!重新整理網頁,發現圖示已經變成自己的了!

Thymeleaf模板引擎

模板引擎

前端交給我們的頁面,是html頁面。如果是我們以前開發,我們需要把他們轉成jsp頁面,jsp好處就是當我們查出一些資料轉發到JSP頁面以後,我們可以用jsp輕鬆實現資料的顯示,及互動等。

jsp支援非常強大的功能,包括能寫Java程式碼,但是呢,我們現在的這種情況,SpringBoot這個專案首先是以jar的方式,不是war,像第二,我們用的還是嵌入式的Tomcat,所以呢,他現在預設是不支援jsp的

那不支援jsp,如果我們直接用純靜態頁面的方式,那給我們開發會帶來非常大的麻煩,那怎麼辦呢?

SpringBoot推薦你可以來使用模板引擎:

模板引擎,我們其實大家聽到很多,其實jsp就是一個模板引擎,還有用的比較多的freemarker,包括SpringBoot給我們推薦的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他們的思想都是一樣的,什麼樣一個思想呢我們來看一下這張圖:

模板引擎的作用就是我們來寫一個頁面模板,比如有些值呢,是動態的,我們寫一些表示式。而這些值,從哪來呢,就是我們在後臺封裝一些資料。然後把這個模板和這個資料交給我們模板引擎,模板引擎按照我們這個資料幫你把這表示式解析、填充到我們指定的位置,然後把這個資料最終生成一個我們想要的內容給我們寫出去,這就是我們這個模板引擎,不管是jsp還是其他模板引擎,都是這個思想。只不過呢,就是說不同模板引擎之間,他們可能這個語法有點不一樣。其他的我就不介紹了,我主要來介紹一下SpringBoot給我們推薦的Thymeleaf模板引擎,這模板引擎呢,是一個高階語言的模板引擎,他的這個語法更簡單。而且呢,功能更強大。

我們呢,就來看一下這個模板引擎,那既然要看這個模板引擎。首先,我們來看SpringBoot裡邊怎麼用。

引入Thymeleaf

怎麼引入呢,對於springboot來說,什麼事情不都是一個start的事情嘛,我們去在專案中引入一下。給大家三個網址:

Thymeleaf 官網:https://www.thymeleaf.org/

Thymeleaf 在Github 的主頁:https://github.com/thymeleaf/thymeleaf

Spring官方文件:找到我們對應的版本

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

找到對應的pom依賴:可以適當點進原始碼看下本來的包!

<!--thymeleaf-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Maven會自動下載jar包,我們可以去看下下載的東西;

Thymeleaf分析

前面呢,我們已經引入了Thymeleaf,那這個要怎麼使用呢?

我們首先得按照SpringBoot的自動配置原理看一下我們這個Thymeleaf的自動配置規則,在按照那個規則,我們進行使用。

我們去找一下Thymeleaf的自動配置類:ThymeleafProperties

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
}

我們可以在其中看到預設的字首和字尾!

我們只需要把我們的html頁面放在類路徑下的templates下,thymeleaf就可以幫我們自動渲染了。

使用thymeleaf什麼都不需要配置,只需要將他放在指定的資料夾下即可!

1、編寫一個TestController

@Controller
public class TestController {
    
    @RequestMapping("/t1")
    public String test1(){
        //classpath:/templates/test.html
        return "test";
    }
    
}

2、編寫一個測試頁面 test.html 放在 templates 目錄下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>測試頁面</h1>

</body>
</html>

3、啟動專案請求測試

Thymeleaf 語法學習

要學習語法,還是參考官網文件最為準確,我們找到對應的版本看一下;

Thymeleaf 官網:https://www.thymeleaf.org/, 簡單看一下官網!我們去下載Thymeleaf的官方文件!

我們做個最簡單的練習 :我們需要查出一些資料,在頁面中展示

1、修改測試請求,增加資料傳輸;

@RequestMapping("/t1")
public String test1(Model model){
    //存入資料
    model.addAttribute("msg","Hello,Thymeleaf");
    //classpath:/templates/test.html
    return "test";
}

2、我們要使用thymeleaf,需要在html檔案中匯入名稱空間的約束,方便提示。

我們可以去官方文件的#3中看一下名稱空間拿來過來:

xmlns:th="http://www.thymeleaf.org"

3、我們去編寫下前端頁面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>狂神說</title>
</head>
<body>
<h1>測試頁面</h1>

<!--th:text就是將div中的內容設定為它指定的值,和之前學習的Vue一樣-->
<div th:text="${msg}"></div>
</body>
</html>

4、啟動測試!

OK,入門搞定,我們來認真研習一下Thymeleaf的使用語法!

1、我們可以使用任意的 th:attr 來替換Html中原生屬性的值!

2、我們能寫哪些表示式呢?

Simple expressions:(表示式語法)
Variable Expressions: ${...}:獲取變數值;OGNL;
    1)、獲取物件的屬性、呼叫方法
    2)、使用內建的基本物件:#18
         #ctx : the context object.
         #vars: the context variables.
         #locale : the context locale.
         #request : (only in Web Contexts) the HttpServletRequest object.
         #response : (only in Web Contexts) the HttpServletResponse object.
         #session : (only in Web Contexts) the HttpSession object.
         #servletContext : (only in Web Contexts) the ServletContext object.

    3)、內建的一些工具物件:
      #execInfo : information about the template being processed.
      #uris : methods for escaping parts of URLs/URIs
      #conversions : methods for executing the configured conversion service (if any).
      #dates : methods for java.util.Date objects: formatting, component extraction, etc.
      #calendars : analogous to #dates , but for java.util.Calendar objects.
      #numbers : methods for formatting numeric objects.
      #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
      #objects : methods for objects in general.
      #bools : methods for boolean evaluation.
      #arrays : methods for arrays.
      #lists : methods for lists.
      #sets : methods for sets.
      #maps : methods for maps.
      #aggregates : methods for creating aggregates on arrays or collections.
==================================================================================

  Selection Variable Expressions: *{...}:選擇表示式:和${}在功能上是一樣;
  Message Expressions: #{...}:獲取國際化內容
  Link URL Expressions: @{...}:定義URL;
  Fragment Expressions: ~{...}:片段引用表示式

Literals(字面量)
      Text literals: 'one text' , 'Another one!' ,…
      Number literals: 0 , 34 , 3.0 , 12.3 ,…
      Boolean literals: true , false
      Null literal: null
      Literal tokens: one , sometext , main ,…
      
Text operations:(文字操作)
    String concatenation: +
    Literal substitutions: |The name is ${name}|
    
Arithmetic operations:(數學運算)
    Binary operators: + , - , * , / , %
    Minus sign (unary operator): -
    
Boolean operations:(布林運算)
    Binary operators: and , or
    Boolean negation (unary operator): ! , not
    
Comparisons and equality:(比較運算)
    Comparators: > , < , >= , <= ( gt , lt , ge , le )
    Equality operators: == , != ( eq , ne )
    
Conditional operators:條件運算(三元運算子)
    If-then: (if) ? (then)
    If-then-else: (if) ? (then) : (else)
    Default: (value) ?: (defaultvalue)
    
Special tokens:
    No-Operation: _

練習測試:

1、 我們編寫一個Controller,放一些資料

@RequestMapping("/t2")
public String test2(Map<String,Object> map){
    //存入資料
    map.put("msg","<h1>Hello</h1>");
    map.put("users", Arrays.asList("qinjiang","kuangshen"));
    //classpath:/templates/test.html
    return "test";
}

2、測試頁面取出資料

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>狂神說</title>
</head>
<body>
<h1>測試頁面</h1>

<div th:text="${msg}"></div>
<!--不轉義-->
<div th:utext="${msg}"></div>

<!--遍歷資料-->
<!--th:each每次遍歷都會生成當前這個標籤:官網#9-->
<h4 th:each="user :${users}" th:text="${user}"></h4>

<h4>
    <!--行內寫法:官網#12-->
    <span th:each="user:${users}">[[${user}]]</span>
</h4>

</body>
</html>

3、啟動專案測試!

我們看完語法,很多樣式,我們即使現在學習了,也會忘記,所以我們在學習過程中,需要使用什麼,根據官方文件來查詢,才是最重要的,要熟練使用官方文件!




作者:你的雷哥 出處:https://www.cnblogs.com/henuliulei/