我们的应用程序是基于 Spring MVC 的 REST 应用程序。我正在尝试使用 ExceptionHandler 注释来处理所有错误和异常。
我有
@ExceptionHandler(Throwable.class)
public @ResponseBody String handleErrors() {
return "error";
}
只要抛出异常,它就会起作用,但对于任何错误都不起作用。
我正在使用Spring 4.0。有什么解决办法吗?
与
ExceptionHandler#value()
属性所示相反
Class<? extends Throwable>[] value() default {};
和
@ExceptionHandler
仅用于处理 Exception
及其子类型。
Spring 使用
ExceptionHandlerExceptionResolver
来解析带注释的处理程序,使用以下方法
doResolveHandlerMethodException(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod, Exception exception)
如您所见,仅接受
Exception
。
在此配置中,您无法使用
Throwable
处理 Error
或 @ExceptionHandler
类型。
我会告诉你提供自己的
HandlerExceptionResolver
实现来处理 Throwable
实例,但是你需要自己提供自己的 DispatcherServlet
(以及大部分 MVC 堆栈),因为 DispatcherServlet
不 catch
Throwable
在任何可以产生重大影响的地方都有实例。
更新:
从 4.3 开始,Spring MVC 将抛出的
Throwable
值包装在 NestedServletException
实例中,并将其公开给 ExceptionHandlerExceptionResolver
。
我最近尝试过这个,经过审查,我的队友向我展示了这篇文章,但在 Spring Boot 3.2.2 中,你可以很好地捕获错误!
您可以进行一种 Hacking 来捕获 Spring MVC 中的错误。 首先,像这样定义一个拦截器:
public class ErrorHandlingInterceptor extends HandlerInterceptorAdapter {
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
{
super.afterCompletion(request, response, handler, ex);
controller.handleError(ex.getCause(), request, response);
} }
其次,在控制器中定义一个方法,例如“handleError”方法:
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setExceptionId(exceptionId);
errorResponse.setErrorMsg(ex.toString());
errorResponse.setServerStackTrace(serverStackTrace(ex));
response.setStatus(responseCode);
response.setContentType("application/json");
ObjectWriter writer = mapper.writer().withDefaultPrettyPrinter();
writer.writeValue(response.getOutputStream(), errorResponse);
最后,在 Spring 配置中配置你的拦截器。
<mvc:interceptors>
<bean class="ErrorHandlingInterceptor" />
</mvc:interceptors>
DispatchServlet 中的代码:
catch (Exception ex) {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// This is where to handle Exception by Spring.
// If Error happens, it will go to catch Error statement
// which will call afterCompletion method
mv = processHandlerException(processedRequest, response, handler, ex);
errorView = (mv != null);
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, processedRequest, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
// Trigger after-completion for successful outcome.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}
catch (Exception ex) {
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}
catch (Error err) {
ServletException ex = new NestedServletException("Handler processing failed", err);
// Trigger after-completion for thrown exception.
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
throw ex;
}