# API设计 **本文引用的文件** - [ApiResponse.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java) - [GlobalExceptionHandler.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java) - [BusinessException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/BusinessException.java) - [AuthenticationException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/AuthenticationException.java) - [SaveObjectException.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/SaveObjectException.java) - [ParamUtils.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java) - [AuthController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java) - [DataController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java) - [FileController.java](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考虑](#性能考虑) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本规范文档面向FMS API的RESTful接口设计与实现,聚焦以下目标: - 统一响应格式与数据封装:基于 ApiResponse 记录体提供一致的成功/失败返回结构。 - 全局异常处理:通过 GlobalExceptionHandler 集中捕获业务异常、认证异常、保存异常及系统异常,并输出标准化错误响应。 - 请求参数验证与类型转换:使用 ParamUtils 进行参数提取、必填校验与类型检查,避免控制器内重复逻辑。 - 版本管理与向后兼容:在URL路径中引入版本前缀,结合字段级兼容性策略保障演进安全。 - 最佳实践与常见问题:总结接口命名、状态码、错误信息、幂等性与分页等实践建议。 ## 项目结构 FMS API采用分层组织: - controller:对外暴露REST端点,负责参数接收与响应封装。 - service:业务逻辑(不在本文重点)。 - exception:自定义异常与全局异常处理器。 - utils:通用工具类,包括统一响应体 ApiResponse、参数工具 ParamUtils 等。 ```mermaid graph TB Client["客户端"] --> Ctl_Auth["AuthController
/auth/*"] Client --> Ctl_Data["DataController
/data/*"] Client --> Ctl_File["FileController
/file/*"] Ctl_Auth --> Svc_Auth["AuthService"] Ctl_Data --> Svc_Data["DataService / DataSaveService"] Ctl_File --> Svc_File["FileService"] Ctl_Auth --> Resp["ApiResponse"] Ctl_Data --> Resp Ctl_File --> Resp Ctl_Auth --> Ex_Hdl["GlobalExceptionHandler"] Ctl_Data --> Ex_Hdl Ctl_File --> Ex_Hdl ``` 图表来源 - [AuthController.java:19-57](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L57) - [DataController.java:19-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java#L19-L96) - [FileController.java:28-113](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L113) - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) 章节来源 - [AuthController.java:19-57](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L57) - [DataController.java:19-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java#L19-L96) - [FileController.java:28-113](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L113) - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) ## 核心组件 - 统一响应体 ApiResponse:以记录体形式定义 code、message、data 三字段,并提供 success/fail 静态工厂方法;内置常用状态码常量,便于跨模块复用。 - 参数工具 ParamUtils:提供 getString/getRequiredString/get/getList/getArray 等方法,支持空值与类型校验,并在不合法时抛出 BusinessException。 - 全局异常处理器 GlobalExceptionHandler:集中处理认证异常、业务异常、保存异常、数据库异常与未知异常,统一返回 ApiResponse 并记录日志。 章节来源 - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) - [ParamUtils.java:13-58](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L13-L58) - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) ## 架构总览 API层遵循“控制器薄、服务厚”的原则: - 控制器仅做参数解析、调用服务、封装响应。 - 业务规则集中在服务层,必要时抛出自定义异常。 - 全局异常处理器将异常转换为统一的 ApiResponse。 ```mermaid sequenceDiagram participant C as "客户端" participant A as "AuthController" participant S as "AuthService" participant E as "GlobalExceptionHandler" participant R as "ApiResponse" C->>A : POST /auth/login {orgid, userid, password} A->>A : 参数校验(ParamUtils/StringUtils) A->>S : login(orgId, userId, password, request) alt 认证成功 S-->>A : Map A-->>C : ApiResponse.success(data) else 认证失败 A-->>C : ApiResponse.fail(AUTH_ERROR_CODE, message) end Note over A,S : 若发生未捕获异常,由E统一处理并返回系统错误 ``` 图表来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) - [GlobalExceptionHandler.java:20-28](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L20-L28) - [ApiResponse.java:16-30](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L16-L30) ## 详细组件分析 ### 统一响应体 ApiResponse - 结构:code(数字)、message(字符串)、data(泛型)。 - 成功构造:success(data)、success(message, data)。 - 失败构造:fail(message)、fail(code, message)。 - 状态码约定: - 0:成功 - 401:认证错误 - 40101:会话被顶替 - 2001:保存失败 - 1000:业务错误 - 500:系统错误 ```mermaid classDiagram class ApiResponse~T~ { +int code +String message +T data +static success(T) +static success(String, T) +static fail(String) +static fail(int, String) } ``` 图表来源 - [ApiResponse.java:3-30](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L3-L30) 章节来源 - [ApiResponse.java:1-32](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L1-L32) ### 全局异常处理 GlobalExceptionHandler - 认证异常 AuthenticationException:返回 401 认证错误。 - 业务异常 BusinessException:返回 1000 业务错误。 - 保存异常 SaveObjectException:返回 2001 保存失败,并附带 table/action/index 详情。 - 数据库异常 SQLException/DataAccessException:记录系统异常日志,返回 500 系统错误。 - 其他异常 Exception:兜底捕获,记录日志并返回 500。 ```mermaid flowchart TD Start(["进入异常处理"]) --> Type{"异常类型?"} Type --> |AuthenticationException| AuthErr["返回 401 认证错误"] Type --> |BusinessException| BizErr["返回 1000 业务错误"] Type --> |SaveObjectException| SaveErr["返回 2001 保存失败
附加table/action/index"] Type --> |SQLException/DataAccessException| DBErr["记录系统异常日志
返回 500"] Type --> |其他Exception| SysErr["记录系统异常日志
返回 500"] AuthErr --> End(["结束"]) BizErr --> End SaveErr --> End DBErr --> End SysErr --> End ``` 图表来源 - [GlobalExceptionHandler.java:20-83](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L20-L83) 章节来源 - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) - [BusinessException.java:1-9](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/BusinessException.java#L1-L9) - [AuthenticationException.java:1-9](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/AuthenticationException.java#L1-L9) - [SaveObjectException.java:1-33](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/SaveObjectException.java#L1-L33) ### 请求参数验证与类型转换 ParamUtils - getString/getRequiredString:从Map中取值,必填项为空时抛出业务异常。 - get:按类型取值并进行类型校验,类型不符抛出业务异常。 - getList/getArray:集合与数组转换,类型不符抛出业务异常。 - 适用场景:控制器中统一参数解析,减少样板代码与分支判断。 ```mermaid flowchart TD In(["传入 params, field, type"]) --> GetVal["获取原始值"] GetVal --> NullCheck{"值为空?"} NullCheck --> |是| ReturnNull["返回 null"] NullCheck --> |否| TypeCheck{"类型匹配?"} TypeCheck --> |否| ThrowBiz["抛出业务异常"] TypeCheck --> |是| Cast["类型转换并返回"] ``` 图表来源 - [ParamUtils.java:13-58](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L13-L58) 章节来源 - [ParamUtils.java:1-60](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L1-L60) ### 控制器与API设计示例 #### 认证接口 AuthController - 路径:POST /auth/login - 请求体:包含 orgid、userid、password - 行为:参数校验 -> 调用服务 -> 成功返回统一数据,失败返回认证错误码 - 异常:缺失参数或认证失败会返回对应业务/认证错误 ```mermaid sequenceDiagram participant C as "客户端" participant A as "AuthController" participant P as "ParamUtils" participant S as "AuthService" participant R as "ApiResponse" C->>A : POST /auth/login A->>P : getString("orgid"/"userid"/"password") P-->>A : 参数值或抛出业务异常 A->>S : login(...) alt 成功 S-->>A : Map A-->>C : ApiResponse.success(Map) else 失败 A-->>C : ApiResponse.fail(401, "认证失败") end ``` 图表来源 - [AuthController.java:26-55](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L26-L55) - [ParamUtils.java:13-23](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L13-L23) - [ApiResponse.java:16-30](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ApiResponse.java#L16-L30) 章节来源 - [AuthController.java:19-57](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L57) #### 数据接口 DataController - 路径:/data/loaddata、/data/loaddatabysql、/data/page、/data/saveobjt、/data/nextid、/data/nextcode、/data/describe - 行为:参数解析 -> 调用数据服务 -> 返回统一响应 - 注意:saveobjt 可能触发 SaveObjectException,由全局处理器统一返回 2001 ```mermaid sequenceDiagram participant C as "客户端" participant D as "DataController" participant DS as "DataService/DataSaveService" participant R as "ApiResponse" C->>D : POST /data/{endpoint} D->>DS : 执行查询/保存/生成ID/描述等操作 DS-->>D : 结果或抛出异常 alt 正常 D-->>C : ApiResponse.success(...) else 保存异常 D-->>C : 由全局处理器返回 2001 end ``` 图表来源 - [DataController.java:29-94](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java#L29-L94) - [GlobalExceptionHandler.java:30-46](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L30-L46) 章节来源 - [DataController.java:19-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java#L19-L96) #### 文件接口 FileController - 路径:/file/config、/file/upload、/file/upload-credential、/file/save-record、/file/delete、/file/static/{fileName:.+} - 行为:上传本地/OSS凭证、保存记录、删除文件、静态资源访问(含路径穿越防护) - 注意:静态资源访问需校验路径合法性,防止越权访问 ```mermaid sequenceDiagram participant C as "客户端" participant F as "FileController" participant FS as "FileService" participant R as "ApiResponse" C->>F : POST /file/upload (files, father, moduleId, cateId?) F->>FS : localUpload(...) FS-->>F : 文件元数据列表 F-->>C : ApiResponse.success(列表) C->>F : GET /file/static/{fileName} F->>F : 路径穿越校验 alt 合法 F-->>C : 二进制流 else 非法 F-->>C : 404 end ``` 图表来源 - [FileController.java:41-111](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L41-L111) 章节来源 - [FileController.java:28-113](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L113) ## 依赖关系分析 - Controller 依赖 Service 与 Utils(ParamUtils、ApiResponse)。 - GlobalExceptionHandler 依赖 ApiResponse 与各自定义异常类型。 - ParamUtils 依赖 BusinessException 进行参数校验失败时的异常抛出。 ```mermaid graph LR AuthCtl["AuthController"] --> Resp["ApiResponse"] DataCtl["DataController"] --> Resp FileCtl["FileController"] --> Resp AuthCtl --> Param["ParamUtils"] DataCtl --> Param FileCtl --> Param GlobalHdl["GlobalExceptionHandler"] --> Resp GlobalHdl --> BizEx["BusinessException"] GlobalHdl --> AuthEx["AuthenticationException"] GlobalHdl --> SaveEx["SaveObjectException"] ``` 图表来源 - [AuthController.java:19-57](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/AuthController.java#L19-L57) - [DataController.java:19-96](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/DataController.java#L19-L96) - [FileController.java:28-113](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L28-L113) - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) - [ParamUtils.java:1-60](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L1-L60) 章节来源 - [GlobalExceptionHandler.java:15-85](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L15-L85) - [ParamUtils.java:1-60](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L1-L60) ## 性能考虑 - 统一响应体为轻量记录体,序列化开销低,适合高频接口。 - 参数解析集中在 ParamUtils,减少控制器分支与重复校验,提升可维护性。 - 全局异常处理器集中记录系统异常日志,便于定位问题与监控告警。 - 文件静态资源访问直接读取磁盘,注意大文件传输与缓存策略(如条件请求、分片下载)。 [本节为通用指导,无需具体文件引用] ## 故障排查指南 - 认证失败:检查 /auth/login 的请求体是否包含 orgid、userid、password,确认服务端认证逻辑。 - 参数错误:关注 ParamUtils 抛出的业务异常,核对字段名与类型。 - 保存失败:查看 SaveObjectException 中的 table、action、index 信息,定位具体操作与行号。 - 数据库异常:检查 SQL 与连接配置,关注全局异常处理器记录的系统异常日志。 - 文件访问异常:确认 /file/static 的路径拼接与权限控制,避免路径穿越。 章节来源 - [GlobalExceptionHandler.java:20-83](file://fms-api/src/main/java/cn/g3soft/fmsapi/exception/GlobalExceptionHandler.java#L20-L83) - [ParamUtils.java:13-58](file://fms-api/src/main/java/cn/g3soft/fmsapi/utils/ParamUtils.java#L13-L58) - [FileController.java:92-111](file://fms-api/src/main/java/cn/g3soft/fmsapi/controller/FileController.java#L92-L111) ## 结论 本项目通过 ApiResponse 统一响应、ParamUtils 统一参数校验、GlobalExceptionHandler 统一异常处理,构建了清晰、稳定且易扩展的API基础能力。建议在后续开发中: - 严格遵循RESTful命名与HTTP语义。 - 在控制器中保持薄逻辑,复杂规则下沉至服务层。 - 使用 ParamUtils 进行参数校验,避免散落分支。 - 通过全局异常处理器保证错误响应一致性。 - 引入API版本管理,确保向后兼容。 [本节为总结性内容,无需具体文件引用] ## 附录 ### RESTful API设计规范 - URL设计 - 使用名词复数表示资源集合,例如 /data、/file。 - 使用HTTP动词表达操作:GET读取、POST创建/提交、PUT更新、DELETE删除。 - 如需过滤/分页,使用查询参数:?page=1&size=20。 - 状态码 - 业务状态码:0成功、1000业务错误、2001保存失败、401认证错误、500系统错误。 - HTTP状态码:优先使用2xx/4xx/5xx,业务错误可在 ApiResponse.code 中体现。 - 请求/响应 - 请求体使用JSON,键名为小写下划线或驼峰(团队统一即可)。 - 响应体统一为 ApiResponse{code,message,data}。 - 版本管理 - 在URL中加入版本前缀:/v1/auth/login、/v1/data/page。 - 新增字段时保持向后兼容:新增可选字段、保留旧字段。 - 废弃字段通过弃用标记与过渡期公告,逐步移除。 - 幂等与安全 - 读操作幂等;写操作尽量设计为幂等(如基于唯一键的upsert)。 - 敏感信息不放入URL;使用HTTPS与鉴权机制。 - 文件访问需校验路径,防止越权。 [本节为通用规范说明,无需具体文件引用] ### 常见问题与解决方案 - 问题:前端无法解析响应 - 解决:确保所有接口返回 ApiResponse 结构,避免直接返回原始对象。 - 问题:参数类型不匹配 - 解决:使用 ParamUtils.get 指定类型,或在控制器中进行显式转换。 - 问题:保存失败难以定位 - 解决:在服务层抛出 SaveObjectException,携带 table/action/index,由全局处理器统一返回。 - 问题:系统异常无日志 - 解决:依赖 GlobalExceptionHandler 的兜底异常处理,确保记录 method/uri 与堆栈。 - 问题:文件越权访问 - 解决:对静态资源路径进行规范化与白名单校验,拒绝越界路径。 [本节为通用问题解答,无需具体文件引用]