一文帶你學習 SpringBoot

1、SpringBoot簡介

1.什麼是SpringBoot

​ 產生背景:Spring開發比較繁瑣,配置文件不少,部署流程複雜,整合第三方框架難度大。這會下降開發效率css

SpringBoot是一個簡化Spring應用建立和開發的框架html

​ 整合了整個Spring技術棧,是JavaEE開發一站式解決方案前端

2.爲何使用SpringBoot

優勢:java

  • 能夠快速構架Spring項目,並與主流框架進行集成
  • 內置Servlet容器,不須要手動部署war包
  • 使用starter管理依賴並進行版本控制
  • 大量自動配置,簡化開發
  • 提供準生產環境的運行時監控
  • 不須要XML文件

2、第一個SpringBoot程序

1.操做步驟

步驟:mysql

1.1 建立一個Maven的jar工程

傳統的應用須要建立web工程,而後將應用打成war包,而後部署在容器中git

而SpringBoot只須要打成一個jar包,其中內置了tomcatgithub

1.2 導入SpringBoot相關依賴
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ly</groupId>
    <artifactId>springboot01-helloworld</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>

    <name>springboot01-helloworld</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
    </build>
</project>
1.3 建立Controller
package com.ly.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Author: LuYi
 * Date: 2019/10/27 11:05
 * Description: 描述
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
        return "Hello World";
    }
}
1.4 建立啓動類
package com.ly;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Author: LuYi
 * Date: 2019/10/27 11:05
 * Description: 使用@SpringBootApplication將類標註成SpringBoot應用
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

<font color='red'>默認會掃描@SpringBootApplication註解所在的包及其子包,也可以使用@ComponentScan("com.ly.controller")註解進行指定</font>web

1.5 打包
<!--該插件能夠將應用打包成一個可執行的jar包-->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

添加該插件,將應用打成可執行的jar包, 執行:java -jar jar文件redis

2. 分析HelloWorld

2.1 POM文件
  • 父工程spring

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
    </parent>
  • 父工程的父工程:用來管理SpringBoot應用中依賴的版本,進行版本控制

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath>../../spring-boot-dependencies</relativePath>
    </parent>
  • 依賴:經過starter指定依賴

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    SpringBoot提供了不少starter(啓動器),分別對應了不一樣的應用場景,當在項目中引入這些starter時,相應場景的依賴就會被導入進來

2.2 啓動類
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
  • @SpringBootApplication

    標註在類上,表示這個類是SpringBoot的啓動類,經過該類的Main方法啓動SpringBoot應用

  • @SpringBootConfiguration

    標註在類上,表示這個類是SpringBoot的配置類

    層級關係:SpringBootConfiguration——>@Configuration——>@Component

​ @Configuration:標註在類上,表示這個類是Spring的配置類,至關於XML配置文件

  • @EnableAutoConfiguration

    開啓自動配置功能,簡化了之前繁瑣的配置

    SpringBoot在啓動時會在/META-INF/spring.factories中EnableAutoConfiguration指定的值,將這些值做爲自動配置類添加到容器中,這些自動配置類會幫咱們完成不少配置工做。

  • @ComponentScan

    標註在類上,指定要掃描的包及其子包

3、快速建立SpringBoot項目

1.簡介

使用Spring initializer快速構建SpringBoot項目

2. 基本操做

  • pom文件和主程序類自動生成,直接寫業務邏輯便可
  • resources文件夾的目錄結構

    |-static    存放靜態資源,如js,css,images
    |-template    存放模板引擎,如freemarker、thymeleaf等
    |-application.properties    SpringBoot應用的配置文件,能夠修改默認設置

4、配置文件

1.簡介

SpringBoot的默認全局配置文件有兩種:

  • application.properties
  • application.yml

文件名固定,存放在classpath:/或classpath:/config/目錄下

能夠修改Spring Boot默認配置,具體參考: https://docs.spring.io/spring...

<font color='red'>注意:SpringBoot2.0和1.0的配置有區別,有的配置項已被刪除</font>

2.YAML用法

2.1 簡介

YAML不是一種標記語言,YAML是專門用來寫配置文件的,它以數據爲中心,簡介強大,比xml和properties更適合作配置文件

YAML文件以.yml或.yaml爲後置名

2.2 application.yml
server:
  port: 8081    #寫法:key: value 冒號後面必須有空格
  servlet:
    context-path: /springboot03/
2.3 語法規則
  • 大小寫敏感
  • 使用縮進表示層級關係
  • 縮進時不容許使用Tab鍵
  • 縮進的空格數目不重要,可是要與對應的層級的左側對齊
  • #表示註釋
