一文詳解Spring Boot的使用

Code_27發表於2020-10-01


Spring Boot基礎

springbootspring快速開發腳手架,通過約定大於配置的方式,快速構建和啟動spring專案 。解決了複雜的配置混亂的依賴管理

Spring Boot特點:

  • 快速開發spring應用的框架
  • 內嵌tomcat和jetty容器,不需要單獨安裝容器,jar包直接釋出一個web應用
  • 簡化maven配置,parent這種方式,一站式引入需要的各種依賴
  • 基於註解的零配置思想
  • 和各種流行框架,spring web mvc,mybatis,spring cloud無縫整合

Spring Boot基礎配置

(1)建立專案

(2)新增依賴

SpringBoot提供了一個名為spring-boot-starter-parent的構件,裡面已經對各種常用依賴(並非全部)的版本進行了管理,我們的專案需要以這個專案為父工程,這樣我們就不用操心依賴的版本問題了,需要什麼依賴,直接引入座標即可!

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

(3)新增web啟動器

為了讓SpringBoot幫我們完成各種自動配置,我們必須引入SpringBoot提供的自動配置依賴,我們稱為 啟動器

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

自動裝配

(4)管理jdk版本

修改為自己使用的版本即可

<properties>
    <java.version>11</java.version>
</properties>

(5)啟動類

使用JBLSpringBootAppGen外掛引入Appliation啟動類和application.yml配置檔案

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

(6)啟動main執行緒即可

@SpringBootApplication註解

當啟動Application類,就會完成IOC的初始化操作,這個時候就會載入@SpringBootApplication註解,這是一個組合註解:

@Target({ElementType.TYPE}) //註解位置
@Retention(RetentionPolicy.RUNTIME)//作用域
@Documented
@Inherited
// 以上四個是Java中提供的元註解
@SpringBootConfiguration // 本質上就是一個Configuration註解
@EnableAutoConfiguration // 自動裝配的註解
@ComponentScan( //掃描註解(掃描啟動類所在包以及子包)
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

在這裡插入圖片描述

改變banner

什麼是banner?

spring Boot啟動時顯示的字元圖案就是banner。

在這裡插入圖片描述

怎麼改變?

  1. 到專案下的 resources 目錄下新建一個banner.txt
  2. 將自己的banner複製到banner.txt
  3. banner生成網站https://www.bootschool.net/ascii

在這裡插入圖片描述


Spring Boot整合

Spring MVC整合

(1)修改埠號

application.properties中新增配置,後面就可以使用修改後的埠進行訪問了

#修改埠
server.port=8888

(2)訪問靜態資源

ResourceProperties的類,裡面就定義了靜態資源的預設查詢路徑

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

只要靜態資源放在這些目錄中任何一個,SpringMVC都會幫我們處理。習慣會把靜態資源放在 classpath:/resources/static/目錄下

在這裡插入圖片描述
比如:
在這裡插入圖片描述

重新啟動Application類後,直接訪問cat.jpg即可

webapp目錄

resources同級目錄下建立一個webapp目錄,該目錄的型別必須是ResourcesRoot

(3)新增攔截器

攔截器類:實現HandlerInterceptor介面

public class LoginInterceptor implements HandlerInterceptor {

    //使用日誌物件進行處理
    private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        logger.debug("處理器執行前執行!");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        logger.debug("處理器執行後執行!");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.debug("跳轉回執行!");
    }
}

配置Spring Mvc:實現WebMvcConfigurer介面

路徑匹配萬用字元 :

  • ?匹配任何單字元
  • *匹配0或者任意數量的字元
  • /** 匹配0或者更多的目錄
@Configuration
public class MvcConfig implements WebMvcConfigurer{

    /**
    * @Description:  通過Bean註解,將定義的攔截器註冊到Spring容器
    * @Param: []
    * @Return: com.xj0927.interceptor.LoginInterceptor
    * @Author: xj0927
    * @Date Created in 2020/9/28 15:00
    */
    @Bean
    public LoginInterceptor loginInterceptor(){
        return new LoginInterceptor();
    }

    /**
    * @Description: 重寫介面中的addInterceptor方法,新增自定義攔截器
    * @Param: [registry]
    * @Return: void
    * @Author: xj0927
    * @Date Created in 2020/9/28 15:01
    */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 通過registry來註冊攔截器,通過addPathPatterns來新增攔截路徑
        registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**");
    }
}

配置日誌級別:

預設日誌級別為info以上

application.properties中進行配置

#設定com.xj0927包的級別為debug
logging.level.com.xj0927=debug

結構如下:
在這裡插入圖片描述

執行檢視即可!!!

jdbc整合

環境配置

(1)引入jdbc啟動器依賴、MySQL依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
</dependency>

(2)配置連線池

application.properties中配置,不過後面在結構更簡單的yaml格式的application.yml中進行配置

引入jdbc啟動器的時候,SpringBoot會自動引入一個連線池HikariCP,相較於之前用的c3p0

在這裡插入圖片描述

#配置jdbc引數:
spring.datasource.url=jdbc:mysql://localhost:3306/xixi?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=
#下面部分可省略(spring boot可自推斷)
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.minimum-idle=10

普通mybatis整合

配置環境

(1)引入mybatis啟動器

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>

(2)演示使用

前提:在application.properties配置好資料庫連線環境,後面建議使用yaml格式,比較簡單。

實體類:

  • 欄位和屬性對應時,會下劃線駝峰命名
public class User implements Serializable {
    private Long id;

    //自動轉換下換線到駝峰命名user_name -> userName
    private String userName;

    private String password;

    private String name;

    private Integer age;

    // 性別,1男性,2女性
    private Integer sex;

    // 出生日期
    private Date birthday;

    // 建立時間
    private Date created;

    // 更新時間
    private Date updated;

    // 備註
    private String note;
}

