在Spring Boot REST API开发中,异常处理是保障接口稳定性和用户体验的关键环节。如果没有统一的异常处理机制,接口遇到错误时会返回框架默认的错误信息,格式不统一且包含过多内部细节,既不利于前端解析,也可能暴露系统敏感信息。因此掌握异常处理的最佳实践是每个Spring Boot开发者的必备技能。

为什么需要统一的异常处理
默认的Spring Boot错误处理会返回包含时间戳、状态码、错误信息、路径等内容的JSON,但是这些信息往往不符合业务需求,比如缺少自定义的业务错误码,错误信息不够友好。统一的异常处理可以做到以下几点:
- 规范所有接口的错误返回格式,让前端处理错误更便捷
- 隐藏系统内部实现细节,避免敏感信息泄露
- 减少重复的异常处理代码,提升代码可维护性
- 支持自定义业务异常,区分不同场景的错误类型
使用@ControllerAdvice实现全局异常捕获
@ControllerAdvice是Spring提供的全局控制器增强注解,配合@ExceptionHandler可以捕获所有控制器抛出的异常,是实现全局异常处理的核心方案。
基础全局异常处理器示例
首先创建一个全局异常处理类,代码如下:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理所有未明确捕获的异常
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
body.put("error", "Internal Server Error");
body.put("message", ex.getMessage());
body.put("path", request.getDescription(false));
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
上述代码会捕获所有控制器中抛出的Exception类型异常,返回一个包含时间戳、状态码、错误类型、错误信息和请求路径的JSON响应,比默认的错误响应更简洁可控。
自定义业务异常类
实际业务中我们往往需要区分不同的错误场景,比如参数校验失败、资源不存在、权限不足等,这时候可以自定义业务异常类,携带自定义的错误码和错误信息。
自定义业务异常实现
首先定义业务异常基类:
public class BusinessException extends RuntimeException {
// 自定义业务错误码
private final Integer errorCode;
public BusinessException(Integer errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public BusinessException(Integer errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public Integer getErrorCode() {
return errorCode;
}
}
然后可以定义具体的业务异常子类,比如资源不存在异常:
public class ResourceNotFoundException extends BusinessException {
// 资源不存在的固定错误码
private static final Integer NOT_FOUND_CODE = 40401;
public ResourceNotFoundException(String message) {
super(NOT_FOUND_CODE, message);
}
public ResourceNotFoundException(String message, Throwable cause) {
super(NOT_FOUND_CODE, message, cause);
}
}
在全局处理器中捕获自定义异常
在之前的GlobalExceptionHandler中添加处理自定义业务异常的方法:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Object> handleBusinessException(BusinessException ex) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("errorCode", ex.getErrorCode());
body.put("message", ex.getMessage());
// 根据错误码匹配对应的HTTP状态码,这里简单处理为200,实际可按需调整
return new ResponseEntity<>(body, HttpStatus.OK);
}
// 处理所有未明确捕获的异常
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllExceptions(Exception ex) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("errorCode", 50000);
body.put("message", "系统内部错误,请联系管理员");
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
规范错误响应结构
为了让前端能统一解析错误响应,建议定义固定的错误响应结构,比如包含以下字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| timestamp | 字符串 | 错误发生的时间 |
| errorCode | 整数 | 自定义业务错误码,用于前端区分错误类型 |
| message | 字符串 | 友好的错误提示信息 |
| data | 对象/空 | 错误场景下一般为空,部分场景可返回补充信息 |
可以在项目中定义一个统一的响应工具类,同时支持成功响应和错误响应的构建:
public class ApiResponse<T> {
private LocalDateTime timestamp;
private Integer errorCode;
private String message;
private T data;
// 成功响应的静态方法
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setTimestamp(LocalDateTime.now());
response.setErrorCode(0);
response.setMessage("操作成功");
response.setData(data);
return response;
}
// 错误响应的静态方法
public static <T> ApiResponse<T> error(Integer errorCode, String message) {
ApiResponse<T> response = new ApiResponse<>();
response.setTimestamp(LocalDateTime.now());
response.setErrorCode(errorCode);
response.setMessage(message);
response.setData(null);
return response;
}
// 省略getter和setter方法
}
修改全局异常处理器,使用统一的响应结构返回错误:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException ex) {
ApiResponse<Void> response = ApiResponse.error(ex.getErrorCode(), ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.OK);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleAllExceptions(Exception ex) {
ApiResponse<Void> response = ApiResponse.error(50000, "系统内部错误,请联系管理员");
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
处理参数校验异常
在REST API中经常需要对请求参数做校验,比如使用<code>@Valid</code>注解校验请求体参数,这时候会抛出MethodArgumentNotValidException异常,也需要统一处理。
在全局异常处理器中添加对应的处理方法:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import java.util.stream.Collectors;
@ControllerAdvice
public class GlobalExceptionHandler {
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Void>> handleValidationException(MethodArgumentNotValidException ex) {
// 拼接所有校验失败的错误信息
String message = ex.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + ":" + error.getDefaultMessage())
.collect(Collectors.joining("; "));
ApiResponse<Void> response = ApiResponse.error(40001, "参数校验失败:" + message);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException ex) {
ApiResponse<Void> response = ApiResponse.error(ex.getErrorCode(), ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.OK);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleAllExceptions(Exception ex) {
ApiResponse<Void> response = ApiResponse.error(50000, "系统内部错误,请联系管理员");
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
最佳实践总结
综合上述内容,Spring Boot REST API异常处理的最佳实践可以总结为以下几点:
- 使用@ControllerAdvice配合@ExceptionHandler实现全局异常捕获,避免在每个控制器中重复写异常处理代码
- 自定义业务异常类,携带自定义错误码,区分不同业务场景的错误
- 定义统一的错误响应结构,让所有接口的错误返回格式一致,方便前端处理
- 单独处理参数校验异常、权限异常等常见框架异常,返回符合业务需求的错误信息
- 生产环境中不要返回异常堆栈信息,避免暴露系统内部细节
按照上述实践搭建异常处理体系后,Spring Boot REST API的错误处理会更规范、更易维护,也能提升前后端联调的效率。
Spring_BootREST_API异常处理全局异常捕获修改时间:2026-07-13 12:45:40