异常
@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 公开的原始响应主体。 |
|
用于访问错误响应的模型。始终为空。 |
|
指定在重定向情况下使用的属性 - (即要附加到查询字符串的属性)以及要临时存储的闪存属性,直到重定向后的请求。请参阅 重定向属性 和 闪存属性。 |
|
要访问任何会话属性,与作为类级 |
|
要访问请求属性。有关更多详细信息,请参阅 |
返回值
@ExceptionHandler
方法支持以下返回值
返回值 | 描述 |
---|---|
|
返回值通过 |
|
返回值指定完整响应(包括 HTTP 标头和正文)通过 |
|
要呈现带有正文中详细信息的 RFC 9457 错误响应,请参阅错误响应 |
|
要呈现带有正文中详细信息的 RFC 9457 错误响应,请参阅错误响应 |
|
要与 |
|
要与隐式模型一起用于渲染的 |
|
要添加到隐式模型中的属性,视图名称通过 |
|
要添加到模型中的属性,视图名称通过 请注意, |
|
要使用的视图和模型属性,以及可选的响应状态。 |
|
如果方法具有 如果上述情况都不成立, |
任何其他返回值 |
如果返回值与上述任何返回值都不匹配,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定),默认情况下,它将被视为要添加到模型中的模型属性。如果它是简单类型,则它将保持未解析状态。 |