dao:在一點與tx mayatismybatis plus不同,不需要繼承Mapper介面

public interface UserDao{
    public List<User> findAll();
}

UserMapper.xml對映檔案:

/resources/mappers資料夾下新增UserMapper.xml檔案

  • 對映介面中的方法
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xj0927.dao.UserDao"> <!--修改處1-->
    <select id="findAll" resultType="com.xj0927.bean.User">
        select * from tb_user
    </select>
</mapper>

配置application.properties

  • 別名掃描,配置後resultType的值就不用寫完整路徑
  • 對映檔案地址
#mybatis配置:
# mybatis 別名掃描
mybatis.type-aliases-package=com.xj0927.bean
# mapper.xml檔案位置,如果沒有對映檔案,請註釋掉
mybatis.mapper-locations=classpath:/mappers/*.xml

啟動類Application

使用普通mybatis提供的構件即可:org.mybatis.spring.annotation.MapperScan

@SpringBootApplication
@MapperScan("com.xj0927.dao")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

另外一種載入介面代理物件的方式,在介面上新增@Mapper註解,但這種方式在介面較多的情況下,每一個都需要新增,比較繁瑣,使用上面的方式,直接掃描介面所在的包。

測試:

  • 測試需要引入測試依賴
  • 測試類上新增@RunWith(SpringRunner.class)@SpringBootTest註解
  • 呼叫物件上新增@Autowired註解
  • 測試的方法上新增@Test註解
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDaoTest {

    @Autowired
    private UserDao dao;

    @Test
    public void findAll() {
        List<User> list = dao.findAll();
        for (User u :list) {
            System.out.println(u);
        }
    }
}

tk mybatis 整合

也叫通用mybatis,可以避免重複的CRUD編寫。

配置環境

(1)引入啟動器依賴

 <dependency>
     <groupId>tk.mybatis</groupId>
     <artifactId>mapper-spring-boot-starter</artifactId>
     <version>2.0.2</version>
 </dependency>

實體類:

  • 預設表名 = 類名 欄位名 = 屬性名
  • 使用@Table(name = "表名")進行表名指定
  • 使用@Column(name = "欄位名")進行欄位指定
  • 使用@Transient不進行欄位對映
@Table(name = "tb_user")//表名與類不一致時
public class User1 implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    //自動轉換下換線到駝峰命名user_name -> userName
	//@Column(name = "user_name")
    private String userName;

    private String password;

    private String name;

    private Integer age;

    // 性別,1男性,2女性
    private Integer sex;

    // 出生日期
    private Date birthday;

    // 建立時間
    private Date created;

    // 更新時間
    private Date updated;

    // 備註
    private String note;
    
    @Transient//不進行欄位對映
    private String info;
}

dao:繼承Mapper介面,不要忘記指定實體物件

繼承Mapper後,就繼承了Mapper的通用crud方法

public interface UserMapper  extends Mapper<User1> {
        public List<User1> findByUser(User1 user1);
}

(2)配置UserMapper.xml

/resources/mappers/路徑下新建UserMapper.xml檔案

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xj0927.dao.UserMapper"> <!--修改地方1-->
    <select id="findByUser" resultType="com.xj0927.bean.User1">
        SELECT * FROM tb_user
        <where>
            <if test="name != null">
            name like '%${name}%'
            </if>
            <if test="note != null">
            or note like '%${note}%'
            </if>
        </where>
    </select>
</mapper>

啟動類:

此時@SpringBootApplication使用tx mybatis的構件:tk.mybatis.spring.annotation.MapperScan

@SpringBootApplication
@MapperScan("com.xj0927.dao")//使用tx mybatis時注意換註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

(3)測試

新增

@Test
public void insert(){
    //新增單條資料{是否會使用預設值}
    User1 user1 = new User1();
    user1.setName("麻子");
    user1.setAge(18);
    //        dao.insert(user1);
    dao.insertSelective(user1);
}

刪除

@Test
public void delete(){
    //1.根據主鍵值刪除元素
    dao.deleteByPrimaryKey(8);

    //2.根據屬性值刪除資料
    User1 user1 = new User1();
    user1.setId(9l);
    dao.delete(user1);
}

修改

@Test
public void update(){
    //根據主鍵值更新
    User1 user1 = new User1();
    user1.setId(9l);
    user1.setName("麻子");
    user1.setAge(15);
    user1.setNote("說明");
    dao.updateByPrimaryKey(user1);
    //        dao.updateByPrimaryKeySelective(user1);
}

檢視

 @Test
public void select(){
    //1.根據主鍵進行查詢
    User1 u = dao.selectByPrimaryKey(1);
    System.out.println(u);

    //2.查詢所有
    List<User1> list = dao.selectAll();
    list.forEach(System.out::println);

    //3.查詢單個資料
    User1 user1 = new User1();
    user1.setName("嘻嘻");
    User1 user2 = dao.selectOne(user1);
    System.out.println(user2);

    //4.根據(屬性條件)查詢符合條件的總條數
    User1 user3 = new User1();
    user3.setName("張三a");
    int i = dao.selectCount(user3);
    System.out.println(i);
}

Example方法

使用Example方法,加一些限制條件,比如使用Example.selectProperties(屬性1,屬性2)查詢指定欄位;

使用example.createCriteria().andLike("name","%a%")模糊查詢。

呼叫crud方法時使用xxxExample(example)即可。

Example example = new Example(User1.class);
example.selectProperties("id","name");
List<User1> list = dao.selectByExample(example);
for (User1 u :list) {
    System.out.println(u);
}

Thymeleaf整合

Thymeleaf是一個跟FreeMarker類似的模板引擎,它可以完全替代JSP

環境配置

(1)引入啟動器

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

SpringBoot會自動為Thymeleaf註冊一個檢視解析器:

在這裡插入圖片描述

Thymeleaf也會根據字首和字尾來確定模板檔案的位置:
在這裡插入圖片描述

將靜態頁面檔案放入/templates/下,

在這裡插入圖片描述

當通過controller層返回users時,會加上字尾.html,指向users.html檔案。

模板快取

Thymeleaf會在第一次對模板解析之後進行快取,極大的提高了併發處理能力。但是這給我們開發帶來了不便,修改頁面後並不會立刻看到效果,我們開發階段可以關掉快取使用:

修改頁面後按快捷鍵: Ctrl + Shift + F9對專案進行rebuild才可以。

# 開發階段關閉thymeleaf的模板快取
spring.thymeleaf.cache=false

使用語法

Thymeleaf一款模板引擎,可代替jsp,實現動靜結合顯示內容。

無網路顯示靜態內容,有網路用後臺得到資料替換靜態內容 。

SpringBoot完美整合。

表示式

前提:

controller層儲存資料到model attribute中,同時跳轉到users[具體路徑:resources/templates,由Thymeleaf指定,同時加上字尾.html]

(1)變數表示式

也叫Spring EL表示式,用來獲取model attribute中的資料

${session.user.name}

注意:必須使用在th標籤之中,這是因為此時渲染到模型中的資料,是採用的Thymeleaf名稱空間

<span>${user.id}</span>
<span th:text="${user.id}"></span>
${user.id} 
1

(2)選擇(*)表示式

th:object屬性指定object物件,然後使用*{}獲取資料

<tr th:each="user : ${users}" th:object="${user}">

同樣*{}必須放在th標籤之中

<span>*{id}</span>
<span th:text="*{id}"></span>
*{id}
1

(3)URL表示式

回話資訊新增到url中,

方式一:url表示式 ,使用@{/地址/(引數)}

<a th:href="@{/delete(id=${user.id},name=*{userName})}">delete</a>

效果:

http://localhost:8888/delete?id=1&name=zhangsan

方式二:文字替換 ,使用|/地址/引數|

<a th:href="|/update/${user.id}|">update</a>

效果:

http://localhost:8888/update/1

方式三:字串拼接 ,使用

"`/地址` + 引數"
<a th:href="'/approve/' + ${user.id}">稽核</a>

效果:

http://localhost:8888/approve/1

常用th標籤
在這裡插入圖片描述
在這裡插入圖片描述

(1)條件判斷ifunless

if表示條件成立才顯示:

<a th:if="*{id > 1}">id大於1才顯示</a>

unless表示條件不成立才顯示:

<a th:unless="*{name == null}">名字不等於空才顯示</a>

兩者結合,使用(if) ? (then) : (else)語法顯示

<a th:text="(${user.id} > 1)? '大於':'小於'"></a>

(2)for迴圈

在定義的迭代物件後面加上status[名字自定義]

<tr th:each="user,status: ${list}" th:object="${user}">

status常用屬性:

  • index:當前迭代物件的序號(從0開始)
  • count:當前迭代的序號(從1開始)
  • size:被迭代物件的大小
  • current:當前迭代變數
  • even/odd:布林值,當前迴圈是否是偶數/奇數(從0開始計算)
  • first:布林值,當前迴圈是否是第一個
  • last:布林值,當前迴圈是否是最後一個
<td th:text="${status.index}"></td>
<td th:text="${status.count}"></td>
<td th:text="${status.size}"></td>
<td th:text="${status.current}"></td>
<td th:text="${status.index}"></td>
<td th:text="${status.even}"></td>

(4)內聯文字inline

先使用th:inline="text"啟用,再使用[[...]]

展示表示式內容:

<td th:inline="text">[[${user.id}]]</td> 

未展示表示式內容:

<td th:inline="none">[[${user.id}]]</td>

(5)內建物件

Thymeleaf提供了一系列Utility物件(內建於Context中),可以通過#直接訪問:

常用:

  • dates : java.util.Date**的功能方法類。
  • calendars : 類似*#dates*,面向java.util.Calendar
  • numbers : 格式化數字的功能方法類
  • strings : 字串物件的功能類,contains,startWiths,prepending/appending等等。
  • objects: 對objects的功能類操作。
  • bools: 對布林值求值的功能方法。
  • arrays:對陣列的功能類方法。
  • lists: 對lists功能類方法
  • sets
  • maps

dates用法:

<td th:text="${#dates.format(#dates.createNow(),'yyyy-MM-dd')}">獲取當前日期並進行格式化輸出</td>

Strings用法:

<span th:text="${#strings.substring(user.name,1,2)}">擷取字串</span>
<span th:text="${#strings.length(user.name)}">獲得長度</span>
<span th:text="${#strings.randomAlphanumeric(2)}">隨機字串</span>
<span th:text="${#strings.equals(user.name, 'hello text....')}">比較兩個字串是否相等</span>

thymeleaf佈局

/resources/templates/目錄下建立footer.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <footer th:fragment="copy(title)">
        &copy; 2020<br>
        <span th:text="${title}">title footer</span>
    </footer>
</body>
</html>

任何地方進行引用都行:

<div th:insert="footer :: copy('哈哈1')"></div>
<div th:replace="footer :: copy('哈哈2')"></div>
<div th:include="footer :: copy('哈哈3')"></div>

在網頁中顯示的原始碼:

<div>
    <footer>
        2020<br>
        <span>哈哈1</span>
    </footer>
</div>

<footer>
    2020<br>
    <span>哈哈2</span>
</footer>

<div>
    2020<br>
    <span>哈哈3</span>
</div>

總結:

  • th:insert:保留自己的主標籤,保留th:fragment的主標籤。
  • th:replace:不要自己的主標籤,保留th:fragment的主標籤。
  • th:include :保留自己的主標籤,不要th:fragment的主標籤。(官方3.0後不推薦)

Mybatis Plus整合

Mybatis-Plus(簡稱MP)是一個Mybatis的增強工具,在 Mybatis 的基礎上只做增強不做改變,避免了我們重複CRUD語句。

新增配置:

(1)引入依賴

<?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.xj0927</groupId>
    <artifactId>mybatis-plus-demo-quickstart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <mybatisplus.version>3.3.2</mybatisplus.version>
        <skipTests>true</skipTests>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

(2)新增配置檔案application.yml

yaml格式結構簡單,推薦使用

這裡使用JBLSpringBootAppGen外掛同時引入Appliation啟動類和application.yml配置檔案

右擊專案:選擇JBLSpringBootAppGen
加粗樣式
在這裡插入圖片描述

演示使用:

這裡使用h2基於記憶體的資料庫,此資料庫一般測試用,比較方便。

jvm啟動時,自動執行指令碼檔案載入相應的資料。

(1)建庫建表

resources資料夾下新建資料夾db用於存放資料庫表結構檔案表資料檔案
在這裡插入圖片描述

schema-h2.sql:表結構檔案

DROP TABLE IF EXISTS user1;

CREATE TABLE user1(
    id BIGINT(20) NOT NULL COMMENT '主鍵ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT(11) NULL DEFAULT NULL COMMENT '年齡',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱',
    PRIMARY KEY (id)
);

data-h2.sql:表資料檔案

DELETE FROM user1;

INSERT INTO user1(id, name, age, email) VALUES
(1,'lisi', 18, 'test1@163.com'),
(2,'zhangsan', 20, 'test22@163.com'),
(3,'wanger', 14, 'test4@163.com'),
(4,'mazi', 28, 'test1@163.com');

(2)配置資料庫

application.yml檔案中進行配置

注意:名字和值之間有一個空格

#DataSource Config
spring:
  datasource:
    driver-class-name: org.h2.Driver
    #配置資料庫表結構
    schema: classpath:db/schema-h2.sql
    #配置資料庫表資料
    data: classpath:db/data-h2.sql
    #連線資料庫[mem:代表記憶體,test資料庫名字可自定義,賬戶密碼自定義]
    url: jdbc:h2:mem:test
    username: root
    password: 123
#日誌輸出
logging:
  level:
        com.xj0927: debug

(3)設定類

實體類

@Data //實體類物件
@TableName("user1")//表名與類名不一致時
@Accessors(chain = true)//在set的同時返回物件:便於鏈式書寫
public class User {

//    @TableId("id_")//主鍵名字不一致
//    @TableId(type = IdType.AUTO)//mysql自增主鍵策略
    @TableId(type = IdType.ASSIGN_ID)//雪花演算法:生成唯一long型的值
    private Long id;

    private String name;
    private Integer age;
    private String email;

    @TableField(exist = false)//表中不存在欄位時
    private String info;

//    public  User setId(Long id) {
//        this.id = id;
//        return this;
//    }
}

dao:繼承BaseMapper介面(裡面包含CRUD方法)

public interface UserMapper extends BaseMapper<User> {//指定實體類
}

啟動類:新增掃描註解@MapperScan("介面所在包名")

@SpringBootApplication
@MapperScan("com.xj0927.dao")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

測試類:在介面中ctrl + shift +t進入測試類

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

    @Autowired //介面物件
    private UserMapper mapper;

    @Test
    public void testSelect1(){
        //呼叫通用方法進行測試
        List list = mapper.selectList(null);
        list.forEach(System.out::println);
        Assert.assertEquals(4,list.size());//使用斷言進行判斷
    }
}

內建CRUD

斷言使用:

  • Assert.assertEquals(期待值,結果值);
  • Assert.assertTrue(條件判斷);

輸出使用:

  • 結果集.forEach(System.out::println)

  • 結果集.forEach( 結果物件 -> {

    System.out.println(結果物件);

    });

(1)新增

id自動生成時,在id屬性上使用@TableId(type = IdType.ASSIGN_ID)雪花演算法生成時,值為long,對應的h2記憶體資料庫的id欄位型別BIGINT

@Test//新增
    public void testInsert(){
        User user = new User();
        user.setName("小紅");
        user.setAge(22);
        user.setEmail("hah@163.com");
        int result = mapper.insert(user);
        
        Assert.assertEquals(1,result);
        mapper.selectList(null).forEach(System.out::println);
    }

(2)刪除

 @Test
    public void testDelete(){
        //1.根據主鍵刪除
        mapper.deleteById(1);
        mapper.selectList(null).forEach(System.out::println);

//      2.批量刪除(使用Wrappers工具類) 
//      刪除age欄位中包含4的資料
        mapper.delete(Wrappers.<User>query().like("age",4));
        mapper.delete(Wrappers.<User>query().gt("age",20));
        mapper.selectList(null).forEach(System.out::println);

        //3.批量刪除(直接建立QueryWrapper物件)
        mapper.delete(new QueryWrapper<User>().like("age",4));
        mapper.selectList(null).forEach(System.out::println);

        //4.批量刪除(使用lambda表示式呼叫實體類方法)
        mapper.delete(new QueryWrapper<User>().lambda().like(User::getAge,4));
        mapper.selectList(null).forEach(System.out::println);
    }

(3)修改

如果想要鏈式設定(set)實體類的屬性,可以新增註解@Accessors(chain = true)

效果相當於:

public  User setId(Long id) {
        this.id = id;
        return this;
    }
@Test
    public void testUpdate(){
        //1.根據id修改
        User user = new User();
        user.setId(1l);
        user.setName("小紅");
        //修改id為1的資料
        mapper.updateById(user);
        mapper.selectList(null).forEach(System.out::println);

        //2.批量修改(通過setter不需要實體物件)
        mapper.update(null,Wrappers.<User>update().set("age",29).like("id",1));
        mapper.selectList(null).forEach(System.out::println);

        //3.批量修改(通過實體物件)
        mapper.update(new User().setName("李四").setAge(43),Wrappers.<User>update().like("id",1));
        mapper.selectList(null).forEach(System.out::println);
    }

(4)檢視

@Test
    public void testSelect(){
        //1.根據id查詢
        System.out.println(mapper.selectById(1));

        //2.查詢一條資料
        System.out.println(mapper.selectOne(Wrappers.<User>query().eq("age",18)));

        //3.投影查詢
        //(只查詢指定欄位)
        mapper.selectList(Wrappers.<User>query().select("name","age")).forEach(user -> {
            System.out.println(user);
        });
        //查詢指定資料
        mapper.selectList(Wrappers.<User>query().eq("age",28)).forEach(user -> {
            System.out.println(user);
        });
    }

分頁

內建分頁:

(1)設定config

@Configuration
public class MybatisPlusPageConfig {
    /**
    * @Description: 分頁外掛
    * @Return: com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor
    * @Author: xj0927
    * @Date Created in 2020/9/29 17:50
    */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        // 開啟count的join優化,只針對left join !!!
        return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
    }
}

