spring mvc 中应使用 @controlleradvice + @exceptionhandler 实现统一异常处理,而非 @aspect 切面,因 aop 无法介入 spring mvc 异常分发流程;需定义通用 result 响应体并配合 @responsestatus 或 httpservletresponse 设置状态码。

Spring MVC 中通过统一异常处理实现规范错误码返回,核心是用 @ControllerAdvice + @ExceptionHandler,而非切面(AOP)。虽然 AOP 可用于日志、权限等横切逻辑,但异常捕获和响应封装在 Web 层更自然、更可控——因为 HandlerExceptionResolver 机制原生支持且语义清晰。
为什么不用 @Aspect 处理异常?
Spring AOP 的 @Around 切面无法直接捕获控制器方法抛出的未处理异常(它只拦截方法调用,不介入 Spring MVC 的异常分发流程);即使强行 try-catch,也无法替代 DispatcherServlet 后续的异常解析链(如 ResponseStatusExceptionResolver),容易导致状态码丢失、响应体混乱或重复处理。
真正推荐的方式是:
- 用
@ControllerAdvice全局捕获异常 - 配合
@ExceptionHandler方法统一构造 JSON 响应 - 返回标准结构(如
{ "code": 5001, "msg": "参数校验失败", "data": null })
定义统一响应格式
先建一个通用返回体,例如:
public class Result<t> {
private int code;
private String msg;
private T data;
public static <t> Result<t> fail(int code, String msg) {
Result<t> r = new Result();
r.code = code;
r.msg = msg;
return r;
}
public static <t> Result<t> success(T data) {
Result<t> r = new Result();
r.code = 200;
r.msg = "OK";
r.data = data;
return r;
}
// getter/setter 略
}</t></t></t></t></t></t></t>
编写全局异常处理器
创建一个带 @ControllerAdvice 的类,覆盖常见异常:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
// 捕获业务异常(如自定义 BusinessException)
@ExceptionHandler(BusinessException.class)
public Result<object> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
// 捕获参数校验异常(@Valid)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<object> handleValidationException(MethodArgumentNotValidException e) {
String defaultMessage = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(4000, "参数错误: " + defaultMessage);
}
// 捕获空指针等运行时异常(兜底)
@ExceptionHandler(RuntimeException.class)
public Result<object> handleRuntimeException(RuntimeException e) {
log.error("系统异常", e);
return Result.fail(5000, "系统繁忙,请稍后再试");
}
// 捕获所有其他异常(谨慎使用,避免掩盖问题)
@ExceptionHandler(Exception.class)
public Result<object> handleException(Exception e) {
log.error("未预期异常", e);
return Result.fail(5001, "服务异常");
}
}</object></object></object></object>
注意:@ResponseBody 必须加上,否则返回的是视图名而非 JSON;异常顺序有优先级,更具体的异常类型要写在前面。
配合状态码与 HTTP Header
如果需要同时设置 HTTP 状态码(如 400、500),可在 @ExceptionHandler 方法中加 @ResponseStatus 或手动设 response.setStatus():
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Result<object> handleBusinessException(...) { ... }</object>
或者注入 HttpServletResponse:
@ExceptionHandler(BusinessException.class)
public Result<object> handleBusinessException(BusinessException e, HttpServletResponse response) {
response.setStatus(400);
return Result.fail(e.getCode(), e.getMessage());
}</object>
补充:让校验注解自动触发统一处理
确保 Controller 方法参数用了 @Valid 或 @Validated,例如:
@PostMapping("/user")
public Result<user> createUser(@Valid @RequestBody UserDTO dto) {
return Result.success(userService.create(dto));
}</user>
这样 MethodArgumentNotValidException 才会被上面的处理器捕获,无需额外 try-catch。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










