SpringBoot圖文教程15—項目異常怎麼辦?「跳轉404錯誤頁面」「全局異常捕獲」

  • 2020 年 3 月 12 日
  • 筆記

有天上飛的概念,就要有落地的實現

  • 概念十遍不如程式碼一遍,朋友,希望你把文中所有的程式碼案例都敲一遍

  • 先贊後看,養成習慣

SpringBoot 圖文教程系列文章目錄

  1. SpringBoot圖文教程1—SpringBoot+Mybatis 環境搭建
  2. SpringBoot圖文教程2—日誌的使用「logback」「log4j」
  3. SpringBoot圖文教程3—「『初戀』情結」集成Jsp
  4. SpringBoot圖文教程4—SpringBoot 實現文件上傳下載
  5. SpringBoot圖文教程5—SpringBoot 中使用Aop
  6. SpringBoot圖文教程6—SpringBoot中過濾器的使用
  7. SpringBoot圖文教程7—SpringBoot攔截器的使用姿勢這都有
  8. SpringBoot圖文教程8—SpringBoot集成MBG「程式碼生成器」
  9. SpringBoot圖文教程9—SpringBoot 導入導出 Excel 「Apache Poi」
  10. SpringBoot圖文教程10—模板導出|百萬數據Excel導出|圖片導出「easypoi」
  11. SpringBoot圖文教程11—從此不寫mapper文件「SpringBoot集成MybatisPlus」
  12. SpringBoot圖文教程12—SpringData Jpa的基本使用
  13. SpringBoot圖文教程13—SpringBoot+IDEA實現程式碼熱部署
  14. SpringBoot圖文教程14—阿里開源EasyExcel「為百萬數據讀寫設計」

前言

本文教程示例程式碼見碼雲倉庫: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的使用),會跳轉到對應的頁面

  • 如果你使用的是webapp目錄,也是一樣的,只要在webapp目錄中存在400.jsp頁面(html也一樣),出現對應的響應狀態的時候(404和500的使用),會跳轉到對應的頁面

以上是默認配置,只要是SpringBoot的項目都會生效,接下來我們來測試一下

  1. 在static目錄下創建error文件夾,400.html以及500.html

  2. 寫一個會報錯的Controller方法 test500

  3. 啟動項目分別訪問一個不存在的路徑【測試】和訪問會報錯的Controller方法,效果如下

自定義錯誤頁面的配置

以上是SpringBoot關於錯誤頁面的默認配置,但是很多時候我們的需求比SpringBoot的默認配置要複雜很多,例如:404頁面不想放在error文件夾下,500錯誤的時候也不想跳轉頁面,而是響應給頁面一個json的數據等。

這個時候需要做的就是修改SpringBoot的默認配置了。

實現的目標:

  • 404的時候跳轉到static下的404頁面
  • 500的時候響應頁面一句話:「後台錯誤 請聯繫管理員」

第一步:創建一個能夠響應 「後台錯誤 請聯繫管理員」 這句話的Controller方法,將404頁面放在static下面【如果是webapp也一樣】

第二步:創建錯誤頁面的配置類,修改默認的配置

  /**   * 錯誤頁面配置   *   * 繼承錯誤頁面註冊器 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頁面

訪問 http://localhost:8802/test500 效果如下:

以上就是跳轉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.寫兩個測試方法 測試全局異常捕獲的效果

訪問 http://localhost:8802/testReturnPage 會跳轉錯誤頁面

訪問 http://localhost:8802/testReturnResult 會返回統一的json數據

總結

恭喜你完成了本章的學習,為你鼓掌!如果本文對你有幫助,請幫忙點贊,評論,轉發,這對作者很重要,謝謝。

讓我們再次回顧本文的學習目標

  • 掌握SpringBoot中異常處理的基本使用

要掌握SpringBoot更多的用法,請持續關注本系列教程。

求關注,求點贊,求轉發

歡迎關注本人公眾號:鹿老師的Java筆記,將在長期更新Java技術圖文教程和影片教程,Java學習經驗,Java面試經驗以及Java實戰開發經驗。