Spring Boot 統一處理全局異常

      網友投稿 1145 2025-04-10

      目錄

      注解的介紹

      @ControllerAdvice

      @ExceptionHandler攔截異常并統一處理

      代碼實現

      自定義異常

      統一異常處理

      前端返回值類

      測試用例

      如果本篇博客對您有一定的幫助,大家記得留言++哦。

      注解的介紹

      @ControllerAdvice

      @ControllerAdvice注解是spring3.2中新增的注解,學名是Controller增強器,作用是給Controller控制器添加統一的操作或處理。

      這里ControllerAdvice也可以這么理解,其抽象級別應該是用于對Controller進行切面環繞的,而具體的業務織入方式則是通過結合其他的注解來實現的。@ControllerAdvice是在類上聲明的注解,其用法主要有三點:

      1.結合方法型注解@ExceptionHandler,用于捕獲Controller中拋出的指定類型的異常,從而達到不同類型的異常區別處理的目的。

      2.結合方法型注解@InitBinder,用于request中自定義參數解析方式進行注冊,從而達到自定義指定格式參數的目的。

      3.結合方法型注解@ModelAttribute,表示其注解的方法將會在目標Controller方法執行之前執行。

      從上面的講解可以看出,@ControllerAdvice的用法基本是將其聲明在某個bean上,然后在該bean的方法上使用其他的注解來指定不同的織入邏輯。不過這里@ControllerAdvice并不是使用AOP的方式來織入業務邏輯的,而是spring內置對其各個邏輯的織入方式進行了內置支持。

      針對聲明@ExceptionHandler 、 @InitBinder或@ModelAttribute方法的類的@Component @ExceptionHandler , @InitBinder在多個@Controller類之間共享。

      使用@ControllerAdvice注解的類可以明確聲明為 Spring bean 或通過類路徑掃描自動檢測。 所有此類 bean 都根據Ordered語義或@Order / @Priority聲明進行Ordered , Ordered語義優先于@Order / @Priority聲明。 然后在運行時按該順序應用@ControllerAdvice bean。 但是請注意,實現PriorityOrdered @ControllerAdvice bean 的PriorityOrdered不高于實現Ordered @ControllerAdvice bean。 此外, Ordered不適用于范圍內的@ControllerAdvice例如,如果這樣的 bean 已被配置為請求范圍或會話范圍的 bean。 對于處理異常, @ExceptionHandler將在第一個具有匹配異常處理程序方法的通知中被選擇。 對于模型的屬性和數據綁定初始化, @ModelAttribute和@InitBinder方法將遵循@ControllerAdvice秩序。

      注意:對于@ExceptionHandler方法,在特定建議 bean 的處理程序方法中,根異常匹配將優先于僅匹配當前異常的原因。 但是,與較低優先級建議 bean 上的任何匹配(無論是根還是原因級別)相比,更高優先級建議上的原因匹配仍然是首選。 因此,請在具有相應順序的優先建議 bean 上聲明您的主要根異常映射。

      默認情況下, @ControllerAdvice ControllerAdvice 中的方法全局應用于所有控制器。 使用諸如annotations 、 basePackageClasses和basePackages (或其別名value )之類的選擇器來定義目標控制器的更窄子集。 如果聲明了多個選擇器,則應用布爾OR邏輯,這意味著所選控制器應至少匹配一個選擇器。 請注意,選擇器檢查是在運行時執行的,因此添加許多選擇器可能會對性能產生負面影響并增加復雜性。

      @ExceptionHandler攔截異常并統一處理

      配合 @ExceptionHandler注解結合使用,當異常拋到controller層時,可以對異常進行統一的處理,規定返回的json格式或者跳轉到指定的錯誤頁面等.

      @ExceptionHandler的作用主要在于聲明一個或多個類型的異常,當符合條件的Controller拋出這些異常之后將會對這些異常進行捕獲,然后按照其標注的方法的邏輯進行處理,從而改變返回的視圖信息。

      用于處理特定處理程序類和/或處理程序方法中的異常的注解。

      使用此注解注釋的處理程序方法允許具有非常靈活的簽名。 它們可能具有以下類型的參數,按任意順序排列:

      異常參數:聲明為一般異常或更具體的異常。 如果注解本身沒有通過其value()縮小異常類型,這也可用作映射提示

      代碼實現

      自定義異常

      /**

      * 自定義一個異常類,用于處理我們發生的業務異常

      *

      * @author Promsing(張有博)

      * @version 1.0.0

      * @since 2021/11/27 - 20:14

      */

      public class BizException extends RuntimeException {

      private static final long serialVersionUID = 1L;

      /**

      * 錯誤碼

      */

      protected String errorCode;

      /**

      * 錯誤信息

      */

      protected String errorMsg;

      public BizException() {

      super();

      }

      public BizException(FrontResult errorInfoInterface) {

      super(errorInfoInterface.getCode());

      this.errorCode = errorInfoInterface.getMessage();

      this.errorMsg = errorInfoInterface.getMessage();

      }

      public BizException(FrontResult errorInfoInterface, Throwable cause) {

      super(errorInfoInterface.getCode(), cause);

      this.errorCode = errorInfoInterface.getCode();

      this.errorMsg = errorInfoInterface.getMessage();

      }

      public BizException(String errorMsg) {

      super(errorMsg);

      this.errorMsg = errorMsg;

      }

      public BizException(String errorCode, String errorMsg) {

      super(errorCode);

      this.errorCode = errorCode;

      this.errorMsg = errorMsg;

      }

      public BizException(String errorCode, String errorMsg, Throwable cause) {

      super(errorCode, cause);

      this.errorCode = errorCode;

      this.errorMsg = errorMsg;

      }

      public String getErrorCode() {

      return errorCode;

      }

      public void setErrorCode(String errorCode) {

      this.errorCode = errorCode;

      }

      public String getErrorMsg() {

      return errorMsg;

      }

      public void setErrorMsg(String errorMsg) {

      this.errorMsg = errorMsg;

      }

      public String getMessage() {

      return errorMsg;

      }

      @Override

      public Throwable fillInStackTrace() {

      return this;

      }

      }

      統一異常處理

      import com.tfjy.arbackend.enumtool.ResultCodeEnum;

      import com.tfjy.arbackend.enumtool.ResutlMsgEnum;

      import com.tfjy.arbackend.util.FrontResult;

      import org.slf4j.Logger;

      import org.slf4j.LoggerFactory;

      import org.springframework.web.bind.annotation.ControllerAdvice;

      import org.springframework.web.bind.annotation.ExceptionHandler;

      import org.springframework.web.bind.annotation.ResponseBody;

      import javax.servlet.http.HttpServletRequest;

      import java.io.IOException;

      import java.net.InetAddress;

      import java.net.UnknownHostException;

      import java.sql.SQLException;

      Spring Boot 統一處理全局異常

      /**

      * 統一異常處理

      *

      * @author Promsing(張有博)

      * @version 1.0.0

      * @since 2021/11/27 - 20:14

      */

      @ControllerAdvice//使用該注解表示開啟了全局異常的捕獲

      public class GlobalExceptionHandler {

      private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

      /**

      * 處理自定義的業務異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value = BizException.class)

      @ResponseBody

      public FrontResult bizExceptionHandler(HttpServletRequest req, BizException e){

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("發生業務異常!原因是:{}",e.getErrorMsg());

      return FrontResult.getExceptionResult(e.getErrorCode(),e.getErrorMsg());

      }

      /**

      * 處理空指針的異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value =NullPointerException.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, NullPointerException e) {

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("發生空指針異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      /**

      * 處理索引越界異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value =IndexOutOfBoundsException.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, IndexOutOfBoundsException e){

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("索引越界異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      /**

      * 處理類未找到異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value =ClassNotFoundException.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, ClassNotFoundException e) {

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("發生類未找到異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      /**

      * 處理SQL異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value = SQLException.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, SQLException e) {

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("發生SQL異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      /**

      * 處理IO異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value = IOException.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, IOException e) {

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("發生IO異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      /**

      * 處理其他異常

      * @param req

      * @param e

      * @return

      */

      @ExceptionHandler(value =Exception.class)

      @ResponseBody

      public FrontResult exceptionHandler(HttpServletRequest req, Exception e){

      logger.error("URL : " + req.getRequestURL().toString());

      logger.error("HTTP_METHOD : " + req.getMethod());

      logger.error("未知異常!原因是:",e);

      return FrontResult.getExceptionResult(ResultCodeEnum.FAIL.getCode(), ResutlMsgEnum.EXECUTE_FAIL.getMsg());

      }

      }

      前端返回值類

      import com.tfjy.arbackend.enumtool.ResultCodeEnum;

      import lombok.AllArgsConstructor;

      import lombok.Data;

      import lombok.NoArgsConstructor;

      @Data

      @AllArgsConstructor

      @NoArgsConstructor

      public class FrontResult {

      /**

      * 結果狀態碼

      */

      private String code;

      /**

      * 響應結果描述

      */

      private String message;

      /**

      * 返回數據

      */

      private Object data;

      /**

      * 靜態方法,返回前端實體結果

      *

      * @param code 狀態碼

      * @param message 消息

      * @param data 數據

      * @return 前端實體結果

      */

      public static FrontResult build(String code, String message, Object data) {

      return new FrontResult(code, message, data);

      }

      /**

      * 返回成功的結果實體

      *

      * @param message 消息

      * @param data 數據

      * @return 實體

      */

      public static FrontResult getSuccessResult(String message, Object data) {

      FrontResult result = new FrontResult();

      result.code = ResultCodeEnum.SUCCESS.getCode();

      result.message = message;

      result.data = data;

      return result;

      }

      /**

      * 返回無需data的成功結果實體

      *

      * @param message 消息內容

      * @return 返回結果

      */

      public static FrontResult getSuccessResultOnlyMessage(String message) {

      FrontResult result = new FrontResult();

      result.code = ResultCodeEnum.SUCCESS.getCode();

      result.message = message;

      result.data = null;

      return result;

      }

      /**

      * 獲取一個異常結果

      *

      * @param code 錯誤碼

      * @param message 自定義異常信息

      * @return FrontResult

      */

      public static FrontResult getExceptionResult(String code, String message) {

      FrontResult result = new FrontResult();

      result.code = code.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getCode() : code;

      result.message = message.isEmpty() ? ResultCodeEnum.CODE_EXCEPTION.getMsg() : message;

      return result;

      }

      }

      import lombok.AllArgsConstructor;

      @AllArgsConstructor

      public enum ResultCodeEnum {

      // 請求成功

      SUCCESS("0000"),

      // 請求失敗

      FAIL("1111"),

      // EXCEL 導入失敗

      EXCEL_FAIL("1000"),

      // userID 為空

      ID_NULL("1001"),

      // 前端傳的實體為空

      MODEL_NULL("1002"),

      // 更新失敗

      UPDATE_FAIL("1011"),

      // 參數為空

      PARAM_ERROR("400"),

      // 代碼內部異常

      CODE_EXCEPTION("500", "代碼內部異常");

      /**

      * 狀態碼

      */

      private String code;

      public String getCode() {

      return code;

      }

      ResultCodeEnum(String code) {

      this.code = code;

      }

      private String msg;

      public String getMsg() {

      return msg;

      }

      }

      public enum ResutlMsgEnum {

      //查詢成功

      FIND_SUCCESS("查詢成功!"),

      //查詢失敗

      FIND_FAIL("查詢失敗!"),

      //更新成功

      UPDATE_SUCCESS("更新成功"),

      //更新失敗

      UPDATE_FAIL("更新成功"),

      SEND_SUCCESS("發送成功"),

      SEND_FAIL("發送失敗");

      private String msg;

      ResutlMsgEnum(String msg) {

      this.msg = msg;

      }

      public String getMsg() {

      return msg;

      }

      }

      測試用例

      /**

      * 測試用例

      *

      * @author Promsing(張有博)

      * @version 1.0.0

      * @since 2021/11/29 - 9:05

      */

      @Api(tags = {"測試controller"})

      @RequestMapping(value = "/testController")

      @RestController

      public class TestController {

      @ApiOperation(value = "測試null")

      @GetMapping(value = "getNull")

      public FrontResult getNull() {

      int length = 0;

      String name=null;

      length = name.length();

      return FrontResult.build(ResultCodeEnum.SUCCESS.getCode(),

      ResutlMsgEnum.EXECUTE_SUCCESS.getMsg(), length);

      }

      }

      其他異常同理,也可以捕獲。完美,沒問題。全局統一異常處理設置成功。

      如果本篇博客對您有一定的幫助,大家記得留言++哦。

      Spring Spring boot

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:設置網頁瀏覽在哪里(網頁頁面設置在哪)
      下一篇:使用SAP Leonardo上的機器學習服務提取圖片的特征向量
      相關文章
      亚洲αv在线精品糸列| vvvv99日韩精品亚洲| 亚洲国产成人精品久久久国产成人一区二区三区综 | 亚洲午夜久久久影院| 亚洲中文字幕丝袜制服一区| 亚洲成AV人在线观看网址| 亚洲AV成人精品日韩一区18p| 亚洲AV永久无码精品一福利| 亚洲中文无码mv| 亚洲人成网亚洲欧洲无码| 亚洲а∨天堂久久精品9966| 亚洲一日韩欧美中文字幕在线| 亚洲Av高清一区二区三区| 色噜噜亚洲男人的天堂| 亚洲av无码片在线观看| 亚洲成年网站在线观看| 亚洲精品天堂无码中文字幕| 无码亚洲成a人在线观看| 四虎精品亚洲一区二区三区| 国产成人久久精品亚洲小说| 亚洲高清偷拍一区二区三区| 亚洲日韩中文字幕日韩在线| 中文字幕亚洲一区二区va在线| 亚洲一区二区三区香蕉| 亚洲成AV人片在线播放无码| 婷婷亚洲综合五月天小说 | 亚洲成a人片在线观看天堂无码| 国产精品亚洲精品久久精品| 亚洲A丁香五香天堂网| 精品国产日韩亚洲一区| 亚洲色欲久久久综合网| 亚洲电影一区二区三区| 亚洲春黄在线观看| 日韩亚洲产在线观看| 国产精品久久久久久亚洲小说| 亚洲精品动漫人成3d在线| 亚洲中文字幕无码一区| 亚洲视频.com| 亚洲va在线va天堂成人| MM1313亚洲精品无码久久| 久久久久国产亚洲AV麻豆|