跳转至

文件下载运行时(DownloadController)

文件运行时接口:校验文件是否存在、文件下载(支持加密解密、PDF 预览转换、水印)、文件上传到指定路径(支持文件转换等待)。

  • 接口类型:REST 资源(@Component 继承 AbstractRuntimeController;类级 produces = MediaType.APPLICATION_JSON_VALUE;但 #2 doFileDownload 直接写回 HttpServletResponse 输出流为文件下载,实际响应非 JSON,据源码)
  • 基址${myapps.context-path.runtime:}/api/runtime
  • Tag:runtime

公共说明

  • 鉴权(据源码):类级基址位于 /api/runtime/**,在 RestSecurityHandlerInterceptor 覆盖范围内,且不在豁免名单(豁免仅覆盖 /api/runtime/login.*/api/runtime/dingding/authlogin/api/runtime/synchronization.*、URI 以 /showjrxml 结尾、含 /getCustomColumnsInfos、含 /accessToken、含 /macro、以 /clear 结尾、含 /pages/ 等,详见 login.md「公共说明 · 鉴权」)。拦截器走 Security.getUserIdFromToken(request),未取到再尝试 Security.getDebugUserIdFromToken(request),两者皆无则拒绝。故需 accessToken(或 debugToken),可通过 Cookie / 请求头 / query 参数任一方式传递。控制器内 getUser()(继承自 AbstractRuntimeController)必须能取到非空 WebUser,否则在 DesUtil.decryptTextByUserId(filepath, getUser().getId()) 时即抛 NPE。
  • filepath 加密#1#2#3filepath 参数均**经 DES 加密**(按当前执行用户密钥),服务端 DesUtil.decryptTextByUserId(filepath, getUser().getId()) 解密。#1 还对 filepath 先做 URLDecoder.decode(filepath, "ISO-8859-1")
  • 响应结构#1#3 返回统一 Resource(见 ../index.md「统一响应结构」);#2 直接写回 HttpServletResponse 输出流为文件下载(非 JSON)。

1. 校验文件是否存在

filepath(DES 加密)校验目标文件是否存在且路径合法(必须落在 ${storage.root.path} 规范路径下)。filepath/resources 开头且提供 applicationId 时,按软件模板资源路径解析。

  • 接口类型:REST 资源
  • 请求方式GET
  • 请求路径/file/isFileExisted(完整:{runtime-context}/api/runtime/file/isFileExisted
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
filepath query string 文件相对路径(先 URLDecoder.decode(..., "ISO-8859-1"),再 DES 解密)
applicationId query string 软件id(DES 加密密文);filepath/resources 开头时必填——用于解析为软件模板资源路径

请求示例

GET /api/runtime/file/isFileExisted?filepath=__ENC_FILEPATH__&applicationId=__ENC_APPID__ HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构非**统一 Resource —— 源码用 new Resource(code, msg, null) 直接构造,errcode200/500,与「统一响应结构」(errcode=0 表成功)**约定不一致,据源码如实记录。

成功示例(文件存在,errcode=200):

{ "errcode": 200, "errmsg": "文件存在!", "data": null, "errors": null }

失败示例

{ "errcode": 500, "errmsg": "文件不存在!", "data": null, "errors": null }

其他失败消息:"编码类型错误!"URLDecoder 不支持的编码,理论不会触发)、"文件路径或类型不合法!"(路径越界)。


2. 文件下载

filepath(DES 加密)下载文件,支持加密文件解密、.preview_pdf 后缀走 PDF 预览转换路径、watermarkStr 加水印(生成带水印的 PDF 并改名下载)。文件不存在时通过 response.getWriter().print("找不到指定文件") 返回纯文本。

  • 接口类型:REST 资源(二进制文件下载)
  • 请求方式@RequestMapping(未限定 method,支持 GET / POST 等所有方法
  • 请求路径/file/download(完整:{runtime-context}/api/runtime/file/download
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
filepath query string 文件相对路径(DES 加密密文)
filename query string 下载显示的文件名;省略时使用服务器端文件名
watermarkStr query string 水印文本;非空时生成水印 PDF 并按 PDF 下载
applicationId query string 软件id(DES 加密密文);filepath/resources 开头时必填——用于解析为软件模板资源路径

请求示例

GET /api/runtime/file/download?filepath=__ENC_FILEPATH__&filename=report.pdf HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:二进制文件流(application/force-download 或图片内联);不返回 JSON Resource

  • 成功(非图片):HTTP 200,Content-Type: application/force-downloadContent-Disposition: attachment; filename="<filename>"(按 USER-AGENT 区分 Firefox / Trident / MSIE / EDGE 与其他,使用 URLEncoder.encodenew String(bytes, "iso-8859-1") 编码),响应体为文件字节流(SecurityFile.resolveFileInputStream + IOUtils.copy)。图片类型(jpg/jpeg/png/gif/bmp/webp/tiff/svg)不强制下载,直接内联输出。
  • 文件不存在:HTTP 200,响应体纯文本 "找不到指定文件"(通过 response.getWriter().print(...) 写出)。
  • 异常:源码吞 IOException / Exceptione.printStackTrace(),无错误响应体。

3. 上传文件到指定文件夹

filepath(DES 加密)上传一个或多个文件到 ${storage.root.path}/<filepath>,校验扩展名合法性,落地后写文件转换任务;可选等待转换完成(超过 180 秒返回超时错误)。

  • 接口类型:REST 资源
  • 请求方式POST
  • 请求路径/file/commitRuntimeFile(完整:{runtime-context}/api/runtime/file/commitRuntimeFile
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
filepath query string 目标相对路径(DES 加密密文),与 ${storage.root.path} 拼接
waitConvert query string 是否等待文件转换完成,默认 false;为 "true" 时轮询直到完成或超时
files body(form-data) file[] multipart 文件数组(字段名 files

请求示例

POST /api/runtime/file/commitRuntimeFile?filepath=__ENC_FILEPATH__&waitConvert=false HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

------Boundary
Content-Disposition: form-data; name="files"; filename="sample.pdf"
Content-Type: application/pdf

<binary>
------Boundary--

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 datanull(成功时仅返回 errcode=0)。

成功示例

{ "errcode": 0, "errmsg": "ok", "data": null, "errors": null }

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

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

失败示例(等待转换超时):

{ "errcode": 4005, "errmsg": "文件转换超时!", "data": null, "errors": null }