深度分析:SpringBoot異常捕獲與封裝處理,看完你學會了嗎?

SpringBoot異常處理

簡介

​ 平常開發過程當中,不免有的程序會由於某些緣由拋出異常,而這些異常通常都是利用try ,catch的方式處理異常或者throw,throws的方式拋出異常無論。這種方法對於程序員來講處理也比較麻煩,對客戶來講也不太友好,因此咱們但願既能方便程序員編寫代碼,不用過多的本身去處理各類異常編寫重複的代碼又能提高用戶的體驗,這時候全局異常處理就顯得很重要也很便捷了,是一種不錯的選擇。前端

1、 全局異常捕獲與處理

Springboot對於異常的處理作了不錯的支持,它提供了兩個可用的註解。程序員

@ControllerAdvice:用來開啓全局的異常捕獲spring

@ExceptionHandler:說明捕獲哪些異常,對哪些異常進行處理。json

@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(value =Exception.class)
    public String exceptionHandler(Exception e){
        System.out.println("發生了一個異常"+e);
        return e.getMessage();
    }
}

上面這段代碼的意思是,只要是代碼運行過程當中有異常就會進行捕獲,並輸出出這個異常。而後咱們隨便編寫一個會發生異常的代碼,測試出來的異常是這樣的。
深度分析:SpringBoot異常捕獲與封裝處理,看完你學會了嗎?後端

​ 這對於先後端分離來講並很差,先後端分離以後惟一的交互就是json了,咱們也但願將後端的異常變成json返回給前端處理,因此就須要統一結果返回和統一異常處理。springboot

2、統一結果返回與統一異常

Result類:封裝返回結果。服務器

public class Result<T> {
    private Integer code;//狀態碼
    private String message;//提示消息
    private T data;//數據

    public Result() {
    }

