异常
@Controller 和 @ControllerAdvice 类可以拥有 @ExceptionHandler 方法来处理控制器方法抛出的异常,如下例所示:
-
Java
-
Kotlin
@Controller
public class SimpleController {
// ...
@ExceptionHandler
public ResponseEntity<String> handle(IOException ex) {
// ...
}
}
@Controller
class SimpleController {
// ...
@ExceptionHandler
fun handle(ex: IOException): ResponseEntity<String> {
// ...
}
}
异常可以匹配顶层传播的异常(例如直接抛出的 IOException)或者包装异常中的嵌套原因(例如包装在 IllegalStateException 中的 IOException)。从5.3版本开始,这可以在任意原因级别进行匹配,而以前只考虑了直接原因。
对于匹配的异常类型,最好将目标异常声明为方法参数,就像前面的例子所示。当多个异常方法匹配时,通常优先选择根异常匹配而不是原因异常匹配。更具体地说,使用 ExceptionDepthComparator 来根据抛出异常类型的深度对异常进行排序。
另外,注解声明可以缩小要匹配的异常类型范围,如下例所示:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: IOException): ResponseEntity<String> {
// ...
}
甚至可以使用具有非常通用参数签名的特定异常类型列表,如下例所示:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: Exception): ResponseEntity<String> {
// ...
}
|
根异常和原因异常匹配之间的区别可能会令人惊讶。 在前面显示的 在 |
我们通常建议在参数签名中尽可能具体,减少根异常和原因异常类型之间不匹配的可能性。考虑将多匹配方法拆分为单独的 @ExceptionHandler 方法,每个方法通过其签名匹配单个特定异常类型。
在多个 @ControllerAdvice 排列中,我们建议在具有相应顺序的 @ControllerAdvice 上声明主要根异常映射。虽然根异常匹配优先于原因异常,但这是在给定控制器或 @ControllerAdvice 类的方法之间定义的。这意味着在优先级较高的 @ControllerAdvice bean 上的原因匹配优先于在优先级较低的 @ControllerAdvice bean 上的任何匹配(例如根匹配)。
最后,@ExceptionHandler 方法实现可以选择通过以原始形式重新抛出来回避处理给定的异常实例。这在您只对根级匹配或在无法静态确定的特定上下文中的匹配感兴趣的情况下非常有用。重新抛出的异常将通过剩余的解析链传播,就好像给定的 @ExceptionHandler 方法一开始就不匹配。
Spring MVC 中对 @ExceptionHandler 方法的支持是建立在 DispatcherServlet 层级上的,HandlerExceptionResolver 机制。
方法参数
@ExceptionHandler 方法支持以下参数:
| 方法参数 | 描述 |
|---|---|
|
异常类型 |
用于访问引发的异常。 |
|
|
用于访问引发异常的控制器方法。 |
|
|
通用访问请求参数和请求以及会话属性,而无需直接使用Servlet API。 |
|
|
选择任何特定的请求或响应类型(例如, |
|
|
强制存在会话。因此,这样的参数永远不会是 |
|
|
当前经过身份验证的用户 —— 如果已知,可能是特定的 |
|
|
请求的 HTTP 方法。 |
|
|
当前请求的区域设置,由最具体的可用 |
|
|
与当前请求关联的时区,由 |
|
|
用于访问原始响应主体,由 Servlet API 公开。 |
|
|
用于访问错误响应的模型。始终为空。 |
|
|
指定在重定向时要使用的属性(即要附加到查询字符串的属性)和要在重定向后的请求之前临时存储的闪存属性。请参阅 重定向属性 和 闪存属性。 |
|
|
用于访问任何会话属性,与存储在会话中的模型属性形成对比,后者是由类级别的 |
|
|
用于访问请求属性。有关更多详细信息,请参阅 |
Return Values
@ExceptionHandler methods support the following return values:
| Return value | Description |
|---|---|
|
|
The return value is converted through |
|
|
The return value specifies that the full response (including the HTTP headers and the body) be converted through |
|
|
To render an RFC 7807 error response with details in the body, see Error Responses |
|
|
To render an RFC 7807 error response with details in the body, see Error Responses |
|
|
A view name to be resolved with |
|
|
A |
|
|
Attributes to be added to the implicit model with the view name implicitly determined through a |
|
|
An attribute to be added to the model with the view name implicitly determined through a Note that |
|
|
The view and model attributes to use and, optionally, a response status. |
|
|
A method with a If none of the above is true, a |
|
Any other return value |
If a return value is not matched to any of the above and is not a simple type (as determined by BeanUtils#isSimpleProperty), by default, it is treated as a model attribute to be added to the model. If it is a simple type, it remains unresolved. |