如何优雅捕获ResponseEntityExceptionHandler中定义的所有标准Spring MVC异常(无需逐个重写处理方法)
我之前也碰到过一模一样的需求——不想逐个重写ResponseEntityExceptionHandler里的各种异常处理方法,但又要把它覆盖的所有Spring MVC标准异常都用自定义格式返回。这里有个非常简洁的解决方案,只需要两步就能搞定:
1. 定义标准错误响应DTO
首先先封装一个统一的错误响应类,包含你需要的状态码、错误信息、时间戳等字段:
import java.time.LocalDateTime; public class StandardErrorResponse { private int status; private String message; private LocalDateTime timestamp; public StandardErrorResponse(int status, String message, LocalDateTime timestamp) { this.status = status; this.message = message; this.timestamp = timestamp; } // 生成getter方法(JSON序列化需要) public int getStatus() { return status; } public String getMessage() { return message; } public LocalDateTime getTimestamp() { return timestamp; } }
2. 继承ResponseEntityExceptionHandler并重写核心方法
自定义全局异常处理器,继承ResponseEntityExceptionHandler,然后重写它的handleExceptionInternal方法——这个方法是所有Spring MVC标准异常处理流程的最终出口,所有该类捕获的异常最终都会走到这里生成响应:
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import java.time.LocalDateTime; @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @Override protected ResponseEntity<Object> handleExceptionInternal( Exception ex, Object body, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { // 构建统一格式的错误响应 StandardErrorResponse errorResponse = new StandardErrorResponse( statusCode.value(), // 你可以根据需求自定义异常信息,比如用ex.getMessage()或者固定提示 ex.getMessage(), LocalDateTime.now() ); // 返回封装后的响应实体 return new ResponseEntity<>(errorResponse, headers, statusCode); } }
为什么这方法可行?
ResponseEntityExceptionHandler里标注了@ExceptionHandler的那个handleException方法,内部会根据异常类型分发到对应的具体处理方法(比如handleHttpRequestMethodNotSupported、handleMethodArgumentNotValid等),而这些具体方法最终都会调用handleExceptionInternal来生成最终的ResponseEntity。所以重写这个方法,就能一次性接管所有该类覆盖的异常,统一修改返回格式,完全不需要逐个重写每个异常的处理逻辑。
额外:针对特殊异常自定义处理
如果某个异常需要特殊的错误信息(比如HttpRequestMethodNotSupportedException要告诉用户支持的请求方法),你也可以单独重写对应的处理方法,同时保留统一的响应格式:
@Override protected ResponseEntity<Object> handleHttpRequestMethodNotSupported( HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { String customMessage = String.format( "请求方法不支持:%s,当前接口支持的方法有:%s", ex.getMethod(), String.join(", ", ex.getSupportedHttpMethods()) ); StandardErrorResponse errorResponse = new StandardErrorResponse( statusCode.value(), customMessage, LocalDateTime.now() ); return new ResponseEntity<>(errorResponse, headers, statusCode); }
这样既实现了统一格式的目标,又能灵活处理特殊场景,完全符合你的需求。
内容的提问来源于stack exchange,提问作者cloooze

