SpringMVC實現全局異常處理器 (轉)


出處:  SpringMVC實現全局異常處理器

  

  我們知道,系統中異常包括:編譯時異常和運行時異常RuntimeException,前者通過捕獲異常從而獲取異常信息,后者主要通過規范代碼開發、測試通過手段減少運行時異常的發生。在開發中,不管是dao層、service層還是controller層,都有可能拋出異常,在springmvc中,能將所有類型的異常處理從各處理過程解耦出來,既保證了相關處理過程的功能較單一,也實現了異常信息的統一處理和維護。這篇博文主要總結一下SpringMVC中如何統一處理異常。 

異常處理思路

  首先來看一下在springmvc中,異常處理的思路

Spring MVC處理異常有4種方式: 

(1)使用Spring MVC提供的簡單異常處理器SimpleMappingExceptionResolver; 

(2)實現Spring的異常處理接口HandlerExceptionResolver 自定義自己的異常處理器; 

(3)使用@ExceptionHandler注解實現異常處理;
(4)使用@ControllerAdvice + @ExceptionHandler

 

下面使用 @ControllerAdvice + @ExceptionHandler來實現

通過 @ControllerAdvice 注解,我們可以在一個地方對所有 @Controller 注解的控制器進行管理。
注解了 @ControllerAdvice 的類的方法可以使用 @ExceptionHandler、 @InitBinder、 @ModelAttribute 注解到方法上,這對所有注解了 @RequestMapping 的控制器內的方法都有效。

  1:@ExceptionHandler:用於捕獲所有控制器里面的異常,並進行處理。
  2:@InitBinder:用來設置 WebDataBinder,WebDataBinder 用來自動綁定前台請求參數到 Model 中。
  3:@ModelAttribute@ModelAttribute 本來的作用是綁定鍵值對到 Model 里,此處是讓全局的@RequestMapping 都能獲得在此處設置的鍵值對。
本文使用 @ControllerAdvice + @ExceptionHandler 進行全局的 Controller 層異常處理。只要設計得當,就再也不用在 Controller 層進行 try-catch 了!

一、經典案例
 需求:希望通過全局統一的異常處理將自定義錯誤碼以json的形式發送給前端。

1、統一返回結果類 ApiResult
首先,定義一個統一結果返回類,最終需要將這個結果類的內容返回給前端。:

/**
 * Api統一的返回結果類
 */
public class ApiResult {

    /**
     * 結果碼
     */
    private String code;
    
    /**
     * 結果碼描述
     */
    private String msg;
    
    
    public ApiResult() {
    }

    public ApiResult(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }
    
    /**
     * 生成一個ApiResult對象, 並返回
     *
     * @param resultCode
     * @return
     */
    public static ApiResult of(ResultCode resultCode) {
        return new ApiResult(resultCode);
    }


    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "ApiResult{" +
                "code='" + code + '\'' +
                ", msg='" + msg + '\'' +
                '}';
    }
    
}

2、錯誤碼枚舉類 ResultCode

有了 ApiResult ,接下來需要定義一個枚舉類, 來包含所有自定義的結果碼。

/**
 * 錯誤碼
 */
public enum ResultCode {
    SUCCESS("0", "success"),
    UNKNOWN_ERROR("0x10001", "unkonwn error"),
    USERNAME_ERROR("0x10002", "username error or does not exist"),
    PASSWORD_ERROR("0x10003", "password error"),
    USERNAME_EMPTY("0x10004", "username can not be empty");
    
    private String code;
    private String msg;
    
    ResultCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

3、自定義業務異常類 BusinessRuntimeException

接下來需要定義我們自己的業務異常類,以后和業務相關的異常通通拋出這個異常類,我們將錯誤碼枚舉變量的值存於其中。

/**
 *    自定義業務異常
 */
public class BusinessRuntimeException extends RuntimeException{
    
    private String code;
    private String msg;
    private ResultCode resultCode;
    
    public BusinessRuntimeException(ResultCode resultCode) {
        super(resultCode.getMsg());
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.resultCode = resultCode;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public ResultCode getResultCode() {
        return resultCode;
    }

    public void setResultCode(ResultCode resultCode) {
        this.resultCode = resultCode;
    }

}

4、全局異常處理類 GlobalExceptionResolver
最后便是定義全局異常處理類。

  1:通過 @ControllerAdvice 指定該類為 Controller 增強類。
  2:通過 @ExceptionHandler 自定捕獲的異常類型。
  3:通過 @ResponseBody 返回 json 到前端。
注意一點:被@ControllerAdvice注解的全局異常處理類也是一個 Controller ,我們需要配置掃描路徑,確保能夠掃描到這個Controller

/**
 *  全局Controller層異常處理類
 */
@ControllerAdvice
public class GlobalExceptionResolver {

    /**
     *處理所有不可知異常
     * @param e 異常
     * @return json結果
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ApiResult handleException(Exception e) {
        System.out.println(e.getMessage());
        return ApiResult.of(ResultCode.UNKNOWN_ERROR);
    }
    
    /**
             * 處理所有業務異常
     * @param e 業務異常
     * @return json結果
     */
    @ExceptionHandler(BusinessRuntimeException.class)
    @ResponseBody
    public ApiResult handleOpdRuntimeException(BusinessRuntimeException e) {
        System.out.println(e.getMessage());
        return ApiResult.of(e.getResultCode());
    }

}

二、測試

1、測試 TestExceptionController

@Controller
@RequestMapping("/test/")
public class TestExceptionController {

    /**
     * 測試返回異常信息
     * @return
     */
    @RequestMapping(value = "exception.do",method = RequestMethod.GET)
    public String returnExceptionInfo() {

        if (1 != 2) {
            // 用戶民錯誤或不存在異常
            throw new BusinessRuntimeException(ResultCode.USERNAME_ERROR);
        }

        return "success";
    }

}

 

效果:

 

其他比較全的文章可以看這個: SpringMVC中的統一異常處理

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM