跳转至

文件下载(FileDownloadController)

提供 KMS 知识管理模块「文件下载域」的核心能力:按文件 Id / checksum 下载(支持服务端叠加水印)、批量打包下载(ZIP)、按文件 Id 取预览对象,以及外部分享链接的校验与下载。下载类端点直接写 HTTP 响应流(二进制 application/force-downloadapplication/octet-stream),不返回统一 Resource JSON 封装;其余端点按统一 Resource 或直接对象序列化。

  • 接口类型:REST 资源(@RestController,继承 AbstractBaseController
  • 基址${myapps.context-path.kms:}/api(类级 @RequestMapping 仅声明 /api 前缀,比常见 /api/kms 少一层;方法级路径自带 /kms/.../files/... 段)
  • Tag:kms文件下载模块

公共说明

  • 鉴权(据源码 KmsMvcConfig + KmsSecurityFilterKmsMvcConfig 注册全局 Servlet 过滤器 KmsSecurityFilter(URL 模式 /*,context-path 为 / 时为 /kms/*)。本控制器路径 /api/kms/download/**/api/kms/downloads/api/kms/disks/files/{fileId}/preview/api/files/outsideshare/{shareObjId}/verify/api/files/outsideshare/{shareObjId}/download 均不在 KmsSecurityFilter.isExcludeURI 的豁免名单内(豁免仅覆盖 /login.*/admin/domain.*/tray/service/authtimeservice/OfficeServer.*outsideshare/.*/preview、静态资源后缀、actuator/health 等;本控制器 outsideshare 端点路径以 /verify/download 结尾,不匹配 /preview 正则)。过滤器调用 Security.getUserIdFromToken(request),取不到用户则返回 HTTP 401(无响应体)。因此所有端点均需 accessToken,可通过以下任一方式传递(据 Security.getUserIdFromToken):query 参数 accessToken、query 参数 access_token(移动端)、请求头 accessToken、Cookie accessToken、请求头 Authorization: Bearer <token>。完整鉴权机制见 index.md「鉴权说明」。
  • 外部分享端点的过滤器旁路(据源码)KmsSecurityFilter.isExcludeURI 内额外判断——当请求同时携带 query 参数 id(分享对象 Id)与 code(提取码),且 fileService.getShareObjById(id).code == codeduration 未过期时,将请求标记为预览豁免(preview=true)直接放行。本控制器 #5 outSideVerify / #6 outSideDownload 的形参 shareObjId 为**路径变量**、code 为 query 参数,本身不读 query 参数 id;若调用方在请求路径之外**额外**附带 ?id=<shareObjId>&code=<有效提取码> 且分享未过期,过滤器将放行该请求,跳过 accessToken 校验。无此 query 组合时仍按上述规则要求 accessToken。
  • 执行用户:控制器内 getUser()(继承自 AbstractBaseController)调用 Security.getUserIdFromToken(request) 还原当前用户 id,再经 Feign(UserAPI.getUserById)装载 KmsUseruserCode 参数
  • 响应结构:本控制器**多数下载端点直接写 HTTP 响应流**(Content-Type: application/force-downloadContent-Disposition: attachment;filename=<编码后文件名>、HTTP 200),不走统一 Resource 封装;错误时(如权限不足)由全局异常处理器返回统一 Resource(见 ../index.md「统一响应结构」),字段为 errcode/errmsg/data/errors。其中 #4 getFilePreviewByFileId 直接以 @ResponseBody 返回 FileObjectResource 封装),#5 outSideVerify 返回统一 Resource
  • HTTP 状态码与错误码(据源码 AbstractBaseController 全局异常处理):成功默认 HTTP 200;InvalidRequestException → HTTP 400 / errcode=400;UnauthorizedException → HTTP 403 / errcode=403;ForbiddenException(权限不足,如缺少 CODE_DOWNLOAD)→ HTTP 403 / errcode=403;ResourceNotFoundException → HTTP 404 / errcode=404;其他 Exception → HTTP 500 / errcode=500。
  • 下载权限校验(据源码 isPrivilege:基于 grantService.isPrivilegedByResourceIdAndUserIdAndOperation(resourceId, GrantOperation.CODE_DOWNLOAD, getUser()) 校验当前用户对每个 folderId/fileId 是否拥有 CODE_DOWNLOAD 操作权限。
  • 文件名编码(据源码 getFileNameCoding:Edge 浏览器(User-AgentEDGE)走 URLEncoder.encode(name, UTF-8),其他浏览器走 new String(name.getBytes(UTF-8), ISO-8859-1),再写入 Content-Disposition 头。
  • 路径变量fileIdchecksumshareObjId 均为 KMS 内部主键(明文 id),非 DES 加密密文

1. 下载文件

根据文件 Id 下载文件。若请求带 referer 头且 preview=false,会先校验当前用户对该文件是否拥有 CODE_DOWNLOAD 权限,无权时抛 ForbiddenException(HTTP 403);据源码注释,HiApp 编辑场景调用下载以**跳过权限验证**。支持服务端叠加水印:传入 watermarkString 时,图片类型生成水印图后下载,非图片类型生成带水印的 PDF 后下载(文件名后缀替换为 .pdf)。

  • 接口类型:REST 资源(直接写 HTTP 响应流)
  • 请求方式@RequestMapping(未限定 method,匹配所有 HTTP 方法;按惯例以 GET/POST 调用)
  • 请求路径/kms/download/{fileId}(完整:{kms-context}/api/kms/download/{fileId}
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
fileId path string 文件Id
watermarkString query string 水印内容(无注解,Spring 默认按形参名绑定为 query 参数;非空时触发水印处理)
preview query boolean 是否预览模式(required=false;为 true 时跳过 referer 触发的权限校验)

请求示例

GET /api/kms/download/__FILEID__?accessToken=__TOKEN__ HTTP/1.1

响应

结构:二进制文件流(非统一 Resource)。 - Content-Type: application/force-download - Content-Disposition: attachment;filename=<编码后文件名>(带水印且非图片时为 <原名>.pdf) - HTTP 200:文件字节流直写 response.getOutputStream()

文件不存在或内部异常时,据源码 catche.printStackTrace() 静默吞掉(不写响应体);权限不足时由全局异常处理器返回:

{ "errcode": 403, "errmsg": "权限不足,下载文件失败", "data": null, "errors": null }

2. 根据 checksum 下载文件

根据文件校验码(checksum)查找匹配文件并下载。服务端会遍历所有匹配的 FileEntity逐一校验 CODE_DOWNLOAD 权限(无权则 continue),首个有权限的文件即下载;若全部无权或无匹配,抛 ForbiddenException(HTTP 403)。水印内容优先取调用方传入的 watermarkString,否则取服务端按当前用户、网盘、部门等动态生成的水印(watermarkService.getWatermarkContent,场景 download)。图片类型生成水印图,非图片类型生成水印 PDF。

  • 接口类型:REST 资源(直接写 HTTP 响应流)
  • 请求方式@RequestMapping(未限定 method,匹配所有 HTTP 方法;按惯例以 GET/POST 调用)
  • 请求路径/kms/download-by-checksum/{checksum}(完整:{kms-context}/api/kms/download-by-checksum/{checksum}
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
checksum path string 文件校验码
watermarkString query string 水印内容(Swagger 标注 required=false;非空时覆盖服务端动态生成的水印)

请求示例

GET /api/kms/download-by-checksum/__CHECKSUM__?watermarkString=机密&accessToken=__TOKEN__ HTTP/1.1

响应

结构:二进制文件流(非统一 Resource)。 - Content-Type: application/force-download - Content-Disposition: attachment;fileName=<编码后文件名> - HTTP 200:首个有权限文件的字节流

失败示例(无匹配/无权限)

{ "errcode": 403, "errmsg": "权限不足,或没有找到合适的文件。下载文件失败!", "data": null, "errors": null }


3. 批量下载文件

根据文件夹 Id 数组与文件 Id 数组批量下载,打包为 ZIP。先统一校验所有 folderIdsfileIdsCODE_DOWNLOAD 权限,无权即抛 ForbiddenException(HTTP 403)。特殊情形:当仅传 1 个 fileId 且无 folderIds 时,内部转调 download(单文件下载,跳过权限二次校验)。

  • 接口类型:REST 资源(直接写 HTTP 响应流)
  • 请求方式@RequestMapping(未限定 method,匹配所有 HTTP 方法;按惯例以 GET/POST 调用)
  • 请求路径/kms/downloads(完整:{kms-context}/api/kms/downloads
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
folderIds query array(string) 文件夹Id数组(无文件夹时传空数组)
fileIds query array(string) 文件Id数组(无文件时传空数组)

请求示例

GET /api/kms/downloads?folderIds=__FOLDERID1__&folderIds=__FOLDERID2__&fileIds=__FILEID1__&accessToken=__TOKEN__ HTTP/1.1

响应

结构:二进制 ZIP 流(非统一 Resource)。 - 多文件/含文件夹时:Content-Type: application/force-downloadContent-Disposition: attachment;fileName=<时间戳yyyyMMddHHmmss>.zip,HTTP 200 - 单文件(folderIds 空 + fileIds 长度 1)时:走 #1 download 的响应规则

失败示例(权限不足)

{ "errcode": 403, "errmsg": "权限不足,下载文件失败", "data": null, "errors": null }


4. 获取文件预览对象

根据文件 Id 取 FileObject(文件对象,含文件物理信息)。直接以 @ResponseBody 返回 FileObject,不走统一 Resource 封装

  • 接口类型:REST 资源
  • 请求方式GET
  • 请求路径/kms/disks/files/{fileId}/preview(完整:{kms-context}/api/kms/disks/files/{fileId}/preview
  • 鉴权:是(需 accessToken,据源码)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
fileId path string 文件Id(实际为 FileObject Id,由 fileService.findByFileObjectId 加载)

请求示例

GET /api/kms/disks/files/__FILEID__/preview?accessToken=__TOKEN__ HTTP/1.1

响应

结构:直接序列化的 FileObjectproduces=application/json非统一 Resource),含文件名、类型、大小、路径、是否文件夹等字段。文件未找到时返回 null

file.md #21 FileController/disks/{diskId}/files/{fileId}/preview(路径含 diskId、返回 Resource 包装的 JSON 字符串)不同:本端点路径**不含 diskId,且返回**裸 FileObject


5. 校验外部链接可用性

校验外部分享链接的提取码与有效期。若 code 与服务端存储的提取码不一致返回 errcode=400duration 已过期返回 errcode=400,校验通过返回 errcode=0注意:本端点为外部链接访问场景设计,但据 KmsSecurityFilter 规则,路径以 /verify 结尾不在豁免名单;调用方需附带 accessToken,或额外以 query 参数 id=<shareObjId>&code=<有效提取码> 触发过滤器的分享预览豁免(详见上文「公共说明」)。

  • 接口类型:REST 资源
  • 请求方式GET
  • 请求路径/files/outsideshare/{shareObjId}/verify(完整:{kms-context}/api/files/outsideshare/{shareObjId}/verify
  • 鉴权:是(需 accessToken,据源码;或调用方额外附 ?id=<shareObjId>&code=<有效提取码> 触发过滤器分享豁免)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
shareObjId path string 分享对象Id
code query string 提取码(无注解,Spring 默认按形参名绑定为 query 参数;建议传入)

请求示例

GET /api/files/outsideshare/__SHAREOBJID__/verify?code=abcd&accessToken=__TOKEN__ HTTP/1.1

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 datanull(仅以 errcode/errmsg 表达校验结果)。

成功示例

{ "errcode": 0, "errmsg": "分享链接可用", "data": null, "errors": null }

失败示例(提取码错误/已失效)

{ "errcode": 400, "errmsg": "提取码错误", "data": null, "errors": null }


6. 外部链接文件下载

按外部链接下载分享对象对应的文件或文件夹。先校验 code 与有效期(不匹配/已失效时直接 response.getWriter().write(...) 写错误文本,不抛异常),通过后按对象类型分流:文件夹打包为 ZIP 下载,单文件直接下载(不叠加水印)。注意:与 #5 同理,路径以 /download 结尾不在 KmsSecurityFilter 豁免名单;调用方需 accessToken,或额外以 query 参数 id=<shareObjId>&code=<有效提取码> 触发豁免。

  • 接口类型:REST 资源(直接写 HTTP 响应流)
  • 请求方式GET
  • 请求路径/files/outsideshare/{shareObjId}/download(完整:{kms-context}/api/files/outsideshare/{shareObjId}/download
  • 鉴权:是(需 accessToken,据源码;或调用方额外附 ?id=<shareObjId>&code=<有效提取码> 触发过滤器分享豁免)
  • Tag:kms文件下载模块

请求参数

参数名 位置 类型 必填 说明
shareObjId path string 分享对象Id
code query string 提取码(建议传入;不匹配时响应体写错误文本)

请求示例

GET /api/files/outsideshare/__SHAREOBJID__/download?code=abcd&accessToken=__TOKEN__ HTTP/1.1

响应

结构:二进制文件流(非统一 Resource)。 - 文件夹:Content-Type: application/force-downloadContent-Disposition: attachment;fileName=<时间戳yyyyMMddHHmmss>.zip,HTTP 200 - 单文件:Content-Type: application/force-downloadContent-Disposition: attachment;fileName=<编码后文件名>,HTTP 200

失败(提取码错误/已失效/内部异常):以纯文本写入响应体(Content-Type 默认),如 提取码错误!分享链接已失效!提取错误:<异常消息>