    /**
     * @param code 響應碼
     * @param message 響應信息
     */
    public Result(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    /**
     * @param code 響應碼
     * @param message 響應信息
     * @param data 數據
     */
    public Result(Integer code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    /**
     * @param resultEnum 自定義枚舉類,包含 code 和 message
     */
    public Result(ResultEnum resultEnum) {
        this.code = resultEnum.getCode();
        this.message = resultEnum.getMessage();
    }

    /**
     * @param resultEnum 自定義枚舉類,包含 code 和 message
     * @param data 數據
     */
    public Result(ResultEnum resultEnum, T data) {
        this.code = resultEnum.getCode();
        this.message = resultEnum.getMessage();
        this.data = data;
    }

    /**
     * 自定義異常返回的結果
     * @param definitionException 自定義異常處理類
     * @return 返回自定義異常
     */
    public static Result<Object> defineError(DefinitionException definitionException) {
        return new Result<>(definitionException.getErrorCode(), definitionException.getErrorMessage());
    }

    /**
     * 其餘異常處理方法返回的結果
     * @param resultEnum 自定義枚舉類,包含 code 和 message
     * @return 返回其餘異常
     */
    public static Result<Object> otherError(ResultEnum resultEnum) {
        return new Result<>(resultEnum);
    }

    //這裏寫get和set方法
}

注意:其中省略了get,set方法。mvc

ResultEnum:自定義枚舉類。app

public enum ResultEnum {
    // 數據操做定義
    SUCCESS(200, "成功"),
    TIME_OUT(130, "訪問超時"),
    NO_PERMISSION(403, "拒絕訪問"),
    NO_AUTH(401, "未經受權訪問"),
    NOT_FOUND(404, "沒法找到資源"),
    METHOD_NOT_ALLOWED(405, "不支持當前請求方法"),
    SERVER_ERROR(500, " 服務器運行異常"),
    NOT_PARAM(10001, "參數不能爲空"),
    NOT_EXIST_USER_OR_ERROR_PASSWORD(10002, "該用戶不存在或密碼錯誤"),
    NOT_PARAM_USER_OR_ERROR_PASSWORD(10003, "用戶名或密碼爲空");;
    /**
     * 響應碼
     */
    private final Integer code;

    /**
     * 響應信息
     */
    private final String message;

    /**
     * 有參構造
     * @param code  響應碼
     * @param message 響應信息
     */
    ResultEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

注意:枚舉類中定義了常見的錯誤碼以及錯誤的提示信息。這裏咱們就定義好了統一的結果返回,其中裏面的靜態方法是用來當程序異常的時候轉換成異常返回規定的格式。前後端分離

DefinitionException:自定義異常處理類。

//@ControllerAdvice+@ResponseBody,開啓全局的異常捕獲,返回JSON
@RestControllerAdvice 
public class GlobalExceptionHandler {

    /**
     * 處理自定義異常
     * @return Result
     * @ExceptionHandler 說明捕獲哪些異常,對那些異常進行處理。
     */
    @ExceptionHandler(value = DefinitionException.class)
    public Result<Object> customExceptionHandler(DefinitionException e) {
        return Result.defineError(e);
    }

    /**
     * 處理其餘異常
     * @return Result
     */
    @ExceptionHandler(value = Exception.class)
    public Result<Object> exceptionHandler(Exception e) {
        return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR);
    }
}

說明:將對象解析成json,是爲了方便先後端的交互。

3、代碼測試與結果

測試類

ResultController:測試的controller類

@RestController
public class ResultController {

    //獲取學生信息
    @GetMapping("/student")
    public Result<Student> getStudent() {
        Student student = new Student();
        student.setId(1);
        student.setAge(18);
        student.setName("XuWwei")
        return new Result<>(ResultEnum.SUCCESS, student);
    }

    //自定義異常處理
    @RequestMapping("/getDeException")
    public Result<Object> DeException() {
        throw new DefinitionException(400, "我出錯了");
    }

    //其餘異常處理
    @RequestMapping("/getException")
    public Result Exception(){
        Result result = new Result();
        int a=1/0;
        return result;
    }

Student:學生類

public class Student {
    /**
     * 惟一標識id
     */
    private Integer id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 年齡
     */
    private Integer age;
}

注意:其中省略了get,set方法。

測試結果

啓動項目,一個一個測試

  1. 正常測試
    深度分析:SpringBoot異常捕獲與封裝處理,看完你學會了嗎?

能夠看到數據是正常返回json,沒有異常。

  1. 自定義異常

深度分析:SpringBoot異常捕獲與封裝處理,看完你學會了嗎?

能夠看到這個自定義的異常被捕獲到了,而且返回了一個json。

  1. 其餘異常
    深度分析:SpringBoot異常捕獲與封裝處理,看完你學會了嗎?

能夠看到這個異常被捕獲到了,而且返回了一個json。

注意:這種方法是不能處理404異常的,捕獲不到。

4、404異常特殊處理

一、修改配置文件

​ 默認狀況下,SpringBoot是不會拋出404異常的,因此@ControllerAdvice也不能捕獲到404異常。咱們能夠經過配置文件來讓這個註解能捕獲到404異常,在application.properties中添加如下配置:

#當發現404異常時直接拋出異常
spring.mvc.throw-exception-if-no-handler-found=true
#關閉默認的靜態資源路徑映射,這樣404不會跳轉到默認的頁面
spring.resources.add-mappings=false

可是關閉默認的靜態資源路徑映射會讓靜態資源訪問出現問題,也就是不適合先後端一體的狀況。

可是咱們能夠手動配置靜態資源路徑映射,就能正常訪問靜態資源了。

@Configuration
public class ResourceConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //能夠訪問localhost:8080/static/images/image.jpg
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

二、修改error跳轉路徑

​ 關閉默認的靜態資源路徑映射顯然不太合理,可能會致使其餘的錯誤發生,因此也能夠經過修改默認錯誤頁面的跳轉路徑來達到咱們的目的。

在GlobalExceptionHandler類中添加NotFoundExceptionHandler類,這個類繼承了ErrorController,能夠重寫error的跳轉路徑。

//處理404NotFoundException
@Controller
class NotFoundExceptionHandler implements ErrorController {

    //設置錯誤頁面路徑
    @Override
    public String getErrorPath() {
        return "/error";
    }

    //當訪問error路徑時,返回一個封裝的異常的Json
    @RequestMapping("/error")
    @ResponseBody
    public Result<Object> error() {
        return Result.otherError(ResultEnum.NOT_FOUND);
    }
}

5、拓展異常類

​ GlobalExceptionHandler的exceptionHandler方法將全部的異常統一返回500系統錯誤,這不符合咱們的設想,因此咱們能夠經過判斷異常的類型,來返回不一樣的值。

將exceptionHandler改爲如下代碼:

/**
  * 處理其餘異常
  * @return Result
  */
@ExceptionHandler(value = Exception.class)
public Result<Object> exceptionHandler(Exception e) {
    if (e instanceof NullPointerException){
        //捕獲空指針異常
        return Result.otherError(ResultEnum.NOT_PARAM);
    }else if (e instanceof IllegalAccessException){
        //非法訪問異常
        return Result.otherError(ResultEnum.NO_PERMISSION);
    } else{
        return Result.otherError(ResultEnum.SERVER_ERROR);
    }
}

注意:更多異常能夠經過else if來細分。

6、總結

​ springboot的異常處理,須要經過@ControllerAdvice註解以及 @ExceptionHandler註解,來攔截全部的異常,並經過一個封裝返回值返回。可是,這兩個註解沒法捕獲404NotFound異常,由於SpringBoot默認是不會拋出404異常的,因此要經過繼承ErrorController來修改404異常的跳轉路徑,達到捕獲404異常的目的。

相關文章
相關標籤/搜索