我想让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
,但仍然应用我的自定义逻辑?
提供一个完整的解决方案:它只是通过扩展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
}
}
好吧,我在一段时间内遇到了同样的问题并尝试了几种方法,比如扩展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;
}
}
以这种方式为异常处理创建类
@RestControllerAdvice
public class MyExceptionHandler extends BaseExceptionHandler {
}
public class BaseExceptionHandler extends ResponseEntityExceptionHandler {
}
这里,ResponseEntityExceptionHandler由spring提供,并覆盖与requestMethodNotSupported,missingPathVariable,noHandlerFound,typeMismatch,asyncRequestTimeouts .......相关的几个异常处理程序方法,带有您自己的异常消息或错误响应对象和状态代码
并在MyExceptionHandler中使用@ExceptionHandler(Exception.class)
方法,如果没有匹配的处理程序,抛出的异常最终会出现。