spring mvc可通过@controlleradvice+@exceptionhandler结合problemdetail类实现rfc 7807标准异常响应,返回含type、title、status、detail、instance字段的application/problem+json格式json,无需手动拼接。

Spring MVC 可以通过 @ControllerAdvice + @ExceptionHandler 统一捕获异常,并按 RFC 7807(Problem Details for HTTP APIs)规范构造标准错误响应体,同时设置对应 HTTP 状态码。
使用 RFC 7807 标准定义错误响应结构
RFC 7807 要求响应体是 JSON,包含至少 type、title、status 三个字段,推荐加上 detail 和 instance。Spring Boot 2.3+ 内置了 ProblemDetail 类(位于 org.springframework.http.ProblemDetail),可直接用于构建合规响应。
-
type:机器可读的错误类型 URI(如"https://example.com/problems/validation-failed"),不一定是真实可访问链接 -
title:简短、人类可读的错误概要(如"Validation Failed") -
status:HTTP 状态码(必须与响应状态一致) -
detail:具体错误原因(如字段校验失败详情) -
instance:当前请求唯一标识(可选,常设为请求路径或 traceId)
编写全局异常处理器
创建一个 @ControllerAdvice 类,用 @ExceptionHandler 拦截特定异常,并返回 ResponseEntity<problemdetail></problemdetail>:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<problemdetail> handleValidationException(
MethodArgumentNotValidException ex, HttpServletRequest request) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
HttpStatus.UNPROCESSABLE_ENTITY, "Validation failed");
problemDetail.setTitle("Validation Error");
problemDetail.setType(URI.create("https://example.com/problems/validation-failed"));
problemDetail.setDetail(ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining("; ")));
problemDetail.setInstance(URI.create(request.getRequestURI()));
return ResponseEntity.status(HttpStatus.UNPROCESSABLE_ENTITY).body(problemDetail);
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<problemdetail> handleGenericException(
RuntimeException ex, HttpServletRequest request) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(
HttpStatus.INTERNAL_SERVER_ERROR, "An unexpected error occurred");
problemDetail.setTitle("Internal Server Error");
problemDetail.setType(URI.create("https://example.com/problems/internal-error"));
problemDetail.setDetail(ex.getMessage());
problemDetail.setInstance(URI.create(request.getRequestURI()));
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(problemDetail);
}
}</problemdetail></problemdetail>
确保响应 Content-Type 正确且无额外包装
默认情况下,Spring 会将 ProblemDetail 序列化为 application/problem+json(RFC 7807 推荐 MIME 类型)。若需兼容旧客户端,也可显式设为 application/json:
- 保持
produces = MediaType.APPLICATION_PROBLEM_JSON_VALUE(推荐) - 若返回
application/json,需确认前端能解析该结构;Spring 默认支持,无需额外配置 - 避免在响应体外再套一层 data 或 result 字段——RFC 7807 要求顶层即为 problem 对象
配合 Spring Boot 的自动配置启用 ProblemDetail 支持
Spring Boot 2.3+ 默认启用 ProblemDetail 支持。若使用更早版本(如 2.2.x),需手动引入依赖并注册序列化器:
- 添加
spring-boot-starter-validation(校验场景必需) - 确保 Jackson 版本 ≥ 2.12(对
ProblemDetail的序列化友好) - 无需自定义
ObjectMapper,Spring Boot 自动注册ProblemDetail的序列化逻辑
只要异常处理器返回 ProblemDetail 并正确设置状态码,Spring 就会生成符合 RFC 7807 的响应,无需手动拼 JSON 或操作 HttpServletResponse。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










