应抛出非检查型 AccountFrozenException 异常,而非通用异常或错误码;它需继承 RuntimeException,支持冻结时间、原因等上下文,应在入口校验时主动抛出,并用 @ExceptionHandler 统一返回 403 响应。

当用户账号被冻结时,应抛出 AccountFrozenException,而不是用通用异常(如 RuntimeException)或返回错误码掩盖问题。这是典型的业务异常场景,需明确区分“可预期的业务失败”与“不可预料的系统错误”。
AccountFrozenException 应继承 RuntimeException
账号冻结属于业务规则触发的明确失败,调用方通常无需强制捕获,但需感知并做对应处理(如提示用户、跳转至解冻页面)。因此建议定义为非检查异常:
- 避免在每层方法签名中声明 throws,减少模板代码
- 便于在 Spring 等框架中配合 @ControllerAdvice 统一处理
- 构造函数支持传入 message 和 frozenTime(冻结时间)、reason(冻结原因)等上下文信息
在关键校验点主动抛出
不要等到执行核心操作(如扣款、登录)失败后才反馈冻结状态。应在入口处或权限校验阶段提前拦截:
- 登录流程:查库获取 User 后,立即判断 status == FROZEN,是则 new AccountFrozenException("账号已被冻结")
- 支付接口:鉴权通过后、扣减余额前,再次校验账号状态(防止并发修改)
- 若使用状态枚举,推荐定义 public enum AccountStatus { NORMAL, FROZEN, CLOSED },避免 magic string
配合统一异常处理器返回友好响应
Spring Boot 中可通过 @ExceptionHandler 捕获该异常,返回结构化 JSON:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- HTTP 状态码建议用 403 FORBIDDEN(权限不足),而非 400 或 500
- 响应体包含 code(如 "ACCOUNT_FROZEN")、message(前端直接展示)、extra(如 unfreezeUrl、contactPhone)
- 日志中记录 userId、frozenAt、operator(谁冻结的),便于排查和审计
避免常见误用
抛出时机和粒度要精准,防止掩盖真实问题:
- 不因数据库连接失败、缓存超时等底层异常误抛 AccountFrozenException
- 不把 “用户名不存在” 和 “账号已冻结” 合并成同一异常,二者语义不同,前端处理逻辑也不同
- 测试时需覆盖正常流程、冻结态流程、以及冻结后状态变更(如解冻)的边界情况
不复杂但容易忽略的是:异常类型本身要能表达意图,而不仅仅是“出错了”。AccountFrozenException 就是告诉所有调用方——这不是 bug,是规则生效。

















