异常处理
@Controller
和 @ControllerAdvice
类可以有 @ExceptionHandler
方法来处理控制器方法中的异常,如下例所示:
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
异常可能与传播的顶级异常匹配(例如直接抛出的 IOException
),或者与包装异常内的嵌套原因匹配
(例如包装在 IllegalStateException
内的 IOException
)。这可以在任意原因级别上匹配,而之前只考虑了直接原因。
对于匹配异常类型,最好将目标异常作为方法参数声明,如前例所示。当多个异常方法匹配时,通常更倾向于根异常匹配而不是原因异常匹配。
更具体地说,使用 ExceptionDepthComparator
根据它们从抛出异常类型开始的深度对异常进行排序。
另外,注解声明可以缩小匹配的异常类型,如下例所示:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
你甚至可以使用具有非常通用参数签名的特定异常类型的列表,如下例所示:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
这种方式允许你将多个特定的异常类型映射到同一个处理方法。在这个方法中,你可以编写通用的逻辑来处理这些异常, 或者根据异常的具体类型进一步区分处理。这种方法特别有用,当你需要对一组相关的异常进行统一处理时。 通过这种方式,你可以简化异常处理逻辑,并提高代码的可维护性。
根异常和原因异常匹配之间的区别可能会令人惊讶。 在前面显示的 在 |
我们通常建议你在参数签名中尽可能具体,减少根异常和原因异常类型之间的潜在不匹配。考虑将一个多匹配方法拆分为单独的
@ExceptionHandler
方法,每个方法通过其签名匹配单个特定异常类型。
在多 @ControllerAdvice
安排中,我们建议在优先级相应的顺序上声明你主要的根异常映射。虽然根异常匹配比原因更受青睐,
但这是在给定控制器或 @ControllerAdvice
类的方法中定义的。这意味着在更高优先级的 @ControllerAdvice
bean
上的原因匹配比在较低优先级的 @ControllerAdvice
bean 上的任何匹配(例如,根)更受青睐。
最后但同样重要的是,@ExceptionHandler
方法的实现可以选择通过以其原始形式重新抛出它来处理给定的异常实例。
这在你对根级别匹配或在无法静态确定的特定上下文中的匹配感兴趣的情况下很有用。重新抛出的异常通过剩余的解析链传播,
就好像给定的 @ExceptionHandler
方法最初没有匹配一样。
Web MVC 中对 @ExceptionHandler
方法的支持建立在 DispatcherHandler
级别,
HandlerExceptionHandler 机制上。
方法参数
@ExceptionHandler
方法支持以下的参数:
方法参数 | 描述 |
---|---|
Exception type |
For access to the raised exception. |
|
访问引发异常的控制器方法. |
|
当前请求上下文 |
|
当前请求的请求方法 |
|
The time zone associated with the current request, as determined by a |
|
原始响应流 |
|
用于访问错误响应的模型。始终为空。 |
|
指定在重定向情况下使用的属性 — (即附加到查询字符串中)以及存储在重定向请求后临时使用的 Flash 属性。 参见 重定向属性 和 Flash 属性。 |
|
请求 attributes. See |
返回值
@ExceptionHandler
方法支持以下返回值:
返回值 | 描述 |
---|---|
|
返回值通过 |
|
返回值指定整个响应(包括 HTTP 头和正文)通过 |
|
要呈现具有正文详细信息的 RFC 7807 错误响应,参见 错误响应。 |
|
要呈现具有正文详细信息的 RFC 7807 错误响应,参见 错误响应。 |
|
一个视图名称,将通过 |
|
一个 |
|
要添加到隐式模型中的属性,视图名称通过 |
|
要添加到模型中的属性,视图名称通过 注意 |
|
要使用的视图和模型属性,以及可选的响应状态。 |
|
如果方法具有 |
任何其他返回值 |
如果返回值不匹配上述任何一种,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定), 则默认情况下,它被视为要添加到模型的模型属性。如果它是一个简单类型,则保持未解析状态。 |