u
This commit is contained in:
1 parent
f3936cec61
commit
15e0ae5b67
115 files changed
+11399
-2741
No files matched your search
@@ -0,0 +1,203 @@
|
||||
---
|
||||
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`** |
|
||||
Reference in new issue
Block a user