使用全局异常的好处是,不在需要去定义很多类型的返回值,当业务出错的时候直接通过异常的返回值方式来返回给前端或者API调用方错误信息。
以前我们的处理方式是如果接口执行正确返回200编码加上正确的结果值,如果失败,返回错误码加上错误信息,这样就导致接口的返回值对象需要兼容正确返回和错误返回值两种情况,其实接口的返回值只需要返回你想要的对象或者列表就行了,错误信息统一交给全局异常处理搞定。
使用全局异常类
定义一个业务异常类,所有的业务异常都需要抛出这一个异常,然后通过不同的状态码来区分具体是哪个异常,和对应的描述信息,状态码和描述信息在全局异常类里面通过枚举去定义。
如果类型比较多,可以定义多个枚举来区分不同类型的业务异常。
自定义一个业务异常,然后通过枚举类型区分具体的那个业务的异常,抛出对应的错误信息
在你业务错误的地方只需要使用throw new BusinessException()就OK了。
public class BusinessException extends RuntimeException {
private BaseResult result;
public BusinessException() {
}
public BusinessException(int status, String message) {
result = new BaseResult(status, message);
}
public BusinessException(ExceptionType exceptionType) {
if (exceptionType != null) {
result = new BaseResult(exceptionType.getStatus(), exceptionType.getMessage());
}
}
public BaseResult getMessageResult() {
return result;
}
public enum ExceptionType {
NAME_ALREADY_EXISTED(Constants.ExceptionType.ALREADY_EXISTS, Constants.ExceptionType.NAME_ALREADY_EXISTS);
private String message;
private int status;
ExceptionType(int status, String message) {
this.message = message;
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
ConstraintViolationException是validated的一个异常,校验参数的。
下面是一个全局异常捕获例子:
@ControllerAdvice
@Order(1) // Macross framework ResponseBodyExceptionHandler is 1000, we start at 900
public class GlobalExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResult verifyErrorHandler(HttpServletRequest request, Exception e) {
LOGGER.error("[exception:GlobalExceptionHandler] {} {}", request.getMethod(), request.getRequestURI());
ConstraintViolationException ce = (ConstraintViolationException) e;
Set<ConstraintViolation<?>> constraintViolationSet = ce.getConstraintViolations();
StringBuilder sb = new StringBuilder();
if (null != constraintViolationSet && !constraintViolationSet.isEmpty()) {
for (ConstraintViolation<?> violation : constraintViolationSet) {
sb.append(violation.getPropertyPath());
sb.append(":");
sb.append(violation.getMessage());
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
}
BaseResult result = new BaseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), sb.toString());
LOGGER.error("[exception:GlobalExceptionHandler] parameter verify error, error message: {}", sb.toString());
return result;
}
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResult verifyErrorHandlers(HttpServletRequest request, Exception e) {
LOGGER.error("[exception:GlobalExceptionHandler] {} {}", request.getMethod(), request.getRequestURI());
MethodArgumentNotValidException ce = (MethodArgumentNotValidException) e;
BindingResult bindingResult = ce.getBindingResult();
StringBuilder sb = new StringBuilder();
if (bindingResult.hasErrors()) {
List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrorList) {
sb.append(fieldError.getDefaultMessage());
sb.append(',');
}
sb.deleteCharAt(sb.length() - 1);
}
BaseResult result = new BaseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), sb.toString());
LOGGER.error("[exception:GlobalExceptionHandler] parameter verify error, error message: {}", sb.toString());
return result;
}
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResult handlerNameAlreadyExistedException(HttpServletRequest request, Exception e) {
LOGGER.error("[exception:NameAlreadyExistedException] {} {}", request.getMethod(), request.getRequestURI());
BusinessException businessException = (BusinessException) e;
BaseResult result = businessException.getMessageResult();
LOGGER.error("[exception:NameAlreadyExistedException]controller class raise exception. e={}", e);
return result;
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResult handler(HttpServletRequest request, Exception e) {
LOGGER.error("[exception:GlobalExceptionHandler] {} {}", request.getMethod(), request.getRequestURI());
BaseResult result = new BaseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage());
LOGGER.error("[exception:GlobalExceptionHandler]controller class raise exception. e={}", e);
return result;
}
}