SpringBoot圖文教程15—專案異常怎麼辦?「跳轉404錯誤頁面」「全域性異常捕獲」
阿新 • • 發佈:2020-03-13
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205829155-764801728.png)
> **有天上飛的概念,就要有落地的實現**
>
> - 概念十遍不如程式碼一遍,朋友,希望你把文中所有的程式碼案例都敲一遍
>
> - 先贊後看,養成習慣
**SpringBoot 圖文教程系列文章目錄**
1. [SpringBoot圖文教程1—SpringBoot+Mybatis 環境搭建](https://mp.weixin.qq.com/s/phk6j3ChBP-kPtS2xZeEZg)
2. [SpringBoot圖文教程2—日誌的使用「logback」「log4j」](https://mp.weixin.qq.com/s/7Mw_xhFF4Q5NtdtcsHc67Q)
3. [SpringBoot圖文教程3—「‘初戀’情結」整合Jsp](https://mp.weixin.qq.com/s/BYzVg5NBcF_ou_PyX8ygag)
4. [SpringBoot圖文教程4—SpringBoot 實現檔案上傳下載](https://mp.weixin.qq.com/s/6ctykPo3eDBEB7YsC0PAZw)
5. [SpringBoot圖文教程5—SpringBoot 中使用Aop](https://mp.weixin.qq.com/s/17qMRlv_mUfwkcVD05Bh2g)
6. [SpringBoot圖文教程6—SpringBoot中過濾器的使用](https://mp.weixin.qq.com/s/r2BO4UMNRAw_REA6nNFLKw)
7. [SpringBoot圖文教程7—SpringBoot攔截器的使用姿勢這都有](https://mp.weixin.qq.com/s/YpDhuOTpt1vjYjnhnK8YdQ)
8. [SpringBoot圖文教程8—SpringBoot整合MBG「程式碼生成器」](https://mp.weixin.qq.com/s/uGYO4fkw03Kxpfp_PIA8rQ)
9. [SpringBoot圖文教程9—SpringBoot 匯入匯出 Excel 「Apache Poi」](https://mp.weixin.qq.com/s/BXfxhO5rFFg6XZQ0rZgGMg)
10. [SpringBoot圖文教程10—模板匯出|百萬資料Excel匯出|圖片匯出「easypoi」](https://mp.weixin.qq.com/s/8Yqfn27UCFP2lU3_IYb5AQ)
11. [SpringBoot圖文教程11—從此不寫mapper檔案「SpringBoot整合MybatisPlus」](https://mp.weixin.qq.com/s/8KG5Wj77MYEUCIRFqWBdPQ)
12. [SpringBoot圖文教程12—SpringData Jpa的基本使用](https://mp.weixin.qq.com/s/gPfSjBj1hMWf23J50d5Z_g)
13. [SpringBoot圖文教程13—SpringBoot+IDEA實現程式碼熱部署](https://mp.weixin.qq.com/s/DYP_12V01D0NJGEBdwK9Ew)
14. [SpringBoot圖文教程14—阿里開源EasyExcel「為百萬資料讀寫設計」](https://mp.weixin.qq.com/s/FNuL3maNtiFCVR7hREYpLA)
## 前言
> 本文教程示例程式碼見碼雲倉庫:https://gitee.com/bingqilinpeishenme/boot-demo
異常處理在Java中是一種很常規的操作,在程式碼中我們常用的方法是try catch或者上拋異常。
但是,如果Controller發生異常了怎麼辦?業務層的異常可以在Controller捕獲,Controller丟擲的異常怎麼捕獲?SpringMvc的異常怎麼捕獲?
這個時候常見的操作有兩種:
1. 跳轉錯誤頁面,例如:找不到路徑的時候跳轉404,程式碼報錯的時候跳轉500等
2. 響應統一的報錯資訊,使用Result物件(自定義的實體類)封裝錯誤碼,錯誤描述資訊響應【分散式服務呼叫的時候推薦使用】
今天我們就簡單的來講解一下SpringBoot中如何進行異常處理,跳轉404或者封裝錯誤資訊響應。
## 跳轉錯誤頁面
### SpringBoot 錯誤頁面的預設配置
在SpringBoot中 error page錯誤頁面是有預設配置的,預設配置是這樣
- 如果在static目錄中存在error資料夾,並且資料夾中存在400.html,或者500.html,出現對應的響應狀態的時候(404和500的使用),會跳轉到對應的頁面
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205829501-641943563.png)
- 如果你使用的是webapp目錄,也是一樣的,只要在webapp目錄中存在400.jsp頁面(html也一樣),出現對應的響應狀態的時候(404和500的使用),會跳轉到對應的頁面
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205830228-839152814.png)
以上是預設配置,只要是SpringBoot的專案都會生效,接下來我們來測試一下
1. 在static目錄下建立error資料夾,400.html以及500.html
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205829501-641943563.png)
2. 寫一個會報錯的Controller方法 test500
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205831066-568235152.png)
3. 啟動專案分別訪問一個不存在的路徑【測試】和訪問會報錯的Controller方法,效果如下
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205831501-1686966401.png)
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205831972-562426817.png)
### 自定義錯誤頁面的配置
以上是SpringBoot關於錯誤頁面的預設配置,但是很多時候我們的需求比SpringBoot的預設配置要複雜很多,例如:404頁面不想放在error資料夾下,500錯誤的時候也不想跳轉頁面,而是響應給頁面一個json的資料等。
這個時候需要做的就是修改SpringBoot的預設配置了。
> **實現的目標:**
> - 404的時候跳轉到static下的404頁面
> - 500的時候響應頁面一句話:“後臺錯誤 請聯絡管理員”
**第一步:建立一個能夠響應 “後臺錯誤 請聯絡管理員” 這句話的Controller方法,將404頁面放在static下面【如果是webapp也一樣】**
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205832429-1008488395.png)
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205832732-1881453929.png)
**第二步:建立錯誤頁面的配置類,修改預設的配置**
```
/**
* 錯誤頁面配置
*
* 繼承錯誤頁面註冊器 ErrorPageRegistrar
*/
@Configuration
public class ErrorConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
/**
* 配置錯誤頁面
*
* ErrorPage 有兩個引數
* 引數1 響應狀態碼 NOT_FOUND 404 INTERNAL_SERVER_ERROR 500
* 引數2 出現響應狀態碼的時候的跳轉路徑 可以自定義跳轉路徑
*/
ErrorPage error404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
ErrorPage error500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/testData");
/**
* 將ErrorPage 註冊到註冊器中
*/
registry.addErrorPages(error404,error500);
}
}
```
**第三步:啟動專案,可以看到如下效果**
訪問不存在的路徑,跳轉404頁面
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205833097-2000763405.png)
訪問 http://localhost:8802/test500 效果如下:
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205833512-650920607.png)
以上就是跳轉404和統一響應資料的操作,但是還有問題,什麼問題呢?
以上的操作實際上沒有針對異常進行捕獲,而是根據響應的狀態碼進行不同的處理的,那麼如果才能針對不同的異常進行捕獲呢?這就要用到全域性異常捕獲了。
## 全域性異常捕獲
還記得文章開頭說過的第二個場景嗎?使用Result物件(自定義的實體類)統一封裝異常狀態碼,異常資訊,進行返回。通過全域性異常捕獲就可以實現。
> 測試的要求是:
> - 捕獲自定義異常,封裝Result物件以json的格式響應
> - 捕獲自定義異常,跳轉到錯誤頁面
### 1.自定義異常
在應用開發過程中,除系統自身的異常外,不同業務場景中用到的異常也不一樣,很多時候需要自定義異常,所以我們自定義兩個異常,分別是:
- ErrorReturnResultException 如果出現這個異常,就返回統一Result物件
- ErrorReturnPageException 如果出現這個異常,就跳轉錯誤頁面
**ErrorReturnResultException**
```
package com.lu.bootexception.exception;
public class ErrorReturnResultException extends RuntimeException {
/**
* 錯誤碼
*/
private int code;
public ErrorReturnResultException() {
}
public ErrorReturnResultException(String message) {
super(message);
}
public ErrorReturnResultException(String message, int code) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
```
**ErrorReturnPageException**
```
package com.lu.bootexception.exception;
public class ErrorReturnPageException extends RuntimeException {
/**
* 錯誤碼
*/
private int code;
public ErrorReturnPageException() {
}
public ErrorReturnPageException(String message, int code) {
super(message);
this.code = code;
}
public ErrorReturnPageException(String message) {
super(message);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
```
### 2.自定義響應實體
定義返回的異常資訊的格式,這樣異常資訊風格更為統一
```
package com.lu.bootexception.exception;
import lombok.Data;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private int code;
private String message;
}
```
### 3.全域性異常捕獲實現
利用Spring的API定義一個全域性異常處理的類,程式碼和註釋如下:
```
package com.lu.bootexception.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @ControllerAdvice 增強Controller的註解 可以實現全域性異常捕獲
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* @ExceptionHandler 指明要捕獲那個異常
* 不加@ResponseBody 會使用檢視解析器跳轉頁面
* 形參處是Exception 簡單來說就是會把捕獲到的異常通過形參傳入方法中
*/
@ExceptionHandler(ErrorReturnPageException.class)
public String errorReturnPageException(Exception e){
// 列印錯誤資訊
System.out.println(e.getMessage());
// 跳轉500頁面
return "forward:/500.html";
}
/**
* 捕獲 ErrorReturnResultException 異常
* 通過 @ResponseBody 註解響應資料 會以json的格式響應
*/
@ExceptionHandler(ErrorReturnResultException.class)
@ResponseBody
public Result errorReturnResultException(final Exception e) {
ErrorReturnResultException exception = (ErrorReturnResultException) e;
/**
* Result 中可以寫入自定義的異常狀態碼
*/
return new Result(5001, exception.getMessage());
}
/**
* 捕獲 RuntimeException 異常
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Result runtimeExceptionHandler(final Exception e) {
RuntimeException exception = (RuntimeException) e;
/**
* Result 中可以寫入自定義的異常狀態碼
*/
return new Result(4004, exception.getMessage());
}
}
```
> 程式碼中用到的註解
> - **@ControllerAdvice** 捕獲丟擲的異常,如果新增 `@ResponseBody` 返回資訊則為`JSON`格式。
> - **@RestControllerAdvice** 相當於 `@ControllerAdvice` 與 `@ResponseBody` 的結合體。
> - **@ExceptionHandler** 指明要捕獲那個異常
>
### 4.寫兩個測試方法 測試全域性異常捕獲的效果
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205834057-826215414.png)
訪問 http://localhost:8802/testReturnPage 會跳轉錯誤頁面
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205834826-1556641335.png)
訪問 http://localhost:8802/testReturnResult 會返回統一的json資料
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205835239-1432527185.png)
## 總結
**恭喜你完成了本章的學習,為你鼓掌!如果本文對你有幫助,請幫忙點贊,評論,轉發,這對作者很重要,謝謝。**
![](https://img2020.cnblogs.com/other/1003051/202003/1003051-20200312205835661-1791815467.gif)
讓我們再次回顧本文的學習目標
> * 掌握SpringBoot中異常處理的基本使用
要掌握SpringBoot更多的用法,請持續關注本系列教程。
## 求關注,求點贊,求轉發
> 歡迎關注本人公眾號:鹿老師的Java筆記,將在長期更新Java技術圖文教程和視訊教程,Java學習經驗,Java面試經驗以及Java實戰開發