Springboot全局异常处理:@ControllerAdvice和ErrorController
目前有两种方式可以实现全局异常处理
@ControllerAdvice
ErrorController
两种处理方式可以同时使用,个人理解同时使用时
@ControllerAdvice
是用来捕获Controller中抛出的异常;
ErrorController
则是捕获未被@ControllerAdvice
捕获的异常,用来做兜底异常处理;
一. @ControllerAdvice 实现
@ControllerAdvice
+ @ExceptionHandler
可以捕获Controller中抛出的异常进行处理(如果在@ExceptionHandler
修饰的方法中再次抛出异常,则进入到/error
路径下,即转交给ErrorController
进行处理)
@ControllerAdvice
class APIResponseExceptionHandler {
... ...
@ExceptionHandler({XDistException.class})
public ResponseEntity<Object> handleXdistException(APIException te) {
return exceptionUtilsService.errorResponse(te, INTERNAL_SERVER_ERROR);
}
... ...
}
二. ErrorController 实现
没有进入Controller的其他部分抛出的异常(拦截器,过滤器或直接访问资源文件中抛出的异常)则交由ErrorController
处理。
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class APIErrorController implements ErrorController {
private static final Logger LOGGER = LoggerFactory.getLogger(APIErrorController.class);
private static final String ERROR_PATH = "/error";
/**
* The error service.
*/
@Autowired
private ErrorService errorService;
/**
* Get error path.
*
* @return Error path {@link String}.
*/
@Override
public String getErrorPath() {
return ERROR_PATH;
}
/**
* Method to execute when the error path is requested.
* This will return a 404, 405, 415 or 500 error depending on the status to the client.
*
* @param request The request object.
*/
@RequestMapping
@ResponseBody
public void error(HttpServletRequest request) {
CoreRequestProperties requestProperties = (CoreRequestProperties) request.getAttribute(RequestParameters.REQUESTPROPERTIES);
HttpStatus status = getStatus(request);
ApiError error;
switch (status) {
// not found the request url
case NOT_FOUND:
error = errorService.createApiError(CoreErrorCodes.INVALID_PATH, requestProperties.getLocale());
throw new NoResourceFoundException("Invalid path specified (404). Throwing invalid path error in the " +
"APIErrorController.", error);
// the request method is not allowed
case METHOD_NOT_ALLOWED:
error = errorService.createApiError(CoreErrorCodes.METHOD_NOT_ALLOWED, requestProperties.getLocale());
throw new MethodNotAllowedException("Invalid method specified (405). Throwing invalid method error in the " +
"APIErrorController.", error);
//the media type is unsupported in the request
case UNSUPPORTED_MEDIA_TYPE:
error = errorService.createApiError(CoreErrorCodes.UNSUPPORTED_MEDIA_TYPE, requestProperties.getLocale());
throw new UnsupportedMediaTypeException("Invalid media type (415). Throwing invalid media type in the " +
"APIErrorController.", error);
// unknown error
default:
error = errorService.createApiError(CoreErrorCodes.ERROR_CONTROLLER_UNKNOWN_ERROR, requestProperties.getLocale());
throw new ApplicationException(" Error occurred " + status + ". Throwing 500 in the APIErrorController.", error);
}
}
/**
* Retrieve the http status from the request.
*
* @param request The request object.
* @return The HTTP status code to return.
*/
protected HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
//if http status is null then return internal server error
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
try {
return HttpStatus.valueOf(statusCode);
} catch (Exception ex) {
LOGGER.warn("Failed to retrieve HttpStatus. Returning default {}", HttpStatus.INTERNAL_SERVER_ERROR, ex);
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
}