前言
簡單回顧下異常分類:
- 非受檢異常:運作時異常
- 受檢異常:編譯時異常
異常的處理通常有兩種方式:
- 第一種就是在目前類使用try-catch捕獲異常并直接處理
- 另一種就是不在目前類處理,使用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
注解,辨別該類中接收的傳回資訊的(json類型的)資料。
@ResponseBody
建立一個統一的異常處理類:
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();
}
*/
}
複制