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掃描到,不然不會生效。