springboot全局統一異常處理及全局統一返回

1、全局統一返回格式:

項目開發形式爲前後端分離,採用Restful接口形式開發,對異常的處理與業務數據統一以json形式返回。接口統一json格式的response返回格式一般定義如下:

{
    "code": 0,
    "msg": "成功",
    "data": {
        "name": "阿飯",
        "age": 16
    }
}

1.1、定義通用的返回類:

package com.fun.common.tools.result;

import com.fun.common.constants.CommonConstants;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;

@Data
public class CustomResponse<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private int code;
    private String msg;
    private T data;

    public CustomResponse(int code) {
        this.code = code;
        this.msg = CommonConstants.SUCCESS;
    }

    public CustomResponse(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public CustomResponse(int code, T data) {
        this.code = code;
        this.data = data;
        this.msg = CommonConstants.SUCCESS;
    }
}

1.2 定義返回值(此處以失敗碼舉例)

package com.fun.common.tools.exception.result;

public enum ErrorResultCode {

    NAME_NOT_NULL(10001, "姓名不能爲空"),
    AGE_NOT_NULL(10002, "年齡不能爲空")
    NULL_POINT_EXCEPTION(10003,"空指針異常"),
    CUSTOM_EXCEPTION(10004,"具體的自定義異常");

    private int code;
    private String msg;
    
    WorkDataResultCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    
    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

1.3、定義接口返回的數據模型

package com.fun.common.tools.result;

import com.fun.common.tools.exception.result.ErrorResultCode ;

public class Result {

    public static CustomResponse success() {
        return new CustomResponse(0);
    }

    public static CustomResponse fail() {
        return new CustomResponse(-1);
    }

    public static CustomResponse success(Object data) {
        return new CustomResponse(0, data);
    }

    public static CustomResponse fail(String msg) {
        return new CustomResponse(-1, msg);
    }

    public static CustomResponse fail(ErrorResultCode resultCode) {
        return new CustomResponse(resultCode.getCode(), resultCode.getMsg());
    }

    public static CustomResponse fail(int code, String msg) {
        return new CustomResponse(code, msg);
    }
}

1.4、全局統一返回測試類

package com.fun.test.controller;

import com.fun.common.tools.exception.CustomException;
import com.fun.common.tools.exception.result.ErrorResultCode;
import com.fun.common.tools.result.CustomResponse;
import com.fun.common.tools.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @ClassName: TestController 
 * @Author: fun
 * @Description: 測試類
 * @Date: 2020/4/16 10:24
 * @Version: 1.0.0
 * 可愛之人必有可胖之處
 * ღღ ∧_∧
 * ฅ(՞•🐽•՞)ฅ
 */

@RestController
@Slf4j
@RequestMapping("/test")
public class TestController {
    @PostMapping(value = "/test")
    public CustomResponse test(User user) {
        if (StringUtil.isEmpty(user.getName())) {
            return Result.fail(ErrorResultCode.NAME_NOT_NULL);
        }
        user.setName("阿飯");
        user.setAge(16)
        return Result.success(user);
    }
}

1.5 全局postman測試結果

1.5.1、成功:

當傳入{"name": "阿飯", "age": 16},返回結果爲:

{
    "code": 0,
    "msg": "成功",
    "data": {
        "name": "阿飯",
        "age": 16
    }
}

1.5.2、失敗:

當傳入{"name": "", "age": 16},返回結果爲:

{
    "code": -1,
    "msg": "姓名不能爲空",
    "data": null
}

1.6 引申:ResponseBodyAdvice 返回統一攔截處理

1.6.1ResponseBodyAdvice

在 spring 4.1 新加入的一個接口,在消息體被HttpMessageConverter寫入之前允許Controller 中 @ResponseBody修飾的方法或ResponseEntity調整響應中的內容,比如做一些返回處理。

ResponseBodyAdvice接口裏一共包含了兩個方法

1.6.2、supports

該組件是否支持給定的控制器方法返回類型和選擇的{@code HttpMessageConverter}類型

1.6.3、beforeBodyWrite

在選擇{@code HttpMessageConverter}之後調用,在調用其寫方法之前調用。

1.6.4 、 全局返回統一攔截處理類

@Slf4j
@RestControllerAdvice
public class GlobalDataAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public Object beforeBodyWrite(Object arg0, MethodParameter arg1, MediaType arg2,
                                  Class<? extends HttpMessageConverter<?>> arg3, ServerHttpRequest arg4, ServerHttpResponse arg5) {

        final String returnTypeName = arg1.getParameterType().getName();
        // 可判斷方法返回類型,做出相應返回處理。例如:測試類中void的返回類型,獲取到以後自動裝載成全局統一返回格式。此處可做
        if ("void".equals(returnTypeName)) {
            return ResponseUtils.success();
        }
        if ("com.fun.common.tools.result.CustomResponse".equals(returnTypeName)) {
            return arg0;
        }
        return ResponseUtils.success(arg0);
    }
    @Override
    public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1) {

        final String returnTypeName = arg0.getParameterType().getName();
        // 用於判斷是否需要做處理
        return !"com.fun.common.tools.result.CustomResponse".equals(returnTypeName);
    }

2、全局異常處理

2.1、自定義異常

package com.fun.common.tools.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
 * @ClassName: CustomException 
 * @Author: fun
 * @Description:自定義異常,繼承RuntimeException ,可根據業務需要添加,此處不做更多擴展
 * @Date: 2020/1/6 10:23
 * @Version: 1.0.0
 * 可愛之人必有可胖之處
 * ღღ ∧_∧
 * ฅ(՞•🐽•՞)ฅ
 */
@Data
public class CustomException extends RuntimeException {
    private int code;
    private String msg;
}

2.2、全局統一異常處理類

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ResponseBody
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(NullPointerException.class)
    public CustomResponse errorHandler(NullPointerException ex) {
        return ResponseUtils.fail(ErrorResultCode.CUSTOM_EXCEPTION);
    }

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(CustomException.class)
    public CustomResponse myErrorHandler(CustomException ex) {
        return ResponseUtils.fail(ex.getCode(), ex.getMsg());
    }
}

2.3、全局統一異常處理測試

2.3.1 全局統一異常處理測試類

package com.fun.test.controller;

import com.fun.common.tools.exception.CustomException;
import com.fun.common.tools.exception.result.ErrorResultCode;
import com.fun.common.tools.result.CustomResponse;
import com.fun.common.tools.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @ClassName: TestController 
 * @Author: fun
 * @Description: 測試類
 * @Date: 2020/4/16 10:24
 * @Version: 1.0.0
 * 可愛之人必有可胖之處
 * ღღ ∧_∧
 * ฅ(՞•🐽•՞)ฅ
 */

@RestController
@Slf4j
@RequestMapping("/test")
public class TestController {
    @PostMapping(value = "/test")
    public CustomResponse test() {
   		User user = new User();
        if (user == null) {
           throw new NullPointerException();
        }
        user.setName("阿飯");
        user.setAge(16)
        return Result.success(customResponse);
    }
}

2.3.2 postman全局統一異常處理測試結果爲:

{
    "code": 10003,
    "msg": "空指針異常",
    "data": null
}

或者上面測試類中,將 throw new NullPointerException();改爲拋出自定義異常,那麼返回結果爲:

{
    "code": 10004,
    "msg": "具體的自定義異常",
    "data": null
}

2.3.3、總結:

全局統一異常處理類根據自身需求去定義需要處理的異常即可。

3、注意:

@RestControllerAdvice註解的類,需要讓spring掃描到,不然不會生效。

3.1 全局統一異常處理及全局統一返回不生效問題解決方法:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章