Spring MVC 与Spring Boot集成的全局异常处理
Spring Boot对Spring MVC的异常处理机制进行了自动配置,简化了异常处理的开发流程。
Spring Boot默认异常处理
Spring Boot默认提供/error端点,异常时返回JSON格式的错误信息:
JSON
{
"timestamp": "2026-05-18T10:30:00.000+00:00",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/api/users/999"
}
自定义错误属性
实现ErrorAttributes接口自定义错误响应内容:
Java
@Component
public class CustomErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", LocalDateTime.now());
errorAttributes.put("code", getStatus(webRequest));
errorAttributes.put("message", getMessage(webRequest));
errorAttributes.put("path", getPath(webRequest));
// 开发环境可返回详细错误信息
if (options.isIncluded(Include.STACK_TRACE)) {
Throwable error = getError(webRequest);
if (error != null) {
errorAttributes.put("trace", Arrays.toString(error.getStackTrace()));
}
}
return errorAttributes;
}
private int getStatus(WebRequest webRequest) {
Integer status = (Integer) webRequest.getAttribute(
"javax.servlet.error.status_code", WebRequest.SCOPE_REQUEST);
return status != null ? status : 500;
}
private String getMessage(WebRequest webRequest) {
String message = (String) webRequest.getAttribute(
"javax.servlet.error.message", WebRequest.SCOPE_REQUEST);
return message != null ? message : "服务器内部错误";
}
private String getPath(WebRequest webRequest) {
return (String) webRequest.getAttribute(
"javax.servlet.error.request_uri", WebRequest.SCOPE_REQUEST);
}
}
全局异常处理器
Java
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResult<Void>> handleException(Exception e, HttpServletRequest request) {
log.error("系统异常: {}", e.getMessage(), e);
return ResponseEntity.status(500)
.body(ApiResult.error(500, "系统繁忙,请稍后重试"));
}
@ExceptionHandler(BindException.class)
public ResponseEntity<ApiResult<Void>> handleBindException(BindException e) {
String message = e.getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest()
.body(ApiResult.error(400, message));
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResult<Void>> handleBusinessException(BusinessException e) {
return ResponseEntity.status(e.getCode())
.body(ApiResult.error(e.getCode(), e.getMessage()));
}
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<ApiResult<Void>> handleNotFound(NoHandlerFoundException e) {
return ResponseEntity.status(404)
.body(ApiResult.error(404, "资源不存在"));
}
}
配置文件设置
application.yml配置:
YAML
server:
error:
include-message: always
include-binding-errors: always
include-stacktrace: never
include-exception: false
spring:
mvc:
throw-exception-if-no-handler-found: true
web:
resources:
add-mappings: false
自定义错误页面
实现ErrorController接口:
Java
@RestController
public class CustomErrorController implements ErrorController {
@Autowired
private ErrorAttributes errorAttributes;
@RequestMapping("/error")
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = errorAttributes.getErrorAttributes(
new ServletWebRequest(request),
ErrorAttributeOptions.defaults()
);
HttpStatus status = getStatus(request);
return ResponseEntity.status(status).body(body);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute(
RequestDispatcher.ERROR_STATUS_CODE);
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
try {
return HttpStatus.valueOf(statusCode);
} catch (Exception ex) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
}
}
统一响应结果封装
Java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResult<T> {
private int code;
private String message;
private T data;
private Long timestamp;
public static <T> ApiResult<T> success(T data) {
return new ApiResult<>(200, "success", data, System.currentTimeMillis());
}
public static <T> ApiResult<T> success() {
return success(null);
}
public static <T> ApiResult<T> error(int code, String message) {
return new ApiResult<>(code, message, null, System.currentTimeMillis());
}
}
结合AOP记录异常日志
Java
@Slf4j
@Aspect
@Component
public class ExceptionLogAspect {
@AfterThrowing(pointcut = "execution(* com.example.controller..*.*(..))", throwing = "ex")
public void logException(JoinPoint joinPoint, Exception ex) {
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.error("异常发生位置: {}.{}, 参数: {}, 异常信息: {}",
className, methodName, Arrays.toString(args), ex.getMessage(), ex);
}
}
生产环境建议关闭
include-stacktrace,避免暴露敏感信息。
要点总结
- Spring Boot默认提供
/error端点处理异常 - 自定义ErrorAttributes可控制响应内容
- @RestControllerAdvice是推荐的全局处理方式
- application.yml可配置错误响应行为
- 结合AOP可实现异常日志记录
📝 发现内容有误?点击此处直接编辑