datai/docs/archive/prompts/032-file-controller-api.md

383 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<ApiResponse<FileUploadResponse>> 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<ApiResponse<FileDownloadResponse>> 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<T> {
private Integer code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.code(200)
.message("success")
.data(data)
.build();
}
public static <T> ApiResponse<T> error(Integer code, String message) {
return ApiResponse.<T>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 代码实现 | 待评估 | 待改进 |