对于最新的稳定版本,请使用 Spring Framework 7.0.6!spring-doc.cadn.net.cn

异常

@Controller@ControllerAdvice 类可以包含 @ExceptionHandler 方法来处理控制器方法中的异常,如下例所示:spring-doc.cadn.net.cn

@Controller
public class SimpleController {

	// ...

	@ExceptionHandler
	public ResponseEntity<String> handle(IOException ex) {
		// ...
	}
}
@Controller
class SimpleController {

	// ...

	@ExceptionHandler
	fun handle(ex: IOException): ResponseEntity<String> {
		// ...
	}
}

该异常可能与正在传播的顶层异常匹配(例如直接抛出的IOException),或者与包装异常中的嵌套原因匹配(例如IOException被包含在IllegalStateException中)。从5.3版本开始,这可以在任意原因级别进行匹配,而之前仅考虑直接原因。spring-doc.cadn.net.cn

对于匹配的异常类型,最好将目标异常声明为方法参数,如前面的例子所示。当多个异常方法匹配时,通常优先选择根异常匹配而不是原因异常匹配。更具体地说,ExceptionDepthComparator用于根据异常从抛出异常类型的深度对异常进行排序。spring-doc.cadn.net.cn

或者,注解声明可以缩小异常类型的范围以匹配,如下例所示:spring-doc.cadn.net.cn

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
	// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: IOException): ResponseEntity<String> {
	// ...
}

你甚至可以使用一个特定异常类型的列表,并带有非常通用的参数签名,如下例所示:spring-doc.cadn.net.cn

@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
	// ...
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handle(ex: Exception): ResponseEntity<String> {
	// ...
}

根异常和原因异常匹配之间的区别可能会令人惊讶。spring-doc.cadn.net.cn

在显示的IOException变体中,该方法通常以实际的FileSystemExceptionRemoteException实例作为参数调用, 因为它们都从IOException继承。但是,如果任何此类匹配的异常在包装异常中传播,而该包装异常本身是一个IOException, 则传递的异常实例是该包装异常。spring-doc.cadn.net.cn

行为在handle(Exception)变体中甚至更简单。这总是在包装场景中被调用,带有包装异常,在这种情况下,实际匹配的异常可以通过ex.getCause()找到。传递的异常只有在这些作为顶级异常抛出时才是实际的FileSystemExceptionRemoteException实例。spring-doc.cadn.net.cn

我们通常建议你在参数签名中尽可能具体,减少根异常类型和原因异常类型之间不匹配的潜在可能性。考虑将一个多匹配方法拆分为单独的@ExceptionHandler方法,每个方法通过其签名匹配一个特定的异常类型。spring-doc.cadn.net.cn

在多@ControllerAdvice配置中,我们建议您在@ControllerAdvice上声明您的主要根异常映射,并指定相应的顺序。虽然优先选择根异常匹配而不是原因,但这在给定控制器或@ControllerAdvice类的方法中定义。这意味着在优先级更高的@ControllerAdvice bean上的原因匹配优先于在优先级更低的@ControllerAdvice bean上的任何匹配(例如,根异常)。spring-doc.cadn.net.cn

最后但并非最不重要的是,一个@ExceptionHandler方法实现可以选择通过以原始形式重新抛出给定的异常实例来退出处理。这在你只对顶级匹配或在无法静态确定的具体上下文中的匹配感兴趣的情况下很有用。重新抛出的异常会继续通过剩余的解析链传播,就像给定的@ExceptionHandler方法根本没有匹配一样。spring-doc.cadn.net.cn

Spring MVC 中对 @ExceptionHandler 方法的支持是基于 DispatcherServlet 级别的 HandlerExceptionResolver 机制。spring-doc.cadn.net.cn

方法参数

@ExceptionHandler 个方法支持以下参数:spring-doc.cadn.net.cn

方法参数 描述

异常类型spring-doc.cadn.net.cn

获取引发的异常。spring-doc.cadn.net.cn

HandlerMethodspring-doc.cadn.net.cn

获取引发异常的控制器方法。spring-doc.cadn.net.cn

WebRequest, NativeWebRequestspring-doc.cadn.net.cn

通用访问请求参数以及请求和会话属性,无需直接使用Servlet API。spring-doc.cadn.net.cn

jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponsespring-doc.cadn.net.cn

选择任何特定的请求或响应类型(例如,ServletRequestHttpServletRequest 或 Spring 的 MultipartRequestMultipartHttpServletRequest)。spring-doc.cadn.net.cn

jakarta.servlet.http.HttpSessionspring-doc.cadn.net.cn

强制要求存在会话。因此,此类参数永远不会为null
请注意,会话访问不是线程安全的。如果允许多个请求并发访问会话,请考虑将RequestMappingHandlerAdapter实例的synchronizeOnSession标志设置为truespring-doc.cadn.net.cn