2.4 基本用法

YAML支持的數據結構有三種:

  • 字面量:單個的,不可再分的值(字符串、數字、boolean值)
  • 對象:鍵值對集合
  • 數組:一組按次序排列的值

三種數據結構的用法:

​ 1.字面量:普通的值,如數字、字符串、布爾值

number: 12.5
str: hello
name: 'tom cruise' #如字符串包含空格及特殊字符須要使用 引號 引發來
name: 'tom \n cruise' #不會對特殊字符進行轉義 結果爲:tom 換行 cruise
name: "tom \n cruise" #對特殊字符進行轉義,會做爲普通字符輸出, 結果爲 tom \n cruise
  1. 對象,也成爲映射Map,包含屬性和值

    # 寫法1:換行寫
    user:
      name: tom
      age: 20
      sex: male
      
    # 寫法2:行內寫法
    user: {name: tom, age: 20, sex: male}
    1. 數組,如List、Set等

      # 寫法1: 一組短橫線開頭的行
      names: 
        - tom
        - jack
        - alice
        
      # 寫法2: 行內寫法
      name: {tom,jack,alice}

3. 爲屬性注入值

經過加載配置文件,爲類中的屬性注入值

3.1 編寫application.yml
user:
  username: admin
  age: 21
  status: true
  birthday: 2019/2/14
  address:
    province: 黑龍江省
    city: 哈爾濱市
  lists:
    - list1
    - list2
    - list3
  maps: {k1: v1,k2: v2}
3.2 建立實體類

User

package com.luyi.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Author: LuYi
 * Date: 2019/10/27 13:49
 * Description: 經過加載配置文件爲當前類中的屬性注入值
 */
// 必須將當前類加入到容器
@Component
// 默認讀取全局配置文件獲取值,當前類中的全部屬性與 user 進行綁定
@ConfigurationProperties(value = "user")
public class User {

    private String username;
    private Integer age;
    private Boolean status;
    private Date birthday;
    private Address address;
    private List<String> lists;
    private Map<String, Object> maps;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

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

    public Boolean getStatus() {
        return status;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public List<String> getLists() {
        return lists;
    }

    public void setLists(List<String> lists) {
        this.lists = lists;
    }

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", status=" + status +
                ", birthday=" + birthday +
                ", address=" + address +
                ", lists=" + lists +
                ", maps=" + maps +
                '}';
    }
}

Address

package com.luyi.bean;

/**
 * Author: LuYi
 * Date: 2019/10/27 13:50
 * Description: 描述
 */
public class Address {

    private String province;
    private String city;

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                '}';
    }
}
3.3 測試
package com.luyi.springboot03config;

import com.luyi.bean.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot03ConfigApplicationTests {

    @Autowired
    private User user;

    @Test
    void contextLoads() {
        System.out.println(user);
    }

}
3.4 添加配置文件處理器依賴(<font color='red'>可選</font>)
<!--配置文件處理器,自動生成元數據信息,編寫配置文件會有提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
3.5 使用properties配置文件
user.username=alice
user.age=22
user.status=false
user.birthday=2019/10/27
user.address.province=黑龍江省
user.address.city=哈爾濱
user.lists=list1,list2,list3
user.maps.k1=v1
user.maps.k2=v2

<font color='red'>注意:在IDEA中默認使用UTF-8編碼,properties文件默認使用ASCII編碼,因此會出現亂碼,可經過勾選解決</font>

優先級:properties > yml

3.6 使用@Value註解注入值
@Value("${user.username}")
private String username;
@Value("${user.age}")
private Integer age;
@Value("${user.status}")
private Boolean status;
@Value("${user.birthday}")
private Date birthday;
//@Value不支持複雜類型封裝
private Address address;
@Value("${user.lists}")
private List<String> lists;
private Map<String, Object> maps;

@Value與@ConfigurationProperties比較:

  • 前者只能夠單值注入,後者能夠批量注入
  • 前者不支持爲複雜類型封裝,後者支持

4.多環境配置

能夠爲不一樣環境提供不一樣配置信息,如開發環境、測試環境、生產環境等

兩種方式:

  • 建立多個properties文件
  • 定義yml文檔塊
4.1 建立多個properties文件

步驟:

​ 1.建立不一樣環境的properties文件

​ 文件命名必須符合aplication-xxx.properties的格式

​ application-dev.properties

server.port=9991

​ application-test.properties

server.port=9992

​ application-prod.properties

