如何在Spring MVC中捕获所有未处理的异常(即没有现有的@ExceptionHandler)?

问题描述 投票:5回答:3

我想让HandlerExceptionResolver通过@ExceptionHandler注释解析我没有明确捕获的任何异常。

无论如何,我想对这些例外应用特定的逻辑。例如,另外发送邮件通知或日志。我可以通过添加@ExceptionHandler(Exception.class) catch来实现这一点,如下所示:

@RestControllerAdvice
public MyExceptionHandler {
    @ExceptionHandler(IOException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object io(HttpServletRequest req, Exception e) {
        return ...
    }


    @ExceptionHandler(Exception.class)
    public Object exception(HttpServletRequest req, Exception e) {
        MailService.send();
        Logger.logInSpecificWay();

        //TODO how to continue in the "normal" spring way with HandlerExceptionResolver?
    }
}

问题:如果我像这样添加@ExceptionHandler(Exception.class),我可以捕获那些未处理的异常。

但我不能让spring继续使用HandlerExceptionResolver正常的工作流程来创建响应ModelAndView并自动设置HTTP状态代码。

例如,如果有人在POST方法上尝试GET,默认弹簧将返回405 Method not allowed。但是使用@ExceptionHandler(Exception.class)我会吞下这个标准的弹簧处理......

那么如何保持默认的HandlerExceptionResolver,但仍然应用我的自定义逻辑?

java spring spring-mvc
3个回答
5
投票

提供一个完整的解决方案:它只是通过扩展ResponseEntityExceptionHandler来工作,因为它处理所有spring-mvc错误。然后可以使用@ExceptionHandler(Exception.class)捕获未处理的那些。

@RestControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> exception(Exception ex) {
        MailService.send();
        Logger.logInSpecificWay();
        return ... custom exception 
    }
}

1
投票

好吧,我在一段时间内遇到了同样的问题并尝试了几种方法,比如扩展ResponseEntityExceptionHandler,但所有这些都解决了一些问题,但创造了其他问题。

然后我决定使用自定义解决方案,这也允许我发送更多信息,我已经写了下面的代码

@RestControllerAdvice
public class MyExceptionHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @ExceptionHandler(NumberFormatException.class)
    public ResponseEntity<Object> handleNumberFormatException(NumberFormatException ex) {
        return new ResponseEntity<>(getBody(BAD_REQUEST, ex, "Please enter a valid value"), new HttpHeaders(), BAD_REQUEST);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException ex) {
        return new ResponseEntity<>(getBody(BAD_REQUEST, ex, ex.getMessage()), new HttpHeaders(), BAD_REQUEST);
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity<Object> handleAccessDeniedException(AccessDeniedException ex) {
        return new ResponseEntity<>(getBody(FORBIDDEN, ex, ex.getMessage()), new HttpHeaders(), FORBIDDEN);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> exception(Exception ex) {
        return new ResponseEntity<>(getBody(INTERNAL_SERVER_ERROR, ex, "Something Went Wrong"), new HttpHeaders(), INTERNAL_SERVER_ERROR);
    }

    public Map<String, Object> getBody(HttpStatus status, Exception ex, String message) {

        log.error(message, ex);

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("message", message);
        body.put("timestamp", new Date());
        body.put("status", status.value());
        body.put("error", status.getReasonPhrase());
        body.put("exception", ex.toString());

        Throwable cause = ex.getCause();
        if (cause != null) {
            body.put("exceptionCause", ex.getCause().toString());
        }
        return body;
    }

}

0
投票

以这种方式为异常处理创建类

@RestControllerAdvice
public class MyExceptionHandler extends BaseExceptionHandler {

}

public class BaseExceptionHandler extends ResponseEntityExceptionHandler {

}

这里,ResponseEntityExceptionHandler由spring提供,并覆盖与requestMethodNotSupported,missingPathVariable,noHandlerFound,typeMismatch,asyncRequestTimeouts .......相关的几个异常处理程序方法,带有您自己的异常消息或错误响应对象和状态代码

并在MyExceptionHandler中使用@ExceptionHandler(Exception.class)方法,如果没有匹配的处理程序,抛出的异常最终会出现。

© www.soinside.com 2019 - 2024. All rights reserved.