java中抽象类不能直接拦截异常,但可通过@controlleradvice全局异常处理器统一捕获并返回result格式,子类控制器可继承basecontroller复用ok()/fail()方法或直接返回result。

在 Java 中,抽象类本身不能直接“拦截异常”,但可以通过结合 Spring 的 @ControllerAdvice 和统一响应结构,让所有继承自某个抽象控制器的子类共享同一套异常处理与返回格式。核心思路是:**抽象类定义通用响应结构 + 全局异常处理器统一捕获 + 子类控制器按需继承或注入**。
定义统一响应基础格式(抽象/工具类)
建议用一个普通类(非抽象类)封装通用返回结构,便于复用和 JSON 序列化:
public class Result<t> {
private int code;
private String message;
private T data;
public static <t> Result<t> success(T data) {
Result<t> r = new Result();
r.code = 200;
r.message = "OK";
r.data = data;
return r;
}
public static <t> Result<t> fail(int code, String message) {
Result<t> r = new Result<t>();
r.code = code;
r.message = message;
return r;
}
// getter / setter 省略
}</t></t></t></t></t></t></t></t>
这个 Result 类不依赖 Spring,可被任意层(Service、Controller)使用,也方便单元测试。
抽象 Controller 定义公共行为(可选)
若多个 Controller 有共用逻辑(如校验、日志、预处理),可定义抽象基类:
public abstract class BaseController {
protected Result<void> ok() {
return Result.success(null);
}
protected <t> Result<t> ok(T data) {
return Result.success(data);
}
protected Result<void> fail(String msg) {
return Result.fail(400, msg);
}
}</void></t></t></void>
子类控制器继承它后,可直接调用 ok()、fail() 等方法,保持风格一致,但不强制要求继承——真正统一靠的是全局异常处理器。
全局异常拦截(@ControllerAdvice + @ExceptionHandler)
这才是实现“统一异常拦截”的关键。创建一个配置类,捕获所有控制器抛出的业务异常和系统异常:
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
// 捕获自定义业务异常(如 BusinessException)
@ExceptionHandler(BusinessException.class)
public Result<void> handleBusinessException(BusinessException e) {
return Result.fail(e.getCode(), e.getMessage());
}
// 捕获参数校验异常(@Valid)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<void> handleValidationException(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.findFirst().orElse("参数校验失败");
return Result.fail(400, msg);
}
// 捕获其他未预期异常(开发阶段兜底)
@ExceptionHandler(Exception.class)
public Result<void> handleUnexpected(Exception e) {
log.error("未预期异常", e);
return Result.fail(500, "服务内部错误");
}
}</void></void></void>
这样,无论哪个 Controller 抛出这些异常,都会被自动转换为标准 Result 格式返回,前端无需关心具体是哪个接口出错。
子类 Controller 示例(简洁写法)
实际业务控制器只需专注业务逻辑,无需手动 try-catch:
@RestController
@RequestMapping("/api/user")
public class UserController extends BaseController {
@GetMapping("/{id}")
public Result<user> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
throw new BusinessException(404, "用户不存在");
}
return ok(user); // 复用抽象类方法,返回 Result<user>
}
}</user></user>
如果不想继承抽象类,也可以直接返回 Result,完全不影响全局异常处理生效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











