全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 8 分钟 ✍️ juanwangdev

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可实现异常日志记录

📝 发现内容有误?点击此处直接编辑

← 上一篇 静态资源访问路径
下一篇 → Spring MVC 多种异常处理
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库