(2)測試

使用內建分頁時,進行查詢時需要使用帶xxxPage的方法

@Test//baseMapper自帶的分頁
    public  void testPage(){
        //設定分類規則:引數1表示第幾頁,引數2表示這頁顯示數量
        Page<User> page = new Page<>(1,6);

        //1.顯示按規則分頁後的結果(不加限制條件)
        Page<User> pageResult = mapper.selectPage(page, null);

        //2.顯示按規則分頁後的結果(加限制條件)
        QueryWrapper<User> w = Wrappers.<User>query().like("age", 2);
        Page<User> pageResult = mapper.selectPage(page, w);
        
        //總條數
        System.out.println(pageResult.getTotal());
        //當前總頁數
        System.out.println(pageResult.getPages());
        //當前頁條數
        System.out.println(pageResult.getSize());
    }

自定義xml分頁:

(1)建立UserMapper介面

該介面需要繼承BaseMapper介面

public interface UserMapper extends BaseMapper<User> {

    /**
    * @Description: 對映的介面方法需要使用@Param定義兩個引數:
    *   第1個參數列示分頁物件,第2個參數列示分頁條件
    * @Param: [page, condition]
    * @Return: com.baomidou.mybatisplus.core.metadata.IPage<com.xj0927.bean.User>
    * @Author: xj0927
    * @Date Created in 2020/9/29 18:44
    */
    public IPage<User> selectUserByPage(@Param("p") IPage<User> page, @Param("c") User condition);
}

