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

2022-09-02 10:41:42

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

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

@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)

我无法继续正常的工作流程来创建响应并自动设置HTTP状态代码。springHandlerExceptionResolverModelAndView

例如,如果有人尝试使用方法,则默认情况下spring将返回.但是有了一个,我会吞下这个标准的春天处理...POSTGET405 Method not allowed@ExceptionHandler(Exception.class)

那么,如何保留默认值,同时仍应用我的自定义逻辑呢?HandlerExceptionResolver


答案 1

为了提供一个完整的解决方案:它的工作原理只是扩展 ,因为它处理所有错误。然后可以使用 捕获未处理的那些。ResponseEntityExceptionHandlerspring-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 
    }
}

答案 2

好吧,我前段时间遇到了同样的问题,并且尝试了几种方法,例如扩展,但所有这些都在解决一些问题,但创造了其他问题。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;
    }

}

推荐