# 异常处理机制 **本文引用的文件** - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本文件系统化梳理 CRM 后端项目的异常处理机制,重点围绕全局异常处理器 GlobalExceptionHandlerAdvice、自定义业务异常类型(BusinessErrorException、MissingParameterException、PermissionErrorException、ResourceNotExistException)以及统一响应格式(Result、ResultCodeEnum)进行说明。文档涵盖异常分类、错误码规范、统一响应格式、最佳实践与调试技巧,帮助开发者快速定位问题并规范地抛出与处理异常。 ## 项目结构 异常处理相关代码集中在基础模块 crm-base 中: - 全局异常处理器位于 advice 包 - 自定义异常位于 domain/exception 包 - 统一响应体与错误码枚举位于 domain/result 包 - 断言工具位于 utils 包,常用于前置参数校验与快速抛出自定义异常 ```mermaid graph TB subgraph "基础模块 crm-base" A["advice
GlobalExceptionHandlerAdvice"] B["domain/exception
BusinessErrorException
MissingParameterException
PermissionErrorException
ResourceNotExistException"] C["domain/result
Result
ResultCodeEnum"] D["utils
AssertUtils"] end A --> C A --> B D --> B ``` 图表来源 - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) 章节来源 - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) ## 核心组件 - 全局异常处理器 GlobalExceptionHandlerAdvice - 职责:集中捕获控制器层抛出的各类异常,将其转换为统一的 Result 响应体,确保前端/调用方获得一致的错误结构。 - 关键点:按异常类型分别映射到不同的 ResultCodeEnum;对未知异常提供兜底处理;避免泄露敏感信息。 - 自定义异常类型 - BusinessErrorException:通用业务异常,携带业务错误码与消息,用于业务规则不满足或流程失败等场景。 - MissingParameterException:参数缺失或非法异常,用于入参校验失败场景。 - PermissionErrorException:权限不足异常,用于鉴权未通过场景。 - ResourceNotExistException:资源不存在异常,用于查询不到目标数据场景。 - 统一响应体 Result - 职责:对外暴露的标准化返回结构,包含状态码、消息、数据等字段。 - 错误码枚举 ResultCodeEnum - 职责:统一定义业务错误码与描述,保证错误码唯一性与可读性。 - 断言工具 AssertUtils - 职责:提供便捷的前置条件检查方法,条件不满足时直接抛出对应的自定义异常,简化业务代码中的校验逻辑。 章节来源 - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) ## 架构总览 下图展示了请求进入控制器后,异常如何被全局处理器捕获并转换为统一响应的整体流程。 ```mermaid sequenceDiagram participant Client as "客户端" participant Controller as "控制器" participant Service as "业务服务" participant Utils as "断言工具" participant Handler as "全局异常处理器" participant Resp as "统一响应体" Client->>Controller : "发起HTTP请求" Controller->>Service : "执行业务逻辑" Service->>Utils : "参数校验/业务断言" Utils-->>Service : "条件不满足则抛出异常" Service-->>Controller : "正常返回或抛出异常" Controller-->>Handler : "异常向上抛出" Handler->>Handler : "根据异常类型选择错误码" Handler->>Resp : "封装为统一响应体" Handler-->>Client : "返回统一响应" ``` 图表来源 - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) ## 详细组件分析 ### 全局异常处理器 GlobalExceptionHandlerAdvice - 设计要点 - 使用 Spring 的全局异常处理注解,拦截控制器层抛出的异常。 - 针对不同类型的异常分别映射到 ResultCodeEnum 中的对应错误码。 - 将异常信息封装进 Result,确保返回结构一致。 - 对未知异常进行兜底处理,避免泄露堆栈信息。 - 典型处理路径 - 业务异常 -> 业务错误码 -> 统一响应 - 参数异常 -> 参数错误码 -> 统一响应 - 权限异常 -> 权限错误码 -> 统一响应 - 资源不存在 -> 资源错误码 -> 统一响应 - 其他异常 -> 系统错误码 -> 统一响应 - 注意事项 - 不要记录敏感信息到日志或响应体。 - 保持错误码与消息的一致性,便于前端提示与监控告警。 - 对于可恢复的业务错误,优先使用业务异常而非系统异常。 章节来源 - [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) ### 自定义异常类型 - BusinessErrorException - 用途:表达业务规则不满足、流程失败等场景。 - 特点:携带业务错误码与消息,便于上层统一处理与展示。 - MissingParameterException - 用途:入参缺失或非法,通常由参数校验失败触发。 - 特点:明确指向“参数”问题,便于前端提示用户补充或修正。 - PermissionErrorException - 用途:鉴权未通过,如角色不足、权限不足。 - 特点:与认证/授权体系配合,统一返回权限错误码。 - ResourceNotExistException - 用途:查询不到目标资源,如 ID 不存在、数据已被删除。 - 特点:明确区分“业务失败”和“资源不存在”,利于前端差异化提示。 章节来源 - [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 - 作用:对外统一返回结构,包含状态码、消息、数据等字段。 - 建议:成功与失败均使用该结构,便于前端统一解析。 - ResultCodeEnum - 作用:统一定义错误码与描述,保证错误码唯一性与可读性。 - 建议:按领域划分错误码段,避免冲突;新增错误码需同步更新文档与测试。 章节来源 - [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) ### 断言工具 AssertUtils 的使用 - 作用:在业务方法开头进行前置条件校验,条件不满足时直接抛出对应的自定义异常。 - 优势:减少样板代码,提升可读性与一致性。 - 示例场景 - 校验必填参数是否为空 - 校验业务状态是否允许当前操作 - 校验权限或资源是否存在 章节来源 - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.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) ### 异常处理流程图 下图展示从参数校验到统一响应生成的关键步骤。 ```mermaid flowchart TD Start(["入口"]) --> CheckParam["参数校验"] CheckParam --> ParamOK{"参数有效?"} ParamOK --> |否| ThrowParamEx["抛出参数异常"] ParamOK --> |是| BizCheck["业务断言"] BizCheck --> BizOK{"业务合法?"} BizOK --> |否| ThrowBizEx["抛出业务异常"] BizOK --> |是| Process["执行业务逻辑"] Process --> Success["返回成功结果"] ThrowParamEx --> Handle["全局异常处理器捕获"] ThrowBizEx --> Handle Handle --> MapCode["映射错误码"] MapCode --> WrapResp["封装统一响应"] WrapResp --> End(["结束"]) Success --> End ``` 图表来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.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) - [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 Result { +状态码 +消息 +数据 } class ResultCodeEnum { +错误码 +描述 } class BusinessErrorException class MissingParameterException class PermissionErrorException class ResourceNotExistException class AssertUtils { +断言方法() } GlobalExceptionHandlerAdvice --> Result : "封装响应" GlobalExceptionHandlerAdvice --> ResultCodeEnum : "映射错误码" AssertUtils --> BusinessErrorException : "抛出" AssertUtils --> MissingParameterException : "抛出" AssertUtils --> PermissionErrorException : "抛出" AssertUtils --> ResourceNotExistException : "抛出" ``` 图表来源 - [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) - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.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) - [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) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java) ## 性能考虑 - 异常路径应避免频繁创建大对象,尽量复用错误码与消息。 - 全局异常处理器中尽量减少复杂计算与外部IO,确保快速返回。 - 参数校验尽量前置,减少无效业务执行带来的开销。 - 日志记录遵循最小化原则,避免打印敏感信息与超大堆栈。 ## 故障排查指南 - 常见问题 - 前端收到非预期状态码:检查 ResultCodeEnum 是否正确映射。 - 错误消息过于笼统:细化异常消息,结合上下文信息。 - 敏感信息泄露:审查日志与响应体,移除敏感字段。 - 调试技巧 - 在业务方法入口处添加断言,快速定位参数问题。 - 使用全局异常处理器日志输出异常类型与错误码,便于追踪。 - 对关键分支编写单元测试,覆盖异常路径。 - 排查步骤 - 确认请求参数是否符合接口约定。 - 检查业务断言与权限校验逻辑。 - 查看全局异常处理器日志与错误码映射。 - 复现问题并缩小范围,逐步定位根因。 章节来源 - [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java) - [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java) - [AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.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) - 断言工具:[AssertUtils.java](file://crm-base/src/main/java/com/crm/base/utils/AssertUtils.java)