You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

15 KiB

全局异常处理

**本文引用的文件** - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java) - [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java) - [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java) - [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java) - [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java) - [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向全局异常处理系统,系统性说明 GlobalExceptionHandlerAdvice 如何统一捕获并处理业务异常、参数异常、权限异常与资源不存在异常;详解各自定义异常类的用途与使用场景;阐述异常响应格式、错误码规范与调试信息输出策略;并提供最佳实践与扩展自定义异常类型的方法。目标是帮助开发者快速理解、正确使用并安全扩展该体系。

项目结构

全局异常处理相关代码集中在基础模块 crm-base 中:

  • 统一异常处理器位于 advice 包
  • 自定义异常类位于 domain/exception 包
  • 统一响应体与错误码枚举位于 domain/result 包
graph TB
subgraph "基础模块 crm-base"
A["advice/GlobalExceptionHandlerAdvice"] --> B["domain/exception/*"]
A --> C["domain/result/Result"]
A --> D["domain/result/ResultCodeEnum"]
B1["BusinessErrorException"]:::node
B2["MissingParameterException"]:::node
B3["PermissionErrorException"]:::node
B4["ResourceNotExistException"]:::node
B --> B1
B --> B2
B --> B3
B --> B4
end
classDef node fill:#fff,stroke:#333,stroke-width:1px;

图表来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • Result.java
  • ResultCodeEnum.java

章节来源

  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java

核心组件

  • 全局异常处理器:集中拦截控制器层抛出的各类异常,转换为统一的响应体。
  • 自定义异常族:
    • 业务异常:用于表达明确的业务规则不满足或流程不可继续。
    • 参数异常:用于校验失败或缺失必填参数等输入问题。
    • 权限异常:用于鉴权失败、越权访问等安全相关问题。
    • 资源不存在异常:用于查询不到目标实体或资源的情况。
  • 统一响应体:对外暴露一致的 JSON 结构,包含状态码、消息、数据与可选的调试信息。
  • 错误码枚举:集中管理业务错误码,保证前后端一致性与可维护性。

章节来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • Result.java
  • ResultCodeEnum.java

架构总览

下图展示了请求进入控制器后,若抛出异常,如何通过全局异常处理器统一转换为标准响应体的流程。

sequenceDiagram
participant Client as "客户端"
participant Controller as "控制器"
participant Advice as "全局异常处理器"
participant Result as "统一响应体"
participant Enum as "错误码枚举"
Client->>Controller : "发起HTTP请求"
Controller-->>Client : "抛出异常(业务/参数/权限/资源不存在)"
Note over Controller : "异常由框架传播至AOP/拦截层"
Controller->>Advice : "异常被全局处理器捕获"
Advice->>Enum : "根据异常类型选择错误码"
Advice->>Result : "构建统一响应体(含状态码/消息/数据/调试信息)"
Advice-->>Client : "返回标准化JSON响应"

图表来源

  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java

详细组件分析

全局异常处理器(GlobalExceptionHandlerAdvice)

职责与行为要点:

  • 统一入口:通过注解将方法注册为全局异常处理器,拦截指定异常类型。
  • 分类处理:针对业务异常、参数异常、权限异常、资源不存在异常分别映射到不同错误码与提示语。
  • 响应构造:基于统一响应体封装结果,确保字段稳定、语义清晰。
  • 调试信息:在开发环境或特定条件下输出堆栈摘要或追踪ID,便于定位问题。
  • 兜底策略:对未预期异常进行安全降级,避免泄露敏感信息。

建议关注点:

  • 异常优先级与匹配顺序,避免误捕获。
  • 日志级别控制,生产环境避免打印敏感内容。
  • 与全局过滤器/拦截器的协作,如链路追踪ID透传。

章节来源

  • GlobalExceptionHandlerAdvice.java

自定义异常族

业务异常(BusinessErrorException)

  • 用途:表达业务规则不满足、流程不可继续等“有明确业务含义”的错误。
  • 典型场景:库存不足、订单状态不允许操作、审批流不通过等。
  • 设计要点:携带业务错误码与可读消息,便于前端展示与后端统计。

章节来源

  • BusinessErrorException.java

参数异常(MissingParameterException)

  • 用途:参数缺失、格式错误或校验失败时抛出。
  • 典型场景:必填字段为空、日期格式不正确、分页参数非法等。
  • 设计要点:提供清晰的字段级或整体提示信息,利于前端表单反馈。

章节来源

  • MissingParameterException.java

权限异常(PermissionErrorException)

  • 用途:鉴权失败、角色/权限不足、越权访问等安全问题。
  • 典型场景:无访问菜单权限、跨部门数据访问受限、Token无效等。
  • 设计要点:避免泄露具体权限细节,仅给出通用提示。

章节来源

  • PermissionErrorException.java

资源不存在异常(ResourceNotExistException)

  • 用途:查询不到目标实体或资源。
  • 典型场景:用户ID不存在、附件已删除、配置项缺失等。
  • 设计要点:区分“逻辑不存在”和“系统错误”,避免误报。

章节来源

  • ResourceNotExistException.java

统一响应体与错误码

统一响应体(Result)

  • 字段约定:状态码、消息、数据、可选调试信息(如traceId)。
  • 序列化:保持稳定的JSON键名与类型,便于前端解析。
  • 扩展性:预留扩展字段空间,支持后续增强(如请求ID、时间戳等)。

章节来源

  • Result.java

错误码枚举(ResultCodeEnum)

  • 作用:集中定义错误码与默认消息,保证一致性。
  • 规范:按模块/层级划分,避免冲突;提供友好提示与内部编码分离。
  • 使用:在异常构造或处理器中引用,减少硬编码。

章节来源

  • ResultCodeEnum.java

异常处理流程图

下图概括了从异常抛出到统一响应的关键分支逻辑。

flowchart TD
Start(["进入全局异常处理器"]) --> Type{"异常类型判断"}
Type --> |业务异常| Biz["映射业务错误码<br/>组装业务消息"]
Type --> |参数异常| Param["映射参数错误码<br/>组装参数提示"]
Type --> |权限异常| Perm["映射权限错误码<br/>组装鉴权提示"]
Type --> |资源不存在| Res["映射资源错误码<br/>组装资源提示"]
Type --> |其他异常| Fallback["兜底处理<br/>安全降级+脱敏"]
Biz --> Build["构建统一响应体"]
Param --> Build
Perm --> Build
Res --> Build
Fallback --> Build
Build --> Return(["返回标准化JSON"])

图表来源

  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java

依赖关系分析

  • 全局异常处理器依赖统一响应体与错误码枚举,实现解耦与复用。
  • 自定义异常之间相互独立,便于按需组合与扩展。
  • 与上层控制器松耦合:控制器只需抛出异常,无需关心响应构造。
classDiagram
class GlobalExceptionHandlerAdvice {
+处理业务异常()
+处理参数异常()
+处理权限异常()
+处理资源不存在异常()
+兜底处理()
}
class BusinessErrorException
class MissingParameterException
class PermissionErrorException
class ResourceNotExistException
class Result
class ResultCodeEnum
GlobalExceptionHandlerAdvice --> Result : "构造响应"
GlobalExceptionHandlerAdvice --> ResultCodeEnum : "获取错误码"
GlobalExceptionHandlerAdvice --> BusinessErrorException : "捕获"
GlobalExceptionHandlerAdvice --> MissingParameterException : "捕获"
GlobalExceptionHandlerAdvice --> PermissionErrorException : "捕获"
GlobalExceptionHandlerAdvice --> ResourceNotExistException : "捕获"

图表来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • Result.java
  • ResultCodeEnum.java

章节来源

  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java

性能考虑

  • 异常路径属于非主流程,应尽量减少异常抛出的频率,优先使用条件判断与校验。
  • 日志输出需分级控制,生产环境避免打印完整堆栈与敏感信息。
  • 统一响应体构造应避免不必要的对象创建与复杂计算。
  • 错误码枚举查找应为常量级开销,避免动态解析。

故障排查指南

常见问题与定位思路:

  • 未捕获异常:检查是否遗漏对应异常类型的处理器分支。
  • 错误码不一致:核对枚举定义与实际使用是否同步更新。
  • 调试信息泄露:确认仅在受控环境下输出,生产环境脱敏。
  • 前端解析失败:检查统一响应体字段命名与类型是否稳定。

章节来源

  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java

结论

通过全局异常处理器与自定义异常族的协同,系统实现了异常处理的标准化、可观测与可扩展。遵循本文的最佳实践,可在保障用户体验的同时提升系统的可维护性与稳定性。

附录

最佳实践

  • 在业务层尽早校验与断言,减少异常发生概率。
  • 使用统一响应体与错误码,避免散落的字符串与魔法值。
  • 对敏感信息进行脱敏,避免堆栈与配置泄露。
  • 为每个异常类型提供清晰的错误码与提示语,便于前端展示与监控告警。

自定义异常扩展方法

  • 新增异常类型:在 domain/exception 下新建异常类,继承基础异常或参照现有模式。
  • 注册处理器:在全局异常处理器中添加对应分支,映射错误码与消息。
  • 补充错误码:在错误码枚举中新增条目,保持命名与分组规范。
  • 单元测试:覆盖正常路径与异常路径,确保响应体结构与字段稳定。

章节来源

  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • GlobalExceptionHandlerAdvice.java
  • Result.java
  • ResultCodeEnum.java