java.security.Principalspring-doc.cadn.net.cn

当前已认证的用户——如果已知,可能是特定的Principal实现类。spring-doc.cadn.net.cn

HttpMethodspring-doc.cadn.net.cn

请求的HTTP方法。spring-doc.cadn.net.cn

java.util.Localespring-doc.cadn.net.cn

当前请求的本地化设置,由最具体的LocaleResolver确定——实际上,是配置的LocaleResolverLocaleContextResolverspring-doc.cadn.net.cn

java.util.TimeZone, java.time.ZoneIdspring-doc.cadn.net.cn

与当前请求相关联的时区,由LocaleContextResolver确定。spring-doc.cadn.net.cn

java.io.OutputStream, java.io.Writerspring-doc.cadn.net.cn

要访问由Servlet API暴露的原始响应体。spring-doc.cadn.net.cn

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMapspring-doc.cadn.net.cn

用于访问错误响应的模型。始终为空。spring-doc.cadn.net.cn

RedirectAttributesspring-doc.cadn.net.cn

指定重定向时要使用的属性(即附加到查询字符串的属性)和暂时存储直到重定向后请求的闪存属性。请参见重定向属性闪存属性spring-doc.cadn.net.cn

@SessionAttributespring-doc.cadn.net.cn

对于访问任何会话属性,与作为类级别@SessionAttributes声明的结果存储在会话中的模型属性不同。请参见 @SessionAttribute以获取更多详细信息。spring-doc.cadn.net.cn

@RequestAttributespring-doc.cadn.net.cn

用于访问请求属性。有关更多详细信息,请参见 @RequestAttributespring-doc.cadn.net.cn

返回值

@ExceptionHandler 方法支持以下返回值:spring-doc.cadn.net.cn

返回值 描述

@ResponseBodyspring-doc.cadn.net.cn

返回值通过 HttpMessageConverter 实例进行转换,并写入响应。请参见 @ResponseBodyspring-doc.cadn.net.cn

HttpEntity<B>, ResponseEntity<B>spring-doc.cadn.net.cn

返回值指定将完整的响应(包括HTTP头和正文)通过HttpMessageConverter实例进行转换并写入响应。 参见ResponseEntityspring-doc.cadn.net.cn

ErrorResponsespring-doc.cadn.net.cn

要在正文中渲染包含详细信息的RFC 7807错误响应, 参见 错误响应spring-doc.cadn.net.cn

ProblemDetailspring-doc.cadn.net.cn

要在正文中渲染包含详细信息的RFC 7807错误响应, 参见 错误响应spring-doc.cadn.net.cn

Stringspring-doc.cadn.net.cn

一个视图名称,将通过ViewResolver个实现进行解析,并与隐式模型一起使用——通过命令对象和@ModelAttribute方法确定。处理器方法还可以通过声明一个Model参数(如前所述)来程序化地丰富模型。spring-doc.cadn.net.cn

Viewspring-doc.cadn.net.cn

一个 View 实例用于与隐式模型一起渲染——通过命令对象和 @ModelAttribute 方法确定。处理器方法还可以通过声明一个 Model 参数(如前所述)来程序化地丰富模型。spring-doc.cadn.net.cn

java.util.Map, org.springframework.ui.Modelspring-doc.cadn.net.cn

Attributes to be added to the implicit model with the view name implicitly determined through a RequestToViewNameTranslator.spring-doc.cadn.net.cn

@ModelAttributespring-doc.cadn.net.cn

要添加到模型中的属性,视图名称通过RequestToViewNameTranslator隐式确定。spring-doc.cadn.net.cn

请注意,@ModelAttribute 是可选的。请参见本表末尾的“任何其他返回值”。spring-doc.cadn.net.cn

ModelAndView 对象spring-doc.cadn.net.cn

要使用的视图和模型属性,以及可选的响应状态。spring-doc.cadn.net.cn

voidspring-doc.cadn.net.cn

具有 void 返回类型(或 null 返回值)的方法被认为完全处理了响应,如果它还具有 ServletResponse 一个 OutputStream 参数,或 带有 @ResponseStatus 注解。同样,如果控制器进行了积极的 ETaglastModified 时间戳检查(详情请参见控制器)。spring-doc.cadn.net.cn

如果上述情况都不成立,返回类型为 void 也可以表示“无响应体”对于 REST 控制器或默认视图名称选择对于 HTML 控制器。spring-doc.cadn.net.cn

任何其他返回值spring-doc.cadn.net.cn

如果返回值不匹配上述任何一种情况,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定), 默认情况下,它将被视为要添加到模型中的模型属性。如果是简单类型,则保持未解析。spring-doc.cadn.net.cn