(2)配置application.yml

#配置mybatis plus
mybatis-plus:
  #別名搜尋
  type-aliases-package: com.xj0927.bean
  #載入對映檔案
  mapper-locations: classpath:/mappers/*.xml

(3)配置UserMapper.xml對映檔案

resources/mappers資料夾下,建立UserMapper.xml,該檔名一定要與介面名相同

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xj0927.dao.UserMapper"> <!--修改地方1-->
    
    <sql id="selectSql">
        SELECT * FROM user1
    </sql>

    <select id="selectUserByPage" resultType="com.xj0927.bean.User">
        <include refid="selectSql"></include>
        <where>
            <if test="c.age !=null">
                age = #{c.age}
            </if>
            <if test="c.email !=null">
                and name like '%${c.name}%'
            </if>
        </where>
    </select>
</mapper>

(4)測試

 @Test//自定義xml分頁
    public void testPage1(){
        //設定分頁規則
        Page<User> page = new Page<>(1,5);

        User user = new User();
        user.setAge(18);
        user.setName("mazi");
        
        //呼叫自定義方法
        IPage<User> pr = mapper.selectUserByPage(page, user);
        
        //總條數
        System.out.println(pr.getTotal());
        //總頁數
        System.out.println(pr.getPages());
        //當前頁條數
        System.out.println(pr.getSize());
        //當前頁數
        System.out.println(pr.getCurrent());
        //分頁規則後的所有條數
        List<User> list = pr.getRecords();
        list.forEach(System.out::println);
    }

pageHelper分頁

(1)引入pageHelper依賴

<dependency> 
    <groupId>com.github.pagehelper</groupId> 
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>

(2)設定config

@Configuration
public class MybatisPlusPageConfig {
    
    /**
    * @Description: 分頁外掛
    * @Return: com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor
    * @Author: xj0927
    * @Date Created in 2020/9/29 17:50
    */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        // 開啟 count 的 join 優化,只針對 left join !!!
        return new PaginationInterceptor().setCountSqlParser(new JsqlParserCountOptimize(true));
    }

    //pageHelper的分頁外掛
    //與上一個分頁外掛不會衝突
    @Bean
    public PageInterceptor pageInterceptor(){
        return new PageInterceptor();
    }

}

