# Prompt First - REQ-011-5 文件上传下载 Controller 和 API 接口 ## 输入引用 引用相关的 docs 文档链接: - [REQ-011.md](../requirements/REQ-011.md) - Salesforce文件上传下载功能总需求 - [REQ-011-5.md](../requirements/REQ-011-5.md) - 文件上传下载 Controller 和 API 接口需求 - [0027-file-infrastructure-enums.md](../decisions/adr/0027-file-infrastructure-enums.md) - 文件上传下载基础设施架构决策 - [0028-attachment-upload-download.md](../decisions/adr/0028-attachment-upload-download.md) - Attachment 文件上传下载架构决策 - [0029-contentdocument-upload-download.md](../decisions/adr/0029-contentdocument-upload-download.md) - ContentDocument 文件上传下载架构决策 - [0030-document-upload-download.md](../decisions/adr/0030-document-upload-download.md) - Document 文件上传下载架构决策 - [0031-file-controller-api.md](../decisions/adr/0031-file-controller-api.md) - 文件上传下载 Controller 和 API 接口架构决策 ## Context Maps 强制列出本次 Prompt 依赖的 Canvas 文件: - [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示 - **相关节点**: [集成核心](node_integration_core) - 提供与Salesforce的各种连接方式 - **相关节点**: [SessionManager](node_session_manager_detail) - 会话管理,提供登录服务 ## 目标 实现 FileController,提供文件上传下载的 RESTful API 接口,支持 Attachment、ContentDocument、Document 三种文件对象类型。用户可以通过 HTTP 请求上传和下载 Salesforce 的三种文件对象,支持指定组织配置 ID。 ### 具体目标 1. 创建 FileController,使用 @RestController 和 @RequestMapping("/files") 注解 2. 实现文件上传接口 POST /files/upload,支持三种文件对象类型 3. 实现文件下载接口 GET /files/download,支持三种文件对象类型 4. 使用 JSR-303 验证注解进行参数验证 5. 使用统一的响应格式 6. 使用策略模式根据文件对象类型调用不同的 Service 7. 使用 Swagger/OpenAPI 注解生成 API 文档 ## 输出格式 ### 代码文件 **文件路径**: `d:\idea_demo\datai\datai-scenes\datai-scene-salesforce\datai-salesforce-integration\src\main\java\com\datai\integration\controller\FileController.java` **代码语言**: Java 17 **代码框架**: Spring Boot 3.5.7 **依赖注解**: - @RestController - @RequestMapping("/files") - @Slf4j - @Tag(name = "文件管理", description = "文件上传下载 API") - @RequiredArgsConstructor - @Autowired **必需导入**: ```java import com.datai.integration.dto.*; import com.datai.integration.enums.FileObjectType; import com.datai.integration.service.*; import io.swagger.v3.oas.annotations.*; import io.swagger.v3.oas.annotations.parameters.*; import io.swagger.v3.oas.annotations.responses.*; import io.swagger.v3.oas.annotations.media.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import jakarta.validation.Valid; import jakarta.validation.constraints.*; ``` ### API 接口定义 #### 1. 文件上传接口 **接口路径**: POST /files/upload **请求参数**: ```java @Parameter(description = "文件对象类型", required = true, example = "ATTACHMENT") @RequestParam("fileObjectType") FileObjectType fileObjectType, @Parameter(description = "组织配置 ID", required = true, example = "org001") @RequestParam("orgConfigId") @NotBlank String orgConfigId, @Parameter(description = "关联记录 ID", required = false, example = "001xx000003DGp2AAG") @RequestParam(value = "relatedRecordId", required = false) String relatedRecordId, @Parameter(description = "文件", required = true) @RequestPart("file") MultipartFile file, @Parameter(description = "文件描述", required = false) @RequestParam(value = "description", required = false) String description ``` **响应格式**: ```java @ApiResponse(responseCode = "200", description = "上传成功", content = @Content(schema = @Schema(implementation = ApiResponse.class))) @ApiResponse(responseCode = "400", description = "请求参数错误", content = @Content(schema = @Schema(implementation = ApiResponse.class))) @ApiResponse(responseCode = "500", description = "服务器内部错误", content = @Content(schema = @Schema(implementation = ApiResponse.class))) ``` **实现逻辑**: ```java @PostMapping("/upload") public ResponseEntity> uploadFile( @RequestParam("fileObjectType") FileObjectType fileObjectType, @RequestParam("orgConfigId") @NotBlank String orgConfigId, @RequestParam(value = "relatedRecordId", required = false) String relatedRecordId, @RequestPart("file") MultipartFile file, @RequestParam(value = "description", required = false) String description) { log.info("收到文件上传请求: fileObjectType={}, orgConfigId={}, fileName={}", fileObjectType, orgConfigId, file.getOriginalFilename()); FileUploadRequest request = FileUploadRequest.builder() .fileObjectType(fileObjectType) .orgConfigId(orgConfigId) .relatedRecordId(relatedRecordId) .file(file) .description(description) .build(); FileUploadResponse response = switch (fileObjectType) { case ATTACHMENT -> attachmentFileService.upload(request); case CONTENT_DOCUMENT -> contentVersionFileService.upload(request); case DOCUMENT -> documentFileService.upload(request); }; log.info("文件上传成功: fileId={}, fileName={}", response.getFileId(), response.getFileName()); return ResponseEntity.ok(ApiResponse.success(response)); } ``` #### 2. 文件下载接口 **接口路径**: GET /files/download **请求参数**: ```java @Parameter(description = "文件对象类型", required = true, example = "ATTACHMENT") @RequestParam("fileObjectType") FileObjectType fileObjectType, @Parameter(description = "组织配置 ID", required = true, example = "org001") @RequestParam("orgConfigId") @NotBlank String orgConfigId, @Parameter(description = "文件 ID", required = true, example = "00Pxx0000016u0HEAQ") @RequestParam("fileId") @NotBlank String fileId ``` **响应格式**: ```java @ApiResponse(responseCode = "200", description = "下载成功", content = @Content(schema = @Schema(implementation = ApiResponse.class))) @ApiResponse(responseCode = "400", description = "请求参数错误", content = @Content(schema = @Schema(implementation = ApiResponse.class))) @ApiResponse(responseCode = "404", description = "文件不存在", content = @Content(schema = @Schema(implementation = ApiResponse.class))) @ApiResponse(responseCode = "500", description = "服务器内部错误", content = @Content(schema = @Schema(implementation = ApiResponse.class))) ``` **实现逻辑**: ```java @GetMapping("/download") public ResponseEntity> downloadFile( @RequestParam("fileObjectType") FileObjectType fileObjectType, @RequestParam("orgConfigId") @NotBlank String orgConfigId, @RequestParam("fileId") @NotBlank String fileId) { log.info("收到文件下载请求: fileObjectType={}, orgConfigId={}, fileId={}", fileObjectType, orgConfigId, fileId); FileDownloadRequest request = FileDownloadRequest.builder() .fileObjectType(fileObjectType) .orgConfigId(orgConfigId) .fileId(fileId) .build(); FileDownloadResponse response = switch (fileObjectType) { case ATTACHMENT -> attachmentFileService.download(request); case CONTENT_DOCUMENT -> contentVersionFileService.download(request); case DOCUMENT -> documentFileService.download(request); }; log.info("文件下载成功: fileId={}, fileName={}", response.getFileId(), response.getFileName()); return ResponseEntity.ok(ApiResponse.success(response)); } ``` ### 统一响应格式 **响应类定义**: ```java @Data @Builder @AllArgsConstructor @NoArgsConstructor public class ApiResponse { private Integer code; private String message; private T data; public static ApiResponse success(T data) { return ApiResponse.builder() .code(200) .message("success") .data(data) .build(); } public static ApiResponse error(Integer code, String message) { return ApiResponse.builder() .code(code) .message(message) .data(null) .build(); } } ``` ## 约束 ### 技术栈约束 1. **Java 版本**: 必须使用 Java 17 2. **Spring Boot 版本**: 必须使用 Spring Boot 3.5.7 3. **Lombok**: 必须使用 Lombok 注解简化代码 4. **Swagger**: 必须使用 Swagger/OpenAPI 3.0 注解生成 API 文档 5. **JSR-303**: 必须使用 JSR-303 验证注解进行参数验证 ### 架构约束 1. **模块约束**: 必须在 datai-salesforce-integration 模块下实现 2. **包路径**: 必须在 com.datai.integration.controller 包下 3. **依赖注入**: 必须使用 @Autowired 或构造函数注入 4. **策略模式**: 必须使用策略模式根据文件对象类型调用不同的 Service 5. **统一响应**: 必须使用统一的响应格式 ### 认证约束 1. **会话管理**: 必须使用 SessionManager 进行会话管理 2. **自动重新登录**: 必须支持自动重新登录机制 3. **组织配置**: 必须支持指定组织配置 ID ### API 设计约束 1. **RESTful 规范**: 必须遵循 RESTful 设计规范 2. **HTTP 方法**: 必须使用正确的 HTTP 方法(POST 用于上传,GET 用于下载) 3. **参数传递**: 必须使用 @RequestParam 和 @RequestPart 注解接收参数 4. **响应状态码**: 必须返回正确的 HTTP 状态码 ### 文档约束 1. **Swagger 注解**: 必须使用 Swagger/OpenAPI 注解生成 API 文档 2. **参数描述**: 必须为每个参数提供详细的描述 3. **响应描述**: 必须为每个响应提供详细的描述 4. **示例数据**: 必须为每个参数和响应提供示例数据 ### 代码质量约束 1. **代码规范**: 必须遵循项目编码规范 2. **日志记录**: 必须使用 @Slf4j 注解记录日志 3. **异常处理**: 必须正确处理异常,提供详细的错误信息 4. **单元测试**: 必须编写单元测试,确保测试覆盖率 ≥ 90% ## Rule Set "请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。" **具体规则**: - 必须使用 Canvas 中定义的类名和方法名 - 必须遵循 Canvas 中定义的调用关系 - 必须参考 Canvas 中的流程图逻辑 **代码规范规则**: - 必须使用 Lombok 注解(@Data、@Builder、@Slf4j、@RequiredArgsConstructor 等) - 必须使用 JSR-303 验证注解(@NotNull、@NotBlank、@Size 等) - 必须使用 Swagger/OpenAPI 注解(@Tag、@Operation、@Parameter、@ApiResponse 等) - 必须使用策略模式(switch-case 语句)根据文件对象类型调用不同的 Service - 必须使用统一的响应格式(ApiResponse) - 必须使用构造函数注入(@RequiredArgsConstructor) - 必须使用 @Valid 注解进行参数验证 **API 设计规则**: - 必须遵循 RESTful 设计规范 - 必须使用正确的 HTTP 方法(POST 用于上传,GET 用于下载) - 必须使用 @RequestParam 和 @RequestPart 注解接收参数 - 必须返回正确的 HTTP 状态码 - 必须提供详细的参数描述和示例数据 - 必须提供详细的响应描述和示例数据 **异常处理规则**: - 必须正确处理异常,提供详细的错误信息 - 必须使用 try-catch 块捕获异常 - 必须记录详细的日志,便于问题排查 - 必须返回统一的错误响应格式 **日志记录规则**: - 必须使用 @Slf4j 注解记录日志 - 必须记录关键操作的开始和结束 - 必须记录异常信息 - 必须记录请求参数和响应结果 ## 验收标准 ### 功能完整性验收标准 1. **上传功能**: 能够成功上传本地文件到 Salesforce Attachment、ContentDocument、Document 对象 2. **下载功能**: 能够成功从 Salesforce Attachment、ContentDocument、Document 对象下载文件到本地 3. **参数验证**: 能够正确验证参数,提供详细的错误信息 4. **异常处理**: 能够正确处理异常,提供详细的错误信息 5. **日志记录**: 能够记录详细的日志,便于问题排查 6. **API 文档**: 能够生成清晰的 API 文档,便于前端调用和集成 ### 代码质量验收标准 1. **代码规范**: 代码符合项目编码规范,有清晰的注释 2. **设计模式**: 使用策略模式封装三种文件对象的上传下载逻辑 3. **单一职责**: 遵循单一职责原则和开闭原则 4. **测试覆盖**: 测试覆盖率 ≥ 90% ### API 设计验收标准 1. **RESTful 规范**: 遵循 RESTful 设计规范 2. **HTTP 方法**: 使用正确的 HTTP 方法(POST 用于上传,GET 用于下载) 3. **参数传递**: 使用 @RequestParam 和 @RequestPart 注解接收参数 4. **响应状态码**: 返回正确的 HTTP 状态码 5. **统一响应**: 使用统一的响应格式 ### 文档质量验收标准 1. **Swagger 注解**: 使用 Swagger/OpenAPI 注解生成 API 文档 2. **参数描述**: 为每个参数提供详细的描述 3. **响应描述**: 为每个响应提供详细的描述 4. **示例数据**: 为每个参数和响应提供示例数据 ### 性能验收标准 1. **上传性能**: 文件上传性能良好,不影响系统响应 2. **下载性能**: 文件下载性能良好,不影响系统响应 3. **并发性能**: 并发上传下载性能良好,不出现资源竞争 ## 风险 ### 输出质量风险 1. **API 设计风险**: API 接口设计可能不够完善 - **缓解措施**: 提前进行 API 设计评审,参考业界最佳实践 2. **参数验证风险**: 参数验证可能不够严格 - **缓解措施**: 使用 JSR-303 验证注解,提供详细的错误信息 3. **响应封装风险**: 响应封装可能不够统一 - **缓解措施**: 定义统一的响应格式,使用统一的响应封装逻辑 ### 技术实现风险 1. **并发风险**: 并发上传下载可能导致资源竞争 - **缓解措施**: 使用线程池,限制并发数,监控并发性能 2. **性能风险**: API 接口性能可能不达标 - **缓解措施**: 提前进行性能测试,优化代码性能 3. **兼容性风险**: 前端可能不兼容新的 API 接口 - **缓解措施**: 提供详细的 API 文档,提供前端集成指南 ### 时间成本风险 1. **开发时间风险**: 开发时间可能超出预期 - **缓解措施**: 提前进行技术调研,参考官方文档和示例代码 2. **测试时间风险**: 测试时间可能超出预期 - **缓解措施**: 提前进行性能测试,优化代码性能 ## 使用记录 | 日期 | 使用场景 | 输入参数 | 输出结果 | 反馈 | 改进措施 | |------|---------|---------|---------|------|----------| | 2026-01-19 | REQ-011-5 阶段 4 执行 | REQ-011-5 需求文档、架构决策文档、提示词文档 | FileController 代码实现 | 待评估 | 待改进 |