Spring Boot 4自定义异常处理:如何保留默认ErrorAttributes生成统一响应?
问题
我需要处理自定义异常,具体需求如下:
- 保留默认错误响应的结构(属性)并添加错误信息,希望无论异常是否被自定义处理器处理,都生成相同的JSON响应(未处理异常仍使用默认的ErrorAttributes响应);
- 不想在每个处理器中手动构建响应(比如手动填充Map,担心无法与ErrorAttributes保持同步)。
我尝试了如下代码,但Spring无法注入ErrorAttributes,报错信息如下:
import org.springframework.boot.webmvc.error.ErrorAttributes; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(InvalidTransferException.class) public ResponseEntity<ErrorAttributes> handle(ErrorAttributes errorAttributes) { return ResponseEntity.unprocessableContent().body(errorAttributes); } }
java.lang.IllegalStateException: Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<org.springframework.boot.webmvc.error.ErrorAttributes> com.example.em_card_service.exception.GlobalExceptionHandler.handle(org.springframework.boot.webmvc.error.ErrorAttributes): No suitable resolver at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:221) ~[spring-web-7.0.7.jar:7.0.7]
期望得到的错误响应JSON结构如下:
{ "timestamp": "2026-05-15T15:55:24.553Z", "status": 422, "error": "Unprocessable Content", "path": "/api/cards/transfer", "message": "Cannot perform transfer to the same card" }
(使用Spring Boot 4)
解决方案
问题根源
你之前的代码报错是因为ErrorAttributes不能直接作为@ExceptionHandler方法的参数,Spring没有对应的参数解析器支持这种注入方式,必须通过类级别的依赖注入获取实例。
方案1:注入ErrorAttributes构建统一响应
通过构造函数注入ErrorAttributes,利用它获取默认的错误属性Map,再添加自定义异常信息,既保留默认结构又避免手动维护字段:
import org.springframework.boot.web.error.ErrorAttributeOptions; import org.springframework.boot.web.servlet.error.ErrorAttributes; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.request.WebRequest; import java.util.Map; @ControllerAdvice public class GlobalExceptionHandler { private final ErrorAttributes errorAttributes; // 构造函数注入ErrorAttributes(Spring 4推荐构造函数注入) public GlobalExceptionHandler(ErrorAttributes errorAttributes) { this.errorAttributes = errorAttributes; } @ExceptionHandler(InvalidTransferException.class) public ResponseEntity<Map<String, Object>> handleInvalidTransferException(InvalidTransferException ex, WebRequest request) { // 获取默认错误属性(包含timestamp、status、error、path等默认字段) Map<String, Object> errorResponse = errorAttributes.getErrorAttributes( request, ErrorAttributeOptions.defaults() // 可按需调整,比如添加栈信息用ErrorAttributeOptions.of(Include.STACK_TRACE) ); // 替换为自定义异常消息 errorResponse.put("message", ex.getMessage()); // 设置对应HTTP状态码 return ResponseEntity.unprocessableContent().body(errorResponse); } }
方案2:自定义ErrorAttributes实现全局统一处理
如果需要对所有异常(包括未处理的)都保持响应结构一致,推荐自定义ErrorAttributes,这样无需在每个异常处理器中重复构建响应:
第一步:自定义ErrorAttributes
import org.springframework.boot.web.error.ErrorAttributeOptions; import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; import org.springframework.stereotype.Component; import org.springframework.web.context.request.WebRequest; import java.util.Map; @Component public class CustomErrorAttributes extends DefaultErrorAttributes { @Override public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) { // 获取默认错误属性 Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, options); Throwable error = getError(webRequest); // 处理自定义异常,设置对应的消息和状态码 if (error instanceof InvalidTransferException) { errorAttributes.put("message", error.getMessage()); errorAttributes.put("status", 422); errorAttributes.put("error", "Unprocessable Content"); } // 可扩展其他自定义异常的处理逻辑 return errorAttributes; } }
第二步:简化异常处理器(仅指定状态码)
此时异常处理器只需返回对应HTTP状态码,响应体由自定义的ErrorAttributes自动生成:
import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(InvalidTransferException.class) public ResponseEntity<Void> handleInvalidTransferException() { return ResponseEntity.unprocessableContent().build(); } }
方案优势
- 两种方案都保留了Spring Boot默认的错误响应结构,无需手动维护
timestamp、path等字段,避免与默认实现脱节; - 方案2更适合全局统一管理所有异常的响应格式,未处理的异常也会自动使用相同结构返回。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