(3)創捷UserMapper介面

public interface UserMapper extends BaseMapper<User> {
        public List<User> selectUserByPage2(User user);
}

(4)配置UserMapper.xml對映檔案

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.xj0927.dao.UserMapper">
    <sql id="selectSql">
        SELECT * FROM user1
    </sql>
    
    <select id="selectUserByPage2" resultType="com.xj0927.bean.User">
        <include refid="selectSql"></include>
        <where>
            <if test="age !=null">
                age = #{age}
            </if>
            <if test="name !=null">
                and name like '%${name}%'
            </if>
        </where>
    </select>

</mapper>

(5)測試

 @Test
    public void testPage2(){
        //限制條件
        User user = new User();
        user.setAge(28);
        user.setName("mazi");

        //寫法一:
        PageInfo<User> page =  PageHelper.startPage(2,5).doSelectPageInfo(() ->{
            mapper.selectUserByPage2(user);
        });

        //寫法二:
        //分頁規則:引數1表示第幾頁,引數2表示這頁條數
        PageHelper.startPage(2,5);
        PageInfo<User> page1 = new PageInfo<User>(mapper.selectUserByPage2(user));


        List<User> list = page.getList();
        list.forEach(System.out::println);

        //總條數
        System.out.println(page.getTotal());
        //總頁數
        System.out.println(page.getPages());
        //當頁條數
        System.out.println(page.getSize());
        //每頁行數
        System.out.println(page.getPageSize());
        //起始行數
        System.out.println(page.getStartRow());
        //是否是第一頁
        System.out.println(page.isIsFirstPage());
        //是否是最後一頁
        System.out.println(page.isIsLastPage());
        //是否還有下一頁
        System.out.println(page.isHasNextPage());
        //是否還有上一頁
        System.out.println(page.isHasPreviousPage());
        //頁碼列表
        System.out.println(Arrays.toString(page.getNavigatepageNums()));
    }

