Files
workspace/code/g3soft-libs/docs/content/api/file.md
T
2026-10-13 22:32:50 +08:00

204 lines
5.6 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.
---
title: 附件
description: 文件上传(本地 / OSS 直传)、记录落库、删除与静态访问
pageClass: g3-api
---
# 附件
文件接口,前缀 `/file/**`。有两种存储模式,由 `erp.file.storage-type` 决定(`local` / `aliyun-oss`)。
| 模式 | 上传链路 |
|---|---|
| `local` | 前端直接 POST 文件 → 后端写盘 + 落库 |
| `aliyun-oss` | 取凭证 → 前端直传 OSS → 回调后端落库 |
> **第一步先问模式**:调 `/file/config` 拿到当前模式,再决定走哪条链路。前端组件不要写死。
## `POST` `/file/config`
返回当前存储模式。
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "操作成功",
"data": { "storageType": "local" }
}
```
</G3ApiPayload>
## `POST` `/file/upload`
**本地上传**(`storage-type=local` 时使用)。支持多文件,**是 `multipart/form-data`,不是 JSON**。
<G3ApiParams title="表单字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `files` | file[] | 是 | 文件,key 固定为 `files`,可重复 |
| `father` | string | 是 | 宿主业务主键(存宿主 `b_id`) |
| `moduleId` | string | 是 | 模块编码 |
| `cateId` | string | | 分类 ID |
</G3ApiParams>
<G3ApiPayload title="请求">
```bash
curl -X POST http://localhost:8088/api/file/upload \
-H 'Authorization: Bearer <token>' \
-F 'files=@report.pdf' \
-F 'father=1234567890' \
-F 'moduleId=v_b_othercompany' \
-F 'cateId=987654321'
```
</G3ApiPayload>
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "操作成功",
"data": [
{
"subid": "1234567890123",
"mx_filename": "report.pdf",
"mx_filesize": "20480",
"mx_fileext": "pdf",
"mx_mapfilename": "/api/file/static/G3HD/2026/10/13/abc.pdf",
"father": "1234567890",
"mx_moduleid": "v_b_othercompany",
"mx_cate_id": "987654321"
}
]
}
```
</G3ApiPayload>
- `mx_mapfilename` 就是**访问地址**,预览 / 下载直接用它。
- `subid` 是雪花 ID,**本地模式由后端自己取号**后写入 `bf_files`(前端不用管)。
## `POST` `/file/upload-credential`
**取 OSS 直传凭证**(`storage-type=aliyun-oss` 时使用)。无请求字段。
后端转发到 g3oss,`bucket` 即当前机构码。
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "操作成功",
"data": {
"accessid": "LTAI...",
"policy": "eyJleHBpcmF0aW9uIjoi...",
"signature": "abc123==",
"dir": "G3HD/",
"host": "https://g3soft.oss-cn-hangzhou.aliyuncs.com",
"expire": 1700000000
}
}
```
</G3ApiPayload>
> **字段以 g3oss 实际返回为准**:后端只做 `readValue(...).Map` 的**原样透传**,不加工也不改名。
> 上面是 OSS 直传的常见字段形状,接入时请以实际返回为准;凭证有有效期,取到后应尽快直传。
## `POST` `/file/save-record`
**OSS 直传完成后回调落库**(`storage-type=aliyun-oss` 时使用)。本地模式不需要单独调它。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `subid` | number | 是 | 上传前取的雪花 ID |
| `father` | string | 是 | 宿主业务主键 |
| `mx_moduleid` | string | 是 | 模块编码 |
| `mx_cate_id` | string | | 分类 ID |
| `mx_filename` | string | 是 | 原始文件名 |
| `mx_filesize` | string | 是 | 文件大小(字节) |
| `mx_fileext` | string | 是 | 扩展名 |
| `mx_mapfilename` | string | 是 | OSS 返回的完整 URL |
</G3ApiParams>
<G3ApiPayload title="响应" :code="0">
```json
{
"code": 0,
"message": "操作成功",
"data": { "subid": "1234567890123", "message": "记录已保存" }
}
```
</G3ApiPayload>
> **`subid` 在 OSS 链路必须由前端在上传前取号**(调 `/data/nextid`),因为凭证直传时后端不在链路上,无法代为取号。
> 本地链路则相反:**后端自己取号**,前端不用传。两条链路都不能依赖数据库自增。
## `POST` `/file/delete`
删除文件:**先删存储、后删 DB 行**。
<G3ApiParams title="请求字段">
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `subid` | string | 是 | 文件记录 ID |
</G3ApiParams>
<G3ApiPayload title="响应" :code="0">
```json
{ "code": 0, "message": "操作成功", "data": null }
```
</G3ApiPayload>
外部对象操作**不属于数据库事务**:
- 删存储失败 → **不删数据库行**(保持可重试)。
- 数据库删除失败 → 保留可重试的清理记录。
记录不存在时静默返回成功(幂等)。
## `GET` `/file/static/{fileName}`
**本地模式**下的文件访问入口。不是 JSON 接口,直接返回文件流。
```text
GET /api/file/static/G3HD/2026/10/13/abc.pdf
```
- 路径形如 `{orgId}/{yyyy}/{MM}/{dd}/{file}`,与 `mx_mapfilename` 去掉前缀后的部分对应。
- 带**路径穿越防护**:解析后必须仍在存储根目录内,否则 404。
- 响应头带 `Content-Disposition: inline`,浏览器可直接预览。
## 相关数据表
| 表 | 说明 |
|---|---|
| `bf_files` | 文件记录(主键 `subid` 雪花 ID,`father` 存宿主主键) |
| `bf_files_category` | 文件分类(`b_module_id` 为空表示跨模块通用分类) |
## 常见错误
| 场景 | 表现 |
|---|---|
| 本地上传时缺少 `files` | `1000` 参数错误 |
| 文件静态访问越界或不存在 | **HTTP 404**(这条路径不走统一响应格式) |
| OSS 凭证获取失败 | `1000`「获取 OSS 上传凭证失败: {状态码}」 |
| 存储模式不匹配 | 例如 `local` 模式下调 `/file/save-record` 会落库成功但文件并不存在——**要先查 `/file/config`** |