# 文件上传接口文档

## 目录

- [接口概览](#接口概览)
- [通用说明](#通用说明)
- [上传接口（内部）](#上传接口内部)
- [文件管理接口](#文件管理接口)
- [内外部调用规则](#内外部调用规则)
- [错误码](#错误码)

---

## 接口概览

| 类别 | 方法 | 路径 | 说明 |
|------|------|------|------|
| 上传 | `POST` | `/file/upload` | 内部单个上传 |
| 上传 | `POST` | `/file/upload/batch` | 内部批量上传 |
| 管理 | `GET` | `/file-storage/presigned-url/{fileId}` | 获取签名 URL |
| 管理 | `GET` | `/file-storage/info/{fileId}` | 获取文件信息 |
| 管理 | `GET` | `/file-storage/download/{fileId}` | 下载文件 |
| 管理 | `GET` | `/file-storage/list-all` | 全部文件列表 |
| 管理 | `GET` | `/file-storage/list-by-creator` | 按上传者查询 |
| 管理 | `DELETE` | `/file-storage/delete/{fileId}` | 删除文件 |
| 管理 | `DELETE` | `/file-storage/delete-batch` | 批量删除 |

---

## 通用说明

### 基础路径

```
开发环境: http://localhost:{port}
生产环境: 按实际部署域名
```

### 统一响应体

```json
{
  "success": true,
  "code": "0",
  "message": "ok",
  "data": { ... }
}
```

### 文件上传大小限制

| 限制项 | 值 |
|--------|-----|
| 单文件上限 | **100 MB** |
| 单次请求上限 | **500 MB** |

### 支持文件类型

不限制文件类型，支持文本、图片、音频、视频等所有常见格式。

---

## 上传接口（内部）

> **所有上传接口均为内部接口**，需要携带有效登录凭证（Cookie / Token）。  
> 上传完成后自动将文件元信息写入 `filestorage` 表。

---

### 1. 内部单个上传

```
POST /file/upload
```

**请求**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `file` | MultipartFile (form-data) | 是 | 上传的文件 |

**示例**

```bash
curl -X POST "http://localhost:8080/file/upload" \
  -H "Cookie: ..." \
  -F "file=@/path/to/document.pdf"
```

**成功响应**

```json
{
  "success": true,
  "code": "0",
  "message": "ok",
  "data": {
    "id": 1001,
    "url": "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/xxx.pdf",
    "presignedUrl": null,
    "size": 204800,
    "originalFilename": "document.pdf",
    "ext": "pdf",
    "contentType": "application/pdf",
    "creatorName": "张三",
    "createdTime": "2026-06-30T10:30:00"
  }
}
```

| 响应字段 | 类型 | 说明 |
|----------|------|------|
| `id` | Integer | 文件记录主键，后续管理操作依赖此 ID |
| `url` | String | OSS 文件永久访问路径 |
| `presignedUrl` | String | 上传时返回 `null`，需通过签名 URL 接口获取 |
| `size` | Long | 文件大小（字节） |
| `originalFilename` | String | 上传时的原始文件名 |
| `ext` | String | 文件扩展名 |
| `contentType` | String | MIME 类型 |
| `creatorName` | String | 创建人姓名（当前登录用户） |
| `createdTime` | String | 文件创建时间 |

---

### 2. 内部批量上传

```
POST /file/upload/batch
```

**请求**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `files` | List\<MultipartFile\> (form-data) | 是 | 多个上传文件（同名参数） |

**示例**

```bash
curl -X POST "http://localhost:8080/file/upload/batch" \
  -H "Cookie: ..." \
  -F "files=@/path/to/file1.png" \
  -F "files=@/path/to/file2.png" \
  -F "files=@/path/to/file3.png"
```

**成功响应**

```json
{
  "success": true,
  "code": "0",
  "message": "ok",
  "data": [
    { "id": 1001, "url": "...", "size": 204800, "originalFilename": "file1.png", ... },
    { "id": 1002, "url": "...", "size": 307200, "originalFilename": "file2.png", ... }
  ]
}
```

> **部分成功策略**：批量上传时，若某个文件上传失败，该文件被跳过，不影响其余文件的上传。

---

## 文件管理接口

### 3. 获取签名 URL

```
GET /file-storage/presigned-url/{fileId}
```

返回带 1 小时有效期的临时访问链接，用于文件预览或安全分发。

**成功响应**

```json
{
  "success": true,
  "data": {
    "id": 1001,
    "url": "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/xxx.pdf",
    "presignedUrl": "https://test-dragon-yf-pub.oss-cn-hangzhou.aliyuncs.com/jjb/xxx.pdf?Expires=...&OSSAccessKeyId=...&Signature=...",
    "size": 204800,
    "originalFilename": "document.pdf",
    "contentType": "application/pdf",
    "creatorName": "张三",
    "createdTime": "2026-06-30T10:30:00"
  }
}
```

### 4. 获取文件信息

```
GET /file-storage/info/{fileId}
```

仅返回文件元信息，不主动生成签名 URL。

### 5. 下载文件

```
GET /file-storage/download/{fileId}
```

以附件形式流式下载文件，`Content-Disposition: attachment`。

### 6. 删除文件

```
DELETE /file-storage/delete/{fileId}
```

同时删除 OSS 文件与 `filestorage` 表记录，不可恢复。

### 7. 批量删除

```
DELETE /file-storage/delete-batch
Content-Type: application/json

[1001, 1002, 1003]
```

### 8. 列表查询

| 接口 | 说明 |
|------|------|
| `GET /file-storage/list-all` | 查询所有文件记录 |
| `GET /file-storage/list-by-creator?creatorUid=xxx` | 按上传者 UID 查询 |

---

## 内外部调用规则

### 核心原则

| 维度 | 说明 |
|------|------|
| **上传写入** | 必须通过上传接口，由接口自动同步到 `filestorage` 表 |
| **表管理** | `filestorage` 表仅提供读取和删除，不允许直接通过 API 新增/修改记录 |
| **安全性** | 文件不直接暴露 OSS 原始 URL，前端通过签名 URL 获取临时访问权限 |

### 调用流程图

```
┌─────────────┐     POST /file/upload      ┌─────────────┐
│   前端 /    │ ──────────────────────────▶  │  API 层      │
│   调用方    │                              │              │
└─────────────┘                              └──────┬──────┘
                                                    │
                              ┌─────────────────────┼─────────────────────┐
                              ▼                     ▼                     ▼
                       ┌──────────┐         ┌──────────┐         ┌──────────┐
                       │ 上传 OSS  │         │ 写表同步  │         │  获取 ID  │
                       │(x-file-  │         │filestorage│         │ 返回前端  │
                       │ storage) │         │  表记录    │         │          │
                       └──────────┘         └──────────┘         └──────────┘
```

### 创建人区分（扩展预留）

当前所有上传接口均为**内部接口**，创建人取自当前登录用户。扩展场景说明：

| 场景 | 接口路径 | 创建人 | 适用情况 |
|------|----------|--------|----------|
| 内部用户上传 | `/file/upload` | 当前登录用户 | 业务操作中上传附件、素材等 |
| > 公开/匿名通道 | `/file/upload/public` | system | 未登录用户提交（可在需要时暴露） |

### 使用规范

1. **禁止绕过上传接口直接操作表**：`filestorage` 表的新增只能由上传接口内部完成，外部系统不允许直接 INSERT
2. **文件访问走签名 URL**：`presignedUrl` 有效期 1 小时，到期后需重新获取
3. **删除不可逆**：删除操作同时清理 OSS 和 DB，调用前需做二次确认

---

## 错误码

| 错误码 | 说明 |
|--------|------|
| `03-01-001` | 文件上传失败 |
| `03-01-002` | 上传文件为空 |
| `03-01-003` | 文件不存在 |
| `03-01-004` | 文件删除失败 |
| `03-01-005` | 文件下载失败 |
| `03-01-006` | OSS 操作异常 |
| `03-01-007` | 文件地址生成失败 |
| `03-01-008` | 文件大小超出限制 |
