@ControllerAdvice异常处理与@ResponseStatus一起使用

时间:2014-06-11 13:58:17

标签: java spring spring-mvc

我有@ControllerAdvice类,它处理一组异常。比我们有一些其他例外,它们用@ResponseStatus注释注释。要结合这两种方法,我们使用博客文章http://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc中描述的技术,即ControllerAdvice我们通过以下方式处理通用Exception

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        // If the exception is annotated with @ResponseStatus rethrow it and let
        // the framework handle it - like the OrderNotFoundException example
        // at the start of this post.
        // AnnotationUtils is a Spring Framework utility class.
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)
            throw e;

        // Otherwise setup and send the user to a default error-view.
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", e);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
    }

它就像一个魅力,然而,使用这种技术会导致错误,以下文字出现在应用程序日志中:

2014-06-11 15:51:32.907 ERROR o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: ...

这是由ExceptionHandlerExceptionResolver中的这段代码引起的:

try {
            if (logger.isDebugEnabled()) {
                logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
            }
            exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);
        }
        catch (Exception invocationEx) {
            logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx);
            return null;
        }

有没有人知道如何正确地将这两种方法结合到异常处理中以避免日志中的错误?

谢谢, 扬

4 个答案:

答案 0 :(得分:1)

当我错过import时,我遇到了同样的问题:

import org.springframework.http.HttpStatus;

Eclipse 没有让我在快速修复中添加它,我手动添加了行,它有所帮助。

答案 1 :(得分:1)

我以稍微不同的方式处理它,我认为这解决了你的问题。

因为我知道基本上我想要处理404与不同色调的500s不同,我会寻找一个NOT_FOUND状态并相应地发送它,这似乎有效,然后你不会重新抛出异常。

这意味着

@ControllerAdvice
public class MVCExceptionHandler {
    private static final Logger log = LogManager.getLogger();

    @ExceptionHandler(Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, HttpServletResponse res, Exception ex) throws Exception {

        // If the exception is annotated with @ResponseStatus check if it's a 404 in which case deal with it, otherwise 500 it.
        if (AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class) != null) {
            ResponseStatus rs = AnnotationUtils.findAnnotation(ex.getClass(), ResponseStatus.class);
            if (HttpStatus.NOT_FOUND.equals(rs.value())) {
                res.setStatus(HttpStatus.NOT_FOUND.value());
                return new ModelAndView("error/404");
            }
        }

        log.error("Error while loading", ex);

        return new ModelAndView("error/500");

    }
}

答案 2 :(得分:1)

这是一个老问题,但我今天刚遇到这个问题,并找到了比禁用ExceptionHandlerExceptionResolver日志记录更好的解决方案。事实证明,通过升级到最新版本的spring框架(4.3.8为我工作)可以解决问题。已修复ExceptionHandlerExceptionResolver以检测原始异常是否从@ExceptionHandler重新抛出。在这种情况下,不再记录异常。

答案 3 :(得分:0)

问题在于您抛出异常而不是返回ModelAndView。从本质上讲,您正试图在ResponseStatusExceptionResolver课程中重新实施ControllerAdvice。你可以这样做(例如通过复制/粘贴来自ResponseStatusExceptionResolver的代码)但除了重复之外,这种方法也是不完整的。对于某些内置异常,Spring也带有DefaultHandlerExceptionResolver,这种方法可能无法正确处理。

相反,我所做的是在Exception.class课程中没有ControllerAdvice的全能处理程序。我不知道这是否是最好的解决方案,但它是我所知道的最好的解决方案。