server.port=9993

​ 2.在application.properties中指定須要激活的配置

#指定要激活的配置
spring.profiles.active=prod
4.2 定義yml文檔塊

​ 1.在yml中使用三個短橫線定義多個文檔塊

spring:
  profiles: dev
server:
  port: 9991
---
spring:
  profiles: test
server:
  port: 9992
---
spring:
  profiles: prod
server:
  port: 9993

​ 2.在第一個文檔塊指定要激活的環境

spring:
  profiles:
    active: test
---

5.加載外部配置文件

5.1 加載properties屬性文件

​ 問題:@ConfigurationProperties默認是從全局配置文件中讀取值,若是想自定義屬性文件中獲取值怎麼辦?

​ 解決:使用@PropertySource註解加載外部屬性文件

// 必須將當前類加入到容器
@Component
//加載外部的屬性文件
@PropertySource({"classpath:user.properties"})
// 默認讀取全局配置文件獲取值,當前類中的全部屬性與 user 進行綁定
@ConfigurationProperties(value = "user")
public class User{
5.2 加載spring配置文件

​ 問題:若是有信息須要寫道xml文件中,想加載xml文件怎麼辦

​ 解決:使用@ImportResource加載外部配置文件

5.3 使用註解方式添加組件

​ 推薦使用全註解方式向Spring容器添加組件,@Configuration和@Bean

/**
 * Author: LuYi
 * Date: 2019/10/28 14:49
 * Description: 描述
 */
//添加在類上,表示這個類是一個配置類,至關於spring配置文件
@Configuration
public class SpringConfig {