Servlet整合

方式一:

(1)自定義Servelt類

@WebServlet(name = "servlet_name",urlPatterns = "/first")
public class MyServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet running");
        PrintWriter writer = resp.getWriter();
        writer.write("success...");
        writer.flush();
        writer.close();
    }
}

(2)啟動類中新增@ServletComponentScan()註解

新增後在SpringBoot啟動的時候會掃描@WebServlet註解

@SpringBootApplication
@MapperScan("com.xj0927.dao")//這是mabatis的掃描註解,不用管
@ServletComponentScan()//servlet 掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

(3)啟動application類測試
在這裡插入圖片描述

方式二:

(1)自定義Servelt類

不新增@WebServlet()註解,放在啟動類中實現

public class MyServlet1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet running");
        PrintWriter writer = resp.getWriter();
        writer.write("success1...");
        writer.flush();
        writer.close();
    }
}

(2)在啟動類application中註冊ServletRegistrationBean物件

@SpringBootApplication
@MapperScan("com.xj0927.dao")//mybatis註解
@ServletComponentScan()//servlet 掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
    //註冊Servlet物件
    @Bean
    public ServletRegistrationBean getRegistrationBean(){
        // 將要新增的Servlet封裝為一個ServletRegistrationBean物件
        ServletRegistrationBean reg = new ServletRegistrationBean(new MyServlet1());
        // 設定對映資訊
        reg.setName("servlet_name");
        reg.addUrlMappings("/second");
        return reg;
    }

}

(3)啟動application類測試

在這裡插入圖片描述

Filter整合

方式一:

(1)自定義Filter類,在過濾器中新增@WebFilter註解

@WebFilter(urlPatterns = "/second")//需要過濾的請求
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("----init----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("________First過濾器執行之前_________");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("________First過濾器執行之後_________");
    }

    @Override
    public void destroy() {
        System.out.println("----destroy----");
    }
}

(2)啟動類中加@ServletComponentScan()掃描註解

與整合Servlet時新增的註解相同

@SpringBootApplication
@MapperScan("com.xj0927.dao")//mybatis掃描註解
@ServletComponentScan()//servlet 掃描註解 //Filter掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

(3)啟動application類測試

測試前提:一定要有Servlet處理請求

在這裡插入圖片描述

方式二:

(1)自定義Filter類

不新增@WebFilter註解

public class MyFilter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("----init2----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("________First過濾器執行之前2_________");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("________First過濾器執行之後2_________");
    }

    @Override
    public void destroy() {
        System.out.println("----destroy2----");
    }
}

(2)在啟動類application中註冊物件

@SpringBootApplication
@MapperScan("com.xj0927.dao")//tx mybatis掃描註解
@ServletComponentScan()//servlet 掃描註解 //Filter掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
    //註冊Servlet物件
    @Bean
    public ServletRegistrationBean getRegistrationBean(){
        // 將要新增的Servlet封裝為一個ServletRegistrationBean物件
        ServletRegistrationBean reg = new ServletRegistrationBean(new MyServlet1());
        // 設定對映資訊
        reg.setName("servlet_name");
        reg.addUrlMappings("/second");
        return reg;
    }
}

(3)啟動application類測試
在這裡插入圖片描述

Listener整合

方式一:

(1)自定義Listener類,新增註解@WebListener

@WebListener
public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("Listener1 : 初始化了....");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("Listener1 : 銷燬了....");
    }
}

(2)在啟動類application中註冊FilterRegistrationBean物件

@SpringBootApplication
@MapperScan("com.xj0927.dao")//使用tx mybatis時注意換註解
@ServletComponentScan()//servlet 掃描註解 //Filter掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }


    //註冊Servlet物件
    @Bean
    public ServletRegistrationBean getRegistrationBean(){
        // 將要新增的Servlet封裝為一個ServletRegistrationBean物件
        ServletRegistrationBean reg = new ServletRegistrationBean(new MyServlet1());
        // 設定對映資訊
        reg.setName("servlet_name");
        reg.addUrlMappings("/second");
        return reg;
    }

    //註冊Filter物件
    @Bean
    public FilterRegistrationBean getFRegistrationBean(){
        FilterRegistrationBean frb = new FilterRegistrationBean(new MyFilter1());
        frb.addUrlPatterns("/second");
        return frb;
    }
}

方式二:

(1)自定義Listener

不新增註解@WebListener

public class MyListener2 implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("Listener2 : 初始化了....");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("Listener1 : 銷燬了....");
    }
}

(2)在啟動類application中註冊ServletListenerRegistrationBean物件

