天天看點

統一異常處理及傳回結果

前言

簡單回顧下異常分類:

  1. 非受檢異常:運作時異常
  2. 受檢異常:編譯時異常

異常的處理通常有兩種方式:

  1. 第一種就是在目前類使用try-catch捕獲異常并直接處理
  2. 另一種就是不在目前類處理,使用throws抛給上一級處理

如果在每個異常處都進行try-catch處理的話,無疑會造成代碼的臃腫,且不夠美觀。

是以,一般來說除非的必須在在目前類處理的異常,否則都會向上抛出,直到抛到controller層為止,在controller層進行統一的異常處理(不處理的話,再往上抛就抛到前端去了)。

統一進行異常處理的常見方式有兩種:1. 使用注解 或者 2. 使用(AOP)攔截器

統一傳回結果

既然要統一進行異常處理了,自然需要統一下資料結果的傳回格式,這裡建議使用一個實體類進行處理,更加的可控易于管理修改。

在實體類中對資料的傳回格式進行下規範:

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Collection;
import java.util.HashMap;

@Data
public class ReturnResult {
    @ApiModelProperty(value = "操作結果")
    private Boolean result;

    @ApiModelProperty(value = "傳回消息")
    private String message;

    @ApiModelProperty(value = "傳回資料")
    private HashMap<String, String> data;

    private ReturnResult() {
    }

    public static ReturnResult error() {
        ReturnResult returnResult = new ReturnResult();
        returnResult.setResult(false);
        returnResult.setMessage("操作出錯");
        return returnResult;
    }

    public static ReturnResult error(HashMap<String, String> data) {
        ReturnResult returnResult = new ReturnResult();
        returnResult.setResult(false);
        returnResult.setMessage("操作出錯");
        returnResult.setData(data);
        return returnResult;
    }

    public static ReturnResult success() {
        ReturnResult returnResult = new ReturnResult();
        returnResult.setResult(true);
        returnResult.setMessage("操作成功");
        return returnResult;
    }

    public static ReturnResult success(HashMap<String, String> data) {
        ReturnResult returnResult = new ReturnResult();
        returnResult.setResult(true);
        returnResult.setMessage("操作成功");
        returnResult.setData(data);
        return returnResult;
    }

    public ReturnResult result(Boolean success) {
        this.setResult(success);
        return this;
    }

    public ReturnResult message(String message) {
        this.setMessage(message);
        return this;
    }

}

           

複制

統一異常處理

controller類示例:

@RestController
public class ErrorTestController {
    @Autowired
    ErrorService errorService;

    @GetMapping("/test")
    public ReturnResult toTest(){
        HashMap<String, String> map = new HashMap<>();
        map.put("data", "這裡是傳回的資料");
        return ReturnResult.success(map);
    }
    @GetMapping("/test1")
    public ReturnResult toTest1(){
        errorService.error1();
        return ReturnResult.success();
    }

    @GetMapping("/test2")
    public ReturnResult toTest2(){
        errorService.error2();
        return ReturnResult.success();
    }

}           

複制

同時在service類中模拟異常:

@Service
public class ErrorService {
    public void error1() throws NullPointerException {
        String[] str = null;
        String s = str[0];
    }

    public void error2() throws ArithmeticException {
        int i = 9 / 0;
    }
    
}
           

複制

AOP處理異常

使用AOP切controller類,進行統一的異常處理。

AOP切面類:

import email.entity.ReturnResult;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;

@Aspect
@Component
public class AOPCatch {
    private final Logger logger = LoggerFactory.getLogger(AOPCatch.class);

    @Around("execution(public * email.controller.*.*(..))")
    public ReturnResult catchException(ProceedingJoinPoint joinPoint) {
        try {
            Object result = joinPoint.proceed();
            // 沒有異常,直接将接收到的被切方法的傳回值原樣傳回
            return (ReturnResult) result;
        } catch (Throwable e) {
            HashMap<String, String> map = new HashMap<>();
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            logger.error(className + ":" + methodName + ":" + e);
            map.put("data", className + ":" + methodName + ":" + e);
            ReturnResult error = ReturnResult.error(map);
            // 有異常,則傳回錯誤資訊
            return error;
        }
    }
}
           

複制

統一異常處理及傳回結果
統一異常處理及傳回結果

注解處理異常

使用

@ControllerAdvice

或者

@RestControllerAdvice

配合

@ExceptionHandler

注解使用

@RestControllerAdvice

注解就相當于

@ControllerAdvice

+

@ResponseBody

注解,辨別該類中接收的傳回資訊的(json類型的)資料。

建立一個統一的異常處理類:

package email.servive;

import email.entity.ReturnResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;

@RestControllerAdvice
//@ControllerAdvice
//@ResponseBody
public class GlobalExceptionHandler {

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

    // 全局異常處理
    @ExceptionHandler(Exception.class)
    public ReturnResult error(Exception e){
        e.printStackTrace();
        logger.error(e.getMessage());
        return ReturnResult.error();
    }

    // 指定異常處理
    @ExceptionHandler(NullPointerException.class)
    public ReturnResult error(NullPointerException e){
        e.printStackTrace();
        logger.error(e.getMessage());

        HashMap<String, String> map = new HashMap<>();
        map.put("data", "空指針異常");
        return ReturnResult.error(map);
    }


// 自定義異常處理,針對于業務需求自定義的
/*
    @ExceptionHandler(MyException.class)
    public ReturnResult error(MyException e){
        e.printStackTrace();
        return ReturnResult.error();
    }
*/

}
           

複制

統一異常處理及傳回結果
統一異常處理及傳回結果
統一異常處理及傳回結果