# 全局异常处理 **本文引用的文件** - [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 包 ```mermaid 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](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) 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) ## 核心组件 - 全局异常处理器:集中拦截控制器层抛出的各类异常,转换为统一的响应体。 - 自定义异常族: - 业务异常:用于表达明确的业务规则不满足或流程不可继续。 - 参数异常:用于校验失败或缺失必填参数等输入问题。 - 权限异常:用于鉴权失败、越权访问等安全相关问题。 - 资源不存在异常:用于查询不到目标实体或资源的情况。 - 统一响应体:对外暴露一致的 JSON 结构,包含状态码、消息、数据与可选的调试信息。 - 错误码枚举:集中管理业务错误码,保证前后端一致性与可维护性。 章节来源 - [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) ## 架构总览 下图展示了请求进入控制器后,若抛出异常,如何通过全局异常处理器统一转换为标准响应体的流程。 ```mermaid 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](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) ## 详细组件分析 ### 全局异常处理器(GlobalExceptionHandlerAdvice) 职责与行为要点: - 统一入口:通过注解将方法注册为全局异常处理器,拦截指定异常类型。 - 分类处理:针对业务异常、参数异常、权限异常、资源不存在异常分别映射到不同错误码与提示语。 - 响应构造:基于统一响应体封装结果,确保字段稳定、语义清晰。 - 调试信息:在开发环境或特定条件下输出堆栈摘要或追踪ID,便于定位问题。 - 兜底策略:对未预期异常进行安全降级,避免泄露敏感信息。 建议关注点: - 异常优先级与匹配顺序,避免误捕获。 - 日志级别控制,生产环境避免打印敏感内容。 - 与全局过滤器/拦截器的协作,如链路追踪ID透传。 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) ### 自定义异常族 #### 业务异常(BusinessErrorException) - 用途:表达业务规则不满足、流程不可继续等“有明确业务含义”的错误。 - 典型场景:库存不足、订单状态不允许操作、审批流不通过等。 - 设计要点:携带业务错误码与可读消息,便于前端展示与后端统计。 章节来源 - [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java) #### 参数异常(MissingParameterException) - 用途:参数缺失、格式错误或校验失败时抛出。 - 典型场景:必填字段为空、日期格式不正确、分页参数非法等。 - 设计要点:提供清晰的字段级或整体提示信息,利于前端表单反馈。 章节来源 - [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java) #### 权限异常(PermissionErrorException) - 用途:鉴权失败、角色/权限不足、越权访问等安全问题。 - 典型场景:无访问菜单权限、跨部门数据访问受限、Token无效等。 - 设计要点:避免泄露具体权限细节,仅给出通用提示。 章节来源 - [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java) #### 资源不存在异常(ResourceNotExistException) - 用途:查询不到目标实体或资源。 - 典型场景:用户ID不存在、附件已删除、配置项缺失等。 - 设计要点:区分“逻辑不存在”和“系统错误”,避免误报。 章节来源 - [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java) ### 统一响应体与错误码 #### 统一响应体(Result) - 字段约定:状态码、消息、数据、可选调试信息(如traceId)。 - 序列化:保持稳定的JSON键名与类型,便于前端解析。 - 扩展性:预留扩展字段空间,支持后续增强(如请求ID、时间戳等)。 章节来源 - [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java) #### 错误码枚举(ResultCodeEnum) - 作用:集中定义错误码与默认消息,保证一致性。 - 规范:按模块/层级划分,避免冲突;提供友好提示与内部编码分离。 - 使用:在异常构造或处理器中引用,减少硬编码。 章节来源 - [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java) ### 异常处理流程图 下图概括了从异常抛出到统一响应的关键分支逻辑。 ```mermaid flowchart TD Start(["进入全局异常处理器"]) --> Type{"异常类型判断"} Type --> |业务异常| Biz["映射业务错误码
组装业务消息"] Type --> |参数异常| Param["映射参数错误码
组装参数提示"] Type --> |权限异常| Perm["映射权限错误码
组装鉴权提示"] Type --> |资源不存在| Res["映射资源错误码
组装资源提示"] Type --> |其他异常| Fallback["兜底处理
安全降级+脱敏"] Biz --> Build["构建统一响应体"] Param --> Build Perm --> Build Res --> Build Fallback --> Build Build --> Return(["返回标准化JSON"]) ``` 图表来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) ## 依赖关系分析 - 全局异常处理器依赖统一响应体与错误码枚举,实现解耦与复用。 - 自定义异常之间相互独立,便于按需组合与扩展。 - 与上层控制器松耦合:控制器只需抛出异常,无需关心响应构造。 ```mermaid 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](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) 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) ## 性能考虑 - 异常路径属于非主流程,应尽量减少异常抛出的频率,优先使用条件判断与校验。 - 日志输出需分级控制,生产环境避免打印完整堆栈与敏感信息。 - 统一响应体构造应避免不必要的对象创建与复杂计算。 - 错误码枚举查找应为常量级开销,避免动态解析。 ## 故障排查指南 常见问题与定位思路: - 未捕获异常:检查是否遗漏对应异常类型的处理器分支。 - 错误码不一致:核对枚举定义与实际使用是否同步更新。 - 调试信息泄露:确认仅在受控环境下输出,生产环境脱敏。 - 前端解析失败:检查统一响应体字段命名与类型是否稳定。 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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) ## 结论 通过全局异常处理器与自定义异常族的协同,系统实现了异常处理的标准化、可观测与可扩展。遵循本文的最佳实践,可在保障用户体验的同时提升系统的可维护性与稳定性。 ## 附录 ### 最佳实践 - 在业务层尽早校验与断言,减少异常发生概率。 - 使用统一响应体与错误码,避免散落的字符串与魔法值。 - 对敏感信息进行脱敏,避免堆栈与配置泄露。 - 为每个异常类型提供清晰的错误码与提示语,便于前端展示与监控告警。 ### 自定义异常扩展方法 - 新增异常类型:在 domain/exception 下新建异常类,继承基础异常或参照现有模式。 - 注册处理器:在全局异常处理器中添加对应分支,映射错误码与消息。 - 补充错误码:在错误码枚举中新增条目,保持命名与分组规范。 - 单元测试:覆盖正常路径与异常路径,确保响应体结构与字段稳定。 章节来源 - [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) - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.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)