@SpringBootApplication
@MapperScan("com.xj0927.dao")//使用tx mybatis時注意換註解
@ServletComponentScan()//servlet 掃描註解 //Filter掃描註解 //Listener掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }


    //註冊Servlet物件
    @Bean
    public ServletRegistrationBean getRegistrationBean(){
        // 將要新增的Servlet封裝為一個ServletRegistrationBean物件
        ServletRegistrationBean reg = new ServletRegistrationBean(new MyServlet1());
        // 設定對映資訊
        reg.setName("servlet_name");
        reg.addUrlMappings("/second");
        return reg;
    }

    //註冊Filter物件
    @Bean
    public FilterRegistrationBean getFRegistrationBean(){
        FilterRegistrationBean frb = new FilterRegistrationBean(new MyFilter1());
        frb.addUrlPatterns("/second");
        return frb;
    }
    
    //註冊Listener物件
    @Bean
    public ServletListenerRegistrationBean getLRegistrationBean(){
        ServletListenerRegistrationBean slr = new ServletListenerRegistrationBean(new MyListener2());
        return slr;
    }
}

Spring Boot檔案上傳與下載

檔案上傳

(1)建立上傳的表單

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>檔案上傳</title>
</head>
<body>
    <form action="/upload" method="post" enctype="multipart/form-data"> <!--注意這裡-->
        <label>photoName:</label><input type="text" name="photoName"><br/>
        <label>photo:</label><input type="file" name="upload"><br/><!--注意這裡-->
        <input type="submit" value="提交">
    </form>
</body>
</html>

(2)服務端contrtoller處理請求

@RestController("/") //相當於@Controller + @RequestBody
public class MyUploadController {

    @RequestMapping("/upload")
    public String upload(String photoName, MultipartFile upload, HttpServletRequest request) throws IOException {
        System.out.println("photoName:" + photoName + ",檔名稱:" + upload.getOriginalFilename());
        String realPath = request.getRealPath("/uploadFile");
        String filename = upload.getOriginalFilename();
        upload.transferTo(new File(realPath,filename));
        return "success";
    }
}

(3)application.properties中配置上傳引數

#檔案上傳設定引數
spring.servlet.multipart.enabled=true
#單個檔案上傳大小
spring.servlet.multipart.max-file-size=200MB
#一次上傳檔案總的大小
spring.servlet.multipart.max-request-size=200MB

(4)測試

webapp下新建資料夾uploadFile,並隨便建立一個檔案a.txt(是什麼不重要,有就行),在前端頁面選擇檔案提交上傳,成功後,可以在uploadFile下看見該檔案
在這裡插入圖片描述

檔案下載

(1)建立上傳的表單

這一步的目的主要是告訴伺服器,你要下載的檔名稱

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>檔案下載</title>
</head>
<body>
    <form action="/downLoad" method="post" enctype="multipart/form-data">
        <label>name:</label><input type="text" name="name">
        <input type="submit" value="下載">
    </form>
</body>
</html>

(2)伺服器controller處理請求