    //標註在方法上,用來向容器中添加組件,將方法的返回值添加到容器中,方法名做爲bean的id
    @Bean
    public Address address(){
        Address address = new Address();
        address.setProvince("山東");
        address.setCity("日照");
        return address;
    }
}

5、SpringBoot自動配置原理

1.執行流程

​ 1.SpringBoot啓動時加載主配置類,使用@EnableAutoConfiguration開啓了自動配置功能

​ 2.@EnableAutoConfiguration中使用了 @Import({AutoConfigurationImportSelector.class})向容器中添加了一些組件(自動配置類)

查看AutoConfigurationImportSelector類中的selectImports方法,再點擊getAutoConfigurationEntry方法中的`<font color='red'>getCandidateConfigurations</font>方法

經過getCandidateConfigurations中的loadFactoryNames方法加載到SpringFactory,

再經過classLoader加載META-INF/spring.factories的配置,從配置中獲取EnableAutoConfiguration(spring-boot-autoconfigure-2.1.9.RELEASE.jar)對應的值。

將這些<font color='red'>自動配置類(xxxAutoConfiguration)</font>添加到容器中

​ 3.經過自動配置類完成自動配置功能。

2. 原理分析

​ 以HttpEncodingAutoConfiguration爲例,就是之前在web.xml中配置的CharacterEncodingFilter過濾器

//表示這是一個配置類,至關於之前編寫的Spring配置文件
@Configuration
//啓用HttpProperties類的ConfigurationProperties功能,經過配置文件爲屬性注入值,並將其添加到容器中
@EnableConfigurationProperties({HttpProperties.class})
//當該應用是web應用時才生效
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
//必須包含CharacterEncodingFilter類才生效
@ConditionalOnClass({CharacterEncodingFilter.class})
//若是配置文件中有spring.http.encoding選項則該配置生效,不然不生效。可是默認已經生效了
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    private final Encoding properties;
    
    //將容器中的HttpProperties注入
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    //將返回的filter添加到容器中,做爲bean
    @Bean
    //若是容器中沒有這個bean纔會生效
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
//從配置文件中獲取指定的值,而後綁定到指定的屬性值
@ConfigurationProperties(
    prefix = "spring.http"
)
public class HttpProperties {
    private Charset charset;
    private Boolean force;
    private Boolean forceRequest;
    private Boolean forceResponse;
    private Map<Locale, Charset> mapping;

注意:

  • 根據當前狀況進行判斷,決定配置類是否生產,若是不知足條件自動配置就不會生效
  • 自動配置類xxAutoConfiguration的屬性是從對應的xxProperties類中獲取
  • xxProperties類中的信息是經過配置文件注入綁定的,能夠經過配置文件指定屬性的值

3.總結

  • SpringBoot在啓動時會加載大量的自動配置類
  • 經過自動配置了向容器中添加組件
  • 經過這些組件自動完成許多功能,從而簡化配置

能夠經過開啓debug模式查看自動配置類的匹配狀況

#開啓debug模式
debug=true

6、Web開發

1.簡介

​ 使用SpringBoot開發Web應用的步驟:

​ 1.建立SpringBoot項目,添加對應的starter

​ 2.在配置文件中指定必要的少許配置

​ 3.編寫業務代碼

​ Web開發的自動配置類WebMvcAutoConfiguration

2.關於靜態資源的映射

2.1 靜態資源的位置

查看WebMvcAutoConfiguration——>addResourceHandlers()——>getStaticLocations()——>staticLocations

靜態資源的默認位置

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

能夠經過上面的文件夾能夠訪問到靜態資源

也能夠在配置文件中本身指定能夠訪問的位置

# 指定靜態資源的位置 存放在根目錄下的public文件夾中
spring.resources.static-locations=classpath:/public
2.2 歡迎頁

查看WebMvcAutoConfiguration—>welcomePageHandlerMapping()—>getWelcomePage()

將index.html頁面放到任意一個靜態資源文件夾中的

2.3 網站圖標

查看WebMvcAutoConfiguration—>內部類FaviconConfiguration—>faviconHandlerMapping

將favicon.ico放到靜態資源的任意文件夾中便可

7、模板引擎

1.簡介

​ 目前Java Web開發推薦使用模板引擎,不建議使用jsp頁面

  • jsp的缺點:本質時Servlet,須要後臺進行編譯,效率較低
  • 模板引擎:不須要編譯,速度快

經常使用的模板引擎:Freemarker、Thymeleaf等

SpringBoot推薦Thymeleaf,且默認不支持jsp,由於jsp必需要打成war包。

<font color='red'>補充:目前主流的web開發更推薦先後端分離,前端使用MVVM框架,Vue.js、Angular、React等</font>

2.Thymeleaf的使用

步驟:

​ 1.添加Thymeleaf的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

​ 2.將html頁面放到templates下

​ templates下的html不能直接訪問,須要使用Controller跳轉,由Thymeleaf進行渲染

ThymeleafAutoConfiguration—>ThymeleafProperties

public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";

​ 默認拼接前綴和後綴

​ 3.使用thymeleaf

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>success</h2>
    <!--使用th:text屬性設置元素中的文本,表達式:${}能夠獲取做用域中的數據-->
    <p th:text="${name}"></p>
</body>
</html>

​ 4.修改頁面後,讓其實時生效

​ 因爲thymeleaf默認啓用了緩存,將緩存禁用掉

#禁用thymeleaf的緩存
spring.thymeleaf.cache=false

<font color='red'>補充:還須要開啓idea的自動編譯,idea默認保存時不會自動編譯</font>

3.語法規則

3.1 經常使用屬性
  • th:text、th:utext

    設置元素中的文本內容

    th:text對特殊字符進行轉義,等價於內聯方式[[${ }]]

    th:utext不對特殊字符集進行轉義,等價於內聯方式[(${ })]

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--th:text、th:utext-->
        <div th:text="${hello}">aaa</div>
        <div th:utext="${hello}">bbb</div>
    
        <!--使用內聯方式,能夠在文本先後添加內容-->
        <div>[[${hello}]]aaa</div>
        <div>[(${hello})]bbb</div>
    </body>
    </html>
  • th:html原生屬性

    用來替換指定的html原生屬性的值

    @RequestMapping("/test2")
    public String test2(Model model){
        model.addAttribute("hello", "<mark>你好</mark>");
    
        model.addAttribute("id", "mydiv");
        model.addAttribute("title", "this is a div");
        return "result";
    }
    <!--th:html原生屬性-->
    <div id="div1" title="這是一個div" th:id="${id}" th:title="${title}">div</div>
  • th:if、th:unless、th:switch、th:case

    條件判斷,相似於if

    <!--th:if、th:unless、th:switch、th:case-->
    <div th:if="${age>=18}">成年</div>
    <p th:unless="${age<18}">成年</p>
    <p th:switch="${role}">
        <span th:case="student">學生</span>
        <span th:case="teacher">老師</span>
        <span th:case="*">其餘</span>
    </p>
    <hr>
  • th:each

    循環,相似於for each

    <!--th:each-->
    <ul>
        <li th:each="name:${names}" th:text="${name}"></li>
    </ul>
  • th:object、th:field

    用於表單數據對象的綁定,將表單綁定到Controller的一個JavaBean參數,常與th:field

    一塊兒使用,須要和*{}選擇表達式配合使用

    <!--th:object、th:field-->
    <h2>修改用戶信息</h2>
    <!--th:object指定對象,th:field指定屬性-->
    <form action="modify" method="post" th:object="${user}">
        編號:<input type="text" th:field="*{id}" readonly> <br>
        姓名:<input type="text" th:field="*{name}"> <br>
        年齡:<input type="text" th:field="*{age}"> <br>
        <input type="submit" value="修改">
    </form>
  • th:fragment

    聲明代碼片斷,經常使用於頁面頭部和尾部的引入

    <!--th:fragment-->
    <header th:fragment="head">
        這是頁面的頭部,導航
    </header>
  • th:include、th:insert、th:replace

    引入代碼片斷,相似於jsp:include

    <!--th:include、th:insert、th:replace-->
    <!--引入templates/include下的header.html頁面中的fragment爲head的片斷-->
    <div th:include="include/header::head"></div>

    三者之間的區別

    th:include會保留本身的標籤,不要th:fragment的標籤(Thymeleaf 3.0 後不推薦使用)

    th:insert保留本身的標籤,也保留th:fragment的標籤

    th:relpace不保留本身的標籤,保留thfragment的標籤

3.2 表達式
  • ${} 變量表達式

    獲取對象的屬性、方法

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--獲取對象的屬性、方法-->
        <div th:text="${user.name}"></div>
        <div th:text="${user['age']}"></div>
        <div th:text="${users[1].name}"></div>
        <!--<div th:text="${users.size()}"></div>-->
        <div>[[${users.size()}]]個</div>
    </body>
    </html>

    使用內置的基本對象,如session和application

    <!--使用內置基本對象-->
    <div th:text="${session.sex}"></div>
    <div th:text="${application.hobby}"></div>

    使用內置的工具對象,如#strings、#dates、#arrays、#lists、#maps等

    <!--使用內置的工具對象-->
    <div th:text="${#strings.startsWith(user.name, 't')}"></div>
    <div th:text="${#strings.substring(user.name, 0, 2)}"></div>
    <div th:text="${#strings.length(user.name)}"></div>
    
    <div th:text="${#dates.createNow()}"></div>
    <div th:text="${#dates.create(2018, 10, 14)}"></div>
    <div th:text="${#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}"></div>
  • *{} 選擇表達式(星號表達式)

    <!--*{}選擇表達式-->
    <div th:object="${user}">
        <div th:text="*{id}"></div>
        <div th:text="*{name}"></div>
        <div th:text="*{age}"></div>
    </div>
  • @{} url表達式

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!--url表達式引入css文件-->
        <link rel="stylesheet" th:href="@{/css/style.css}">
    </head>
    <!--url表達式-->
    <a th:href="@{/findUser(name=${user.name})}">查詢指定的用戶信息</a>
    <a href="product/list.html" th:href="@{/product/list}">商品列表</a>
    <script th:src="@{/js/common.js}"></script>
  • 運算符

    eq gt le == != 三目運算符

4.熱部署

使用SpringBoot提供的devtools實現熱部署

原理:實時監控classpath下文件的變化,若是發生變化自動重啓

配置:添加devtools依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <!--該依賴不傳遞-->
    <optional>true</optional>
</dependency>

8、擴展默認的SpringMVC功能

1.簡介

​ 之前在SpringMVC中能夠經過以下代碼進行視圖跳轉和攔截器:

<mvc:view-controller path="/showLogin" view-name="login"/>
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/hello"/>
        <bean class="com.luyi.interceptor.HelloInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

SpringBoot默認配置默認沒有提供以上功能,須要本身擴展,使用WebMvcConfigurer接口

2.基本操做

​ 步驟:

​ 1.定義一個配置類,實現WebMvcConfigurer接口

​ 2.實現須要的方法

/**
 * Author: LuYi
 * Date: 2019/10/29 17:58
 * Description: 擴展默認的SpringMVC的功能
 * 要求:
 * 1.將該類標記爲配置類
 * 2.實現WebMvcConfigurer接口
 * 3.根據須要實現接口中相應的方法
 *
 * 注意:這個接口中的方法都添加了jdk1.8中的default方法修飾,不強制實現全部方法(jdk1.8新特性)
 * 在SpringBoot1.0中是繼承WebMvcConfigurerAdapter類,SpringBoot2.0是基於jdk1.8的,
 * 因此經過實現WebMvcConfigurer的方式
 */
//將該類設置爲配置類
@Configuration
public class CustomMvcConfig implements WebMvcConfigurer {

    //添加ViewController
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //將訪問login頁面的url設置爲showLogin
        registry.addViewController("/showLogin").setViewName("login");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/test2");
    }
}

9、全局異常處理

1.簡介

​ 當程序出現異常時進行全局處理,SpringBoot默認的異常信息提示:Whitelabel Error Page

兩種方式:

  • 定義錯誤碼頁面
  • 定義異常通知

2.定義錯誤碼頁面

​ 建立 錯誤狀態碼.html頁面,放到templates/error目錄中,當發生錯誤時會自動到該目錄下查找對應的錯誤頁面

​ 能夠建立如 4xx.html5xx.html頁面,用來匹配全部該類型的錯誤(會優先進行精確匹配

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>5xx錯誤</h2>
    <h3>狀態碼:[[${status}]]</h3>
    <h3>異常消息:[[${message}]]</h3>
    <h3>錯誤提示:[[${error}]]</h3>
    <h3>時間戳:[[${timestamp}]]</h3>
</body>
</html>

3.定義異常通知

/**
 * Author: LuYi
 * Date: 2019/10/29 18:45
 * Description: 異常通知:用來處理全局異常
 */
@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(ArithmeticException.class)
    public String arithmetic(Exception e){
        System.out.println("警報:程序出現異常,發短信:" + e.getMessage());
        return "error/5xx";
    }

    @ExceptionHandler(Exception.class)
    public String exception(Exception e){
        System.out.println("警報:程序出現異常,發郵件:" + e.getMessage());
        return "error/5xx";
    }
}

10、關於Servlet容器

1.簡介

​ SpringBoot中默認內置了Servlet:Tomcat

​ 問題:SpringBoot默認以jar包方式啓動內置的Servlet容器,沒有web.xml文件,如何註冊Servlet三大組件:Servlet、Filter、Listener

​ 解決:經過自定義Servlet配置,使用ServletRegistrationBean、FilterRegistrationBean、ServletListenerRegistrationBean

2.註冊Servlet組件

​ 步驟:

​ 1.定義一個配置類

​ 2.自定義一個方法,用來註冊組件

/**
 * Author: LuYi
 * Date: 2019/10/29 19:12
 * Description: 自定義Servlet配置
 */
//將該類聲明爲配置類
@Configuration
public class CustomServletConfig {

    //將方法返回值放到Spring容器
    @Bean
    public ServletRegistrationBean myServlet(){
        ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>();
        //對MyServlet進行註冊
        registrationBean.setServlet(new MyServlet());
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/myServlet");
        registrationBean.setUrlMappings(urls);

        return registrationBean;
    }

    //註冊Filter
    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        //註冊filter
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/showLogin", "/test1");
        return registrationBean;
    }

    //註冊Listener
    @Bean
    public ServletListenerRegistrationBean myListener(){
        ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>();
        registrationBean.setListener(new MyListener());
        return registrationBean;
    }
}

3.使用外部的Servlet容器

3.1 優缺點

​ 使用內置Servlet容器:

​ 優勢:使用簡單,將應用打成jar包

​ 缺點:不支持jsp、可定製性不高

​ 使用外部的Servlet容器

​ 優勢:支持jsp、可定製性高

​ 缺點:須要將應用打成war包

3.2 操做步驟

​ 步驟:

​ 1.建立一個Maven的war工程

​ 有以下三個變化

​ 1.打包方式變爲war

<packaging>war</packaging>

​ 2.將內置的tomcat的scope配置爲provided

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

​ 3.定義了一個SpringBootServletInitializer的子類

/**
 * 要求:
 * 1.必須繼承SpringBootServletInitializer
 * 2.重寫configure()方法
 * 3.調用SpringApplicationBuilder的sources()方法,傳入主程序類的
 */
public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Springboot05WarApplication.class);
    }

}

​ 2.建立web目錄的結構

​ 3.配置前綴和後綴

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

​ 4.配置Tomcat

​ 要使用SpringBoot須要的Tomcat版本

11、SpringBoot數據訪問

1.JDBC

​ 步驟:

​ 1.建立工程,選擇如下模板:web、jdbc、mysql

​ 2.配置數據庫鏈接信息

#指定數據庫鏈接參數
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

#指定數據源
spring.datasource.type=org.apache.commons.dbcp.BasicDataSource

​ 3.測試

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
class Springboot06JdbcApplicationTests {

    @Autowired
    private DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        System.out.println("---------------------------");
        System.out.println("DataSource的類型: " + dataSource.getClass());
        System.out.println("Connection的鏈接: " + dataSource.getConnection());
    }

}

​ 4.配置鏈接池參數

spring.datasource.initialSize=10
spring.datasource.maxActive=100
spring.datasource.minIdle=5
spring.datasource.maxWait=50000

​ 問題:添加上面的參數不生效,由於SpringBoot默認並不支持這些參數(DataSourceProperties)

​ 解決:自定義數據源配置

/**
 * Author: LuYi
 * Date: 2019/10/30 16:09
 * Description: 描述
 */
@Configuration
public class DatasourceConfig {

    @Bean
    //從配置文件中讀取spring.datasource屬性,並注入給數據源的屬性
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
        return new BasicDataSource();
    }
}

​ 5.使用JdbcTemplate操做數據庫

/**
 * Author: LuYi
 * Date: 2019/10/30 16:17
 * Description: 描述
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @RequestMapping("/findAll")
    @ResponseBody
    public List<Map<String, Object>> findAll(){
        String sql = "select * from t_user";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        return list;
    }
}

2.MyBatis

2.1 基本步驟

​ 1.建立工程,先擇如下模塊:web、mybatis

​ 2.配置數據源

#配置DataSource
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    initialSize: 5
    maxActive: 100
    minIdle: 3
    maxWait: 50000
#配置MyBatis
mybatis:
    type-aliases-package: com.luyi.pojo
    mapper-locations: classpath:mapper/*.xml

​ 3.編寫Mapper、Service、Controller

​ 4.配置MyBatisConfig配置類

/**
 * Author: LuYi
 * Date: 2019/10/30 16:57
 * Description: 描述
 */
@Configuration
//掃描MyBatis接口所在的包
@MapperScan("com.luyi.mapper")
public class MyBatisConfig {

    @Bean
    //加載主配置文件,注入配置信息
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource druidDataSource(){
        return new DruidDataSource();
    }
}
2.2 配置PageHelper分頁插件

​ 步驟:

​ 1.添加PageHelper依賴

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.10</version>
</dependency>

​ 2.配置PageHelper的屬性

#配置PageHelper
pagehelper:
  helper-dialect: mysql

​ 3.使用PageHelper

@Override
public PageInfo<User> findByPage(int pageNum, int pageSize) {

    //使用PageHelper設置分頁
    PageHelper.startPage(pageNum, pageSize);

    List<User> users = userMapper.selectAll();

    PageInfo<User> pageInfo = new PageInfo<>(users);

    return pageInfo;
}
2.3 使用MyBatis Plus

​ 參考:http://mp.baomidou.com/

​ 步驟:

​ 1.添加MyBatis Plus的依賴

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.20</version>
</dependency>

​ 2.配置全局配置文件

#配置DataSource
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    initialSize: 5
    maxActive: 100
    minIdle: 3
    maxWait: 50000
#配置MyBatis Plus
mybatis-plus:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: com.luyi.pojo
  global-config:
    db-config:
      #主鍵類型
      id-type: auto
      #字段策略
      field-strategy: not_empty
      #駝峯下劃線轉換
      table-underline: true
      #全局表前綴
      table-prefix: t_
      #刷新mapper神器
      refresh-mapper: true

​ 3 配置MyBatis Plus

/**
 * Author: LuYi
 * Date: 2019/10/31 9:59
 * Description: 描述
 */
@Configuration
@MapperScan("com.luyi.mapper")
public class MyBatisPlusConfig {

    /**
     * 分頁插件,自動識別數據庫類型
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource(){
        return new DruidDataSource();
    }
}

​ 4.編寫Mapper,繼承BaseMapper

/**
 * Author: LuYi
 * Date: 2019/10/31 10:07
 * Description: 繼承BaseMapper接口
 */
public interface UserMapper extends BaseMapper<User> {
}

​ 5.測試

@RunWith(SpringRunner.class)
@SpringBootTest
class Springboot08MpApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
    }

    @Test
    public void add(){
        User user = new User();
        user.setUsername("xxx");
        user.setPassword("111");
        userMapper.insert(user);
        System.out.println("-------------" + user);
    }

    @Test
    public void removeById(){
        int i = userMapper.deleteById(3);
        System.out.println(i);
    }

    @Test
    public void modifyById(){
        User user = new User();
        user.setId(6);
        user.setUsername("zhangsan");
        user.setPassword("123");
        userMapper.updateById(user);
    }

    @Test
    public void findById(){
        User user = userMapper.selectById(1);
        System.out.println(user);
    }

    @Test
    public void findByCondition(){
        //定義條件構造器,用來封裝查詢條件
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.eq("username", "tom");
        wrapper.like("username", "%a%");
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void findByPage(){
        Page<User> page = new Page<>(2, 2);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        IPage<User> userIPage = userMapper.selectPage(page, wrapper.select("id", "username", "password"));
        assertThat(page).isSameAs(userIPage);
        System.out.println("總條數---->" + userIPage.getTotal());
        System.out.println("當前頁數---->" + userIPage.getCurrent());
        System.out.println("當前每頁顯示數---->" + userIPage.getSize());
        System.out.println(userIPage.getRecords());
        System.out.println("----------自帶分頁----------");
    }

}

<font color='red'>補充:lombok的使用</font>

步驟:

​ 1.添加依賴

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>provided</scope>
</dependency>

​ 2.使用lombok提供的註解

/**
 * Author: LuYi
 * Date: 2019/10/30 16:32
 * Description: Lombok的使用
 * Lombok提供了許多註解,標註在類上或者屬性上
 */
@Getter
@Setter
@ToString
@Data   //至關於以上註解
@TableName(value = "t_user")    //指定當前數據庫表的名稱
public class User implements Serializable {

    private Integer id;
    private String username;
    private String password;
}

​ 3.在Idea中安裝lombok插件

​ 因爲源代碼中沒有getter/setter等的定義,Idea沒法識別,能夠安裝lombok插件解決

12、SpringBoot整合Redis

1.簡介

​ Redis是一個內存數據庫,能夠做爲緩存、消息中間件、key-value數據庫等來使用

2.操做

​ 步驟:

​ 1.添加依賴

​ 注意:在SpringBoot1.0中使用的Redis客戶端時Jedis,在SpringBoot2.0中使用的時Lettuce

<!--整合Redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!--SpringBoot2.0使用的Redis客戶端時Lettuce-->
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

​ 2.配置redis

#redis配置
spring.redis.host=192.168.52.128
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=3

​ 3.基本用法

使用SpringDataRedis提供的工具類:StringRedisTemplate、RedisTemplate

​ 封裝JsonUtils

/**
 * Author: LuYi
 * Date: 2019/10/31 17:37
 * Description: Json工具類,基於jackson
 */
public class JsonUtils {

    //獲取jackson對象
    private static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 將對象轉換爲Json字符串
     */
    public static String objectToJson(Object obj){
        try {
            //將對象轉換爲Json字符串
            String jsonStr = objectMapper.writeValueAsString(obj);
            return jsonStr;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 將Json字符串轉換爲對象
     */
    public static <T> T jsonToObject(String jsonStr, Class<T> clazz){
        try {
            T t = objectMapper.readValue(jsonStr, clazz);
            return t;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

​ 測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class Springboot09RedisApplicationTests {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void contextLoads() {
    }

    /**
     * 使用StringRedisTemplate
     * Redis數據類型:String、List、Set、ZSet、Hash
     */
    @Test
    public void test1(){
        /**
         * 操做redis
         */
//        ValueOperations<String, String> value = stringRedisTemplate.opsForValue();
//        ListOperations<String, String> list = stringRedisTemplate.opsForList();
//        SetOperations<String, String> set = stringRedisTemplate.opsForSet();
//        ZSetOperations<String, String> zset = stringRedisTemplate.opsForZSet();
//        HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();

        /**
         * 操做String
         */
//        stringRedisTemplate.opsForValue().set("username", "admin");
//        System.out.println(stringRedisTemplate.opsForValue().get("username"));

        /**
         * 操做List
         */
//        stringRedisTemplate.opsForList().leftPush("name", "tom");
//        stringRedisTemplate.opsForList().leftPushAll("name", "aaa", "bbb", "ccc");
//        System.out.println(stringRedisTemplate.opsForList().range("name", 0, -1));

        /**
         * 存儲對象
         */
        User user = new User();
        user.setId(1001);
        user.setUsername("tom");
        user.setPassword("123");

        //將對象轉換爲json格式
        String jsonStr = JsonUtils.objectToJson(user);
        System.out.println(jsonStr);

        stringRedisTemplate.opsForValue().set("user", jsonStr);

        //獲取jsonStr
        String str = stringRedisTemplate.opsForValue().get("user");

        //將str轉換爲對象
        User u = JsonUtils.jsonToObject(str, User.class);
        System.out.println(u);
    }

    /**
     * 使用redisTemplate
     */
    @Test
    public void test2(){
        redisTemplate.opsForValue().set("sex", "male");
        String sex = redisTemplate.opsForValue().get("sex");
        System.out.println(sex);
    }

}
相關文章
相關標籤/搜索