跳转至

文件上传(FileUploadController)

提供 KMS 知识管理模块「文件上传域」的能力:将一个或多个文件上传到指定网盘文件夹(含按目录结构上传整棵文件夹)。本控制器共 2 个端点。

注意:本控制器为 KMS 版(@RestController(value="KmFileUploadController"),包 cn.myapps.kms.controller),与运行时模块的 UploadControllercn.myapps.kms.common.controller,见 upload.md)及 runtime 模块的同名控制器均不同——请勿混淆。

Runtime Feign:表单附件 filePattern=02 时,Runtime 经 KmsApi 先调 folder.md #11 resolve-or-createfolderId,再调本页 #1 上传文件folderId + files diskId 参数)。详见 runtime/file-upload.md

  • 接口类型:REST 资源(@RestController,方法未声明 produces,由全局消息转换器按 JSON 处理)
  • 基址${myapps.context-path.kms:}/api(类级 @RequestMapping 仅声明单一前缀;端点路径以 /kms/... 开头)
  • Tag:kms文件上传模块

公共说明

  • 鉴权(据源码 KmsMvcConfig + KmsSecurityFilterKmsMvcConfig 注册全局 Servlet 过滤器 KmsSecurityFilter(URL 模式 /*,context-path 为 / 时为 /kms/*)。本控制器路径 /api/kms/upload/api/kms/folder/upload 不在 KmsSecurityFilter.isExcludeURI 的豁免名单内(豁免仅覆盖 /login.*/admin/domain.*/tray/service/authtimeservice/OfficeServer.*outsideshare/.*/preview、静态资源后缀、actuator/health 等;/kms/uploads 下载路径虽豁免,但本控制器为 /kms/upload/kms/folder/upload 上传路径,不在豁免范围)。过滤器调用 Security.getUserIdFromToken(request),取不到用户则返回 HTTP 401因此所有端点均需 accessToken,可通过以下任一方式传递(据 Security.getUserIdFromToken):query 参数 accessToken、query 参数 access_token(移动端)、请求头 accessToken、Cookie accessToken、请求头 Authorization: Bearer <token>。完整鉴权机制见 index.md「鉴权说明」。
  • 执行用户:控制器内 getUser()(继承自 AbstractBaseController)调用 Security.getUserIdFromToken(request) 还原当前用户 id,再经 Feign(UserAPI.getUserById)装载 KmsUser,用于写入 creator/creatorId/domainIduserCode 参数
  • 响应结构:统一 Resource(见 ../index.md「统一响应结构」),字段为 errcode/errmsg/data/errors
  • 文件类型校验:上传时调用 cn.myapps.core.util.file.FileUtil.isLegalFileExt(extensions) 校验扩展名;非法时本控制器**显式**返回 errcode=4001(非默认错误码,见模块 index「错误码补充」)。
  • 存储路径:文件按内容 MD5 校验和分桶存储:前 2 位为目录名、后 30 位为文件名,落盘至 ${storageRootPath}/kms/.objects/<前2位>/<后30位>;上传前先写临时文件计算 checksum,再 Files.copy 到最终位置并删除临时文件。
  • 异步后处理:上传完成后投递 KMS 后处理任务(摘要+关键词抽取、Lucene 索引、AI 向量化);任务投递失败仅记录日志、不影响上传结果。
  • 错误处理folderId 为空或 multipartFiles.length == 0 时抛 MissingServletRequestPartException(HTTP 400);写盘异常包装为 HttpMessageNotWritableException(HTTP 406)。

1. 上传文件

将一个或多个文件上传到指定的目标文件夹(folderId)。每个文件创建一条 FileEntity 记录(originType=UPLOAD),并投递索引建立任务。若传入 sourceFileId,则按源文件覆盖更新(保留原 Id、同步更新摘要记录、投递索引更新任务)。

  • 接口类型:REST 资源
  • 请求方式POST
  • 请求路径/kms/upload(完整:{kms-context}/api/kms/upload
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件上传模块

请求参数

参数名 位置 类型 必填 说明
folderId query/form string 目标文件夹Id(决定文件归属与网盘Id)
files body(form) file[] 一个或多个文件(表单字段名固定为 files
category query/form string 标签名逗号分隔串(写入文件 categorys 字段)
sourceFileId query/form string 源文件Id;传入时按源文件覆盖更新而非新建

请求示例

POST /api/kms/upload?folderId=__FOLDERID__&category=报告,审批&accessToken=__TOKEN__ HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="folderId"

__FOLDERID__
------WebKitFormBoundary
Content-Disposition: form-data; name="files"; filename="报告.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document

(二进制内容)
------WebKitFormBoundary--

响应

结构:统一 ResourcedataList<Map>,每项结构如下:

字段 类型 说明
fileName string 原始文件名
filePath string 上传后路径前缀+相对路径(FileUtil.UPLOAD_FOLDER_PATH + url
id string 文件Id(新建为随机 UUID;覆盖更新时为源文件Id)
fileSize long 文件大小(字节)
fileType string . 的扩展名(如 .docx

成功示例

{
  "errcode": 0,
  "errmsg": "ok",
  "data": [
    { "fileName": "报告.docx", "filePath": "/kms/uploads/a3/abcdef...", "id": "__FILEID__", "fileSize": 10240, "fileType": ".docx" }
  ],
  "errors": null
}

失败示例(文件类型不合法,显式返回 4001)

{ "errcode": 4001, "errmsg": "上传的文件类型不合法!", "data": null, "errors": null }

失败示例(文件为空):抛 MissingServletRequestPartException(HTTP 400)。


2. 上传文件夹

按前端拖拽上传文件夹场景,将一组文件连同其目录结构(filesPath)整体上传到指定网盘下。服务端会按最深目录逐层创建 FolderEntity,再将每个文件归位到对应子文件夹。

  • 接口类型:REST 资源
  • 请求方式POST
  • 请求路径/kms/folder/upload(完整:{kms-context}/api/kms/folder/upload
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件上传模块

请求参数

参数名 位置 类型 必填 说明
folderId query/form string 目标根文件夹Id(目录树挂载点)
diskId query/form string 网盘Id
files body(form) file[] 一个或多个文件(表单字段名固定为 files
filesPath query/form string[] files 一一对应的目录结构路径(前端拖拽上传时携带,用于重建目录树)

说明:服务端将 filesPath[i]files[i].getOriginalFilename() 配合解析目录层级;文件名以 ~ 开头(Office 临时文件)会被跳过。

请求示例

POST /api/kms/folder/upload?folderId=__FOLDERID__&diskId=__DISKID__&filesPath=/项目/2024/报告.docx&accessToken=__TOKEN__ HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="folderId"

__FOLDERID__
------WebKitFormBoundary
Content-Disposition: form-data; name="diskId"

__DISKID__
------WebKitFormBoundary
Content-Disposition: form-data; name="filesPath"

/项目/2024/报告.docx
------WebKitFormBoundary
Content-Disposition: form-data; name="files"; filename="报告.docx"
Content-Type: application/octet-stream

(二进制内容)
------WebKitFormBoundary--

响应

结构:统一 ResourcedataMap,结构如下:

字段 类型 说明
msg string 固定为 "上传成功"
id string 最深层目录创建后的目标文件夹Id(copyFolderId,便于前端继续操作)
autoCategoryList array 各文件元信息列表,每项结构同 #1 响应 data 元素(fileName/filePath/id/fileSize/fileType

成功示例

{
  "errcode": 0,
  "errmsg": "ok",
  "data": {
    "msg": "上传成功",
    "id": "__FOLDERID2__",
    "autoCategoryList": [
      { "fileName": "报告.docx", "filePath": "/kms/uploads/a3/abcdef...", "id": "__FILEID__", "fileSize": 10240, "fileType": ".docx" }
    ]
  },
  "errors": null
}

失败示例(文件类型不合法)

{ "errcode": 4001, "errmsg": "上传的文件类型不合法!", "data": null, "errors": null }