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

383 lines
15 KiB
Markdown
Raw Permalink Normal View History

# 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 代码实现 | 待评估 | 待改进 |