推荐使用@controlleradvice+@exceptionhandler实现全局异常处理,配合自定义result响应体,按异常类型分层捕获并返回标准code/message,同步设置http状态码,记录分级日志,确保前后端协作友好。

在 Spring Boot 项目中,推荐使用 @ControllerAdvice + @ExceptionHandler 实现全局统一异常处理,配合自定义错误响应结构,做到后端异常不暴露细节、前端提示友好、日志可追溯。
定义标准化错误响应体
先统一返回格式,便于前端解析和 UI 展示:
public class Result<t> {
private int code;
private String message;
private T data;
public static <t> Result<t> fail(int code, String message) {
Result<t> r = new Result();
r.code = code;
r.message = message;
return r;
}
// getter/setter 省略
}</t></t></t></t>
常见状态码建议:200(成功)、400(参数错误)、401(未登录)、403(无权限)、500(服务异常)。
编写全局异常处理器
用 @ControllerAdvice 拦截所有控制器抛出的异常,按类型分别处理:
@ControllerAdvice
public class GlobalExceptionHandler {
// 捕获业务异常(如 ServiceException)
@ExceptionHandler(ServiceException.class)
@ResponseBody
public Result<void> handleServiceException(ServiceException e) {
log.warn("业务异常: {}", e.getMessage(), e);
return Result.fail(e.getCode(), e.getMessage());
}
// 捕获参数校验异常(@Valid)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Result<void> handleValidationException(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
return Result.fail(400, "请求参数错误:" + msg);
}
// 捕获空指针、数组越界等运行时异常(兜底)
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Result<void> handleRuntimeException(RuntimeException e) {
log.error("系统未预期异常", e);
return Result.fail(500, "系统繁忙,请稍后再试");
}
// 捕获所有其他异常(最宽泛兜底)
@ExceptionHandler(Exception.class)
@ResponseBody
public Result<void> handleException(Exception e) {
log.error("未知异常", e);
return Result.fail(500, "服务异常,请联系管理员");
}
}</void></void></void></void>
补充关键细节
-
区分异常层级:自定义
ServiceException继承RuntimeException,用于主动抛出的业务错误(如“余额不足”、“用户不存在”),避免混同系统级异常。 -
日志记录要谨慎:敏感信息(如密码、身份证号)不能打在 error 日志里;对
RuntimeException记录完整堆栈,对ServiceException只需 warn + 消息即可。 -
HTTP 状态码同步设置:在
@ExceptionHandler方法中添加@ResponseStatus(HttpStatus.BAD_REQUEST)注解,确保响应状态码与业务语义一致。 - 避免重复捕获:不要在 Controller 内用 try-catch 吞掉异常再 throw,会绕过全局处理器;除非需要做局部补偿逻辑(如事务回滚后重试)。
前端提示友好性建议
后端只负责返回清晰的 code 和用户可读的 message;前端根据 code 做差异化处理:
- code=401 → 跳转登录页
- code=403 → 弹出“权限不足”提示,不刷新页面
- code=500 → 上报错误 ID(可由后端生成 traceId 并写入响应头),方便排查
- 所有 message 不拼接技术细节(如“NullPointerException”、“Table 'xxx' doesn't exist”)
不复杂但容易忽略。核心是分层拦截、分类响应、前后端约定清晰,就能让异常从“吓人报错”变成“温和提醒”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











