Spring MVC 返回JSON格式错误信息
RESTful API开发中,统一JSON格式的错误响应是前后端协作的基础。
统一响应结构设计
Java
public class ErrorResponse {
private int code;
private String message;
private String path;
private Long timestamp;
private Object data;
// 构造器
public ErrorResponse(int code, String message, String path) {
this.code = code;
this.message = message;
this.path = path;
this.timestamp = System.currentTimeMillis();
}
// 静态工厂方法
public static ErrorResponse of(int code, String message, String path) {
return new ErrorResponse(code, message, path);
}
public static ErrorResponse badRequest(String message, String path) {
return new ErrorResponse(400, message, path);
}
public static ErrorResponse unauthorized(String message, String path) {
return new ErrorResponse(401, message, path);
}
public static ErrorResponse forbidden(String message, String path) {
return new ErrorResponse(403, message, path);
}
public static ErrorResponse notFound(String message, String path) {
return new ErrorResponse(404, message, path);
}
public static ErrorResponse internalError(String message, String path) {
return new ErrorResponse(500, message, path);
}
// getter/setter省略
}
全局异常处理器实现
Java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception e, HttpServletRequest request) {
ErrorResponse error = ErrorResponse.internalError(
e.getMessage(),
request.getRequestURI()
);
return ResponseEntity.status(500).body(error);
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
ErrorResponse error = new ErrorResponse(500, e.getMessage(), request.getRequestURI());
return ResponseEntity.status(500).body(error);
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e, HttpServletRequest request) {
ErrorResponse error = ErrorResponse.badRequest(
e.getMessage(),
request.getRequestURI()
);
return ResponseEntity.badRequest().body(error);
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResponseEntity<ErrorResponse> handleMethodNotSupported(
HttpRequestMethodNotSupportedException e,
HttpServletRequest request) {
ErrorResponse error = new ErrorResponse(405, "不支持的请求方法: " + e.getMethod(), request.getRequestURI());
return ResponseEntity.status(405).body(error);
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public ResponseEntity<ErrorResponse> handleMediaTypeNotSupported(
HttpMediaTypeNotSupportedException e,
HttpServletRequest request) {
ErrorResponse error = new ErrorResponse(415, "不支持的媒体类型: " + e.getContentType(), request.getRequestURI());
return ResponseEntity.status(415).body(error);
}
}
参数校验异常处理
Java
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
MethodArgumentNotValidException e,
HttpServletRequest request) {
List<Map<String, String>> errors = e.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> {
Map<String, String> err = new HashMap<>();
err.put("field", error.getField());
err.put("message", error.getDefaultMessage());
return err;
})
.collect(Collectors.toList());
ErrorResponse error = ErrorResponse.badRequest("参数校验失败", request.getRequestURI());
error.setData(errors);
return ResponseEntity.badRequest().body(error);
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ErrorResponse> handleConstraintViolation(
ConstraintViolationException e,
HttpServletRequest request) {
List<Map<String, String>> errors = e.getConstraintViolations()
.stream()
.map(violation -> {
Map<String, String> err = new HashMap<>();
err.put("property", violation.getPropertyPath().toString());
err.put("message", violation.getMessage());
return err;
})
.collect(Collectors.toList());
ErrorResponse error = ErrorResponse.badRequest("参数校验失败", request.getRequestURI());
error.setData(errors);
return ResponseEntity.badRequest().body(error);
}
响应示例
成功响应:
JSON
{
"code": 200,
"message": "success",
"path": "/api/users/1",
"timestamp": 1716000000000,
"data": {
"id": 1,
"name": "张三"
}
}
错误响应:
JSON
{
"code": 400,
"message": "参数校验失败",
"path": "/api/users",
"timestamp": 1716000000000,
"data": [
{
"field": "username",
"message": "用户名不能为空"
},
{
"field": "email",
"message": "邮箱格式不正确"
}
]
}
结合枚举定义错误码
Java
public enum ErrorCode {
SUCCESS(200, "操作成功"),
BAD_REQUEST(400, "请求参数错误"),
UNAUTHORIZED(401, "未授权访问"),
FORBIDDEN(403, "禁止访问"),
NOT_FOUND(404, "资源不存在"),
INTERNAL_ERROR(500, "服务器内部错误");
private final int code;
private final String message;
ErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() { return code; }
public String getMessage() { return message; }
}
生产环境建议返回通用错误信息,避免暴露敏感的异常堆栈信息。
要点总结
- 设计统一的ErrorResponse结构,包含code、message、path、timestamp
- 使用@RestControllerAdvice实现全局异常处理
- 参数校验异常需提取字段错误信息
- 使用枚举管理错误码,提高可维护性
- 生产环境注意隐藏敏感异常信息
📝 发现内容有误?点击此处直接编辑