@RestController("/") //相當於@Controller + @RequestBody
public class MyUploadDownController {
        @RequestMapping("/downLoad")
    public String down(String name, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        String realPath = request.getRealPath("/uploadFile");
        //1.要下載的檔案地址
        realPath = realPath + "/" + name;
        File file = new File(realPath);
        //2.設定響應的頭和客戶端儲存的檔名
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        //attachment 表示以附件的形式響應給客戶端
        response.setHeader("Content-Disposition","attachment;fileName=" + file.getName());

        //複製檔案
        FileInputStream in = null;
        ServletOutputStream out = null;
        try {
            in = new FileInputStream(file);
            out = response.getOutputStream();
            // 迴圈讀取
            byte[] b = new byte[1024];
            int length = 0;
            while((length = in.read(b)) > 0){
                out.write(b,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //關閉流
            try {
                if(in != null){
                    in.close();
                }
                if(out != null){
                    out.flush();
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "success";
    }
}

(3)測試

輸入檔名,即可到伺服器指定資料夾下進行查詢,然後下載

在這裡插入圖片描述

Spring Boot熱部署

(1)什麼是SpringBoot熱部署

SpringBoot熱部署就是在專案正在執行的時候修改程式碼, 卻不需要重新啟動專案。

有了SpringBoot熱部署後大大提高了開發效率,因為頻繁的重啟專案,勢必會浪費很多時間, 有了熱部署後,不用擔心修改程式碼重啟專案了。

(2)SpringBoot熱部署的流程

.pom檔案中匯入 spring-boot-devtools依賴:

<!--SpringBoot熱部署配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

pom.xml中新增外掛:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
                <addResources>true</addResources>
            </configuration>
        </plugin>
    </plugins>
</build>

設定application.properties

#配置專案熱部署
spring.devtools.restart.enabled=true

idea中設定自動編譯:ctrl+alt+s開啟設定(Other Settings 的設定是對整個工作空間專案都啟作用,而Settings的設定是對整個專案啟作用),搜尋Compliler,勾選Build project automatically
在這裡插入圖片描述

按住ctrl + shift + alt + /,出現如下圖所示介面,點選Registry
在這裡插入圖片描述

點選進入後,勾選compiler.automake.allow.when.app.running後關閉即可

在這裡插入圖片描述

通過以上步驟,就完成了SpringBoot專案的熱部署功能!!!

(3)對熱部署測試是否成功:

@RestController
public class HotAutoController {

    @RequestMapping("/index")
    public String index() {
        return "helloworld!";
    }
}

啟動專案,通過瀏覽器輸入地址:http://localhost:8888/index 【埠號選擇你使用的】

結果如下:

在這裡插入圖片描述

新加請求,在不重新啟動專案的情況下測試熱部署是否配置成功:

@RestController
public class HotAutoController {

    @RequestMapping("/index")
    public String index() {
        return "helloworld!";
    }

    @RequestMapping("/say")
    public String say(){
        return "I love Java!";
    }
}

測試新加請求是否成功,瀏覽器輸入http://localhost:8080/say後結果如下:

在這裡插入圖片描述

SpringBoot中的異常處理

1. 自定義錯誤頁面:

SpringBoot預設的處理異常的機制:SpringBoot預設的已經提供了一套處理異常的機制。

一旦程式中出現了異常 SpringBoot會向/errorurl傳送請求。在 springBoot中提供了一個叫 BasicExceptionController 來處理/error 請求,然後跳轉到預設顯示異常的頁面來展示異常資訊:

在這裡插入圖片描述

只需要在resources/templates中新增一個error.html頁面即可:

在這裡插入圖片描述

隨便寫一個錯誤請求,進行測試:

在這裡插入圖片描述

2.@ExceptionHandler處理

  • 針對特定的異常處理
  • 異常處理程式碼和業務程式碼耦合性比較強

Controller類:

@RestController
public class ExceptionHandlerController {
    //請求1:模擬NullPointerException異常
    @RequestMapping("/show1")
    public String show1(){
        String msg = null;
        msg.length(); //NullPointerException
        return "success";
    }
    /**
    * @Description: 如果當前類中出現了NullPointerException異常就會跳轉到本方法對應的view中
    */
    @ExceptionHandler(value = {NullPointerException.class})
    public ModelAndView nullPointerException(Exception e){
        ModelAndView view = new ModelAndView();
        //處理的異常請求
        view.addObject("error",e.toString());
        //處理異常的頁面
        view.setViewName("error1");
        return view;
    }

    //請求2:模擬ArithmeticException異常
    @RequestMapping("/show2")
    public String show2(){
        int i = 0;
        int b = 100;
        System.out.println(b/i); // ArithmeticException
        return "success";
    }

    /**
     * 如果當前類中出現了ArithmeticException異常就會跳轉到本方法對應的view中
     */
    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView arithmeticException(Exception e){
        ModelAndView view = new ModelAndView();
        view.addObject("error",e.toString());
        view.setViewName("error2");
        return view;
    }
}

對應的錯誤處理頁面:

在這裡插入圖片描述

分別請求/show1/show2時,出現異常,跳轉到對應頁面。

3.@ControllerAdvice處理 :

@ControllerAdvice,它是一個Controller增強器,可對controller中被@RequestMapping註解的方法加一些邏輯處理。最常用的就是異常處理。

需要配合@ExceptionHandler使用。當將異常拋到controller時,可以對異常進行統一處理,規定返回的json格式或是跳轉到一個錯誤頁面

自定義異常MyException

@Data
public class MyException extends RuntimeException{
        private long code;//錯誤程式碼
        private String msg;//錯誤資訊

        public MyException(long code, String msg) {
                this.msg = msg;
                this.code = code;
        }
        public MyException(String message) {
                super(message);
        }
}

發生自定義異常後的邏輯處理:

使用@ControllerAdvice實現業務程式碼和系統異常處理程式碼解耦

@ControllerAdvice //全域性異常捕捉處理
public class AdviceException {
    
    @ExceptionHandler(value = {MyException.class})
    public ModelAndView MyExceptionHandler(MyException e){
        ModelAndView view = new ModelAndView();
        view.addObject("code",e.getCode());
        view.addObject("msg",e.getMsg());
        //發生異常後跳轉的頁面
        view.setViewName("error1");
        return view;
    }
}

錯誤頁面:
在這裡插入圖片描述

Controller層:(模擬請求訪問時,出現自定義異常)

@RestController
public class ExceptionController {
    @RequestMapping("/test1")
    public String testException() throws Exception{
        throw new MyException(403,"頁面錯誤");
    }
}

測試:訪問http://localhost:8888/test1
在這裡插入圖片描述

4.SimpleMappingExceptionResolver處理

通過系統提供的異常對映處理實現

SimpleMappingExceptionResolver處理的方法中進行地址對映即可

在處理類application中進行對應異常的地址對映:

@SpringBootApplication
@MapperScan("com.xj0927.dao")//mybatis 掃描註解
@ServletComponentScan()//servlet 掃描註解 //Filter掃描註解 //Listener掃描註解
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }

    /**
     * 異常資訊和對應的 處理地址的 對映
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){

        SimpleMappingExceptionResolver mapping = new SimpleMappingExceptionResolver();
        //不同異常跳轉不同頁面
        Properties p = new Properties();
        p.setProperty("java.lang.NullPointerException","error3");
        p.setProperty("java.lang.ArithmeticException","error4");

        mapping.setExceptionMappings(p);
        return mapping;
    }
}

錯誤頁面:

在這裡插入圖片描述

5.自定義HandlerExceptionResolver全域性異常

只要發生自定義類裡面的異常就進行相應的跳轉處理。新增@Component與實現HandlerExceptionResolver

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        System.out.println("全域性的自定義異常處理觸發了....");
        ModelAndView model = new ModelAndView();
        if(e instanceof  NullPointerException){
            //跳轉頁面
            model.setViewName("error5");
            model.addObject("error","空指標異常");
        }else if(e instanceof  ArithmeticException){
            //跳轉頁面
            model.setViewName("error6");
            model.addObject("error","算數異常");
        }
        return model;
    }
}

SpringBoot中的單元測試

(1)新增spring-boot-starter-test依賴

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

(2)在所需測試的類中 ctrl + shift + t進入測試類
在這裡插入圖片描述

(3)測試類中新增註解(綠色部分)

在這裡插入圖片描述

Freemarker整合【未完成】

FreeMarker是一個基於 Java的模板引擎,最初專注於使用 MVC軟體架構進行動態網頁生成。使用Freemarker 的主要優點是表示層和業務層的完全分離。程式設計師可以處理應用程式程式碼,而設計人員可以處理 html 頁面設計。最後使用freemarker 可以將這些結合起來,給出最終的輸出頁面。
在這裡插入圖片描述

環境配置

(1)新增依賴

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

【待補充。。。】

SpringBoot整合Shiro

SpringBoot整合SpringSecurity

SpringBoot整合Ehcache

SpringBoot整合SpringDataRedis

SpringBoot整合Scheduled

SpringBoot整合Quartz

SpringBoot整合SpringDataJPA

相關文章