文件下载运行时(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、#3的filepath参数均**经 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) 直接构造,errcode 取 200/500,与「统一响应结构」(errcode=0 表成功)**约定不一致,据源码如实记录。
成功示例(文件存在,errcode=200):
失败示例:
其他失败消息:"编码类型错误!"(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-download,Content-Disposition: attachment; filename="<filename>"(按USER-AGENT区分 Firefox / Trident / MSIE / EDGE 与其他,使用URLEncoder.encode或new String(bytes, "iso-8859-1")编码),响应体为文件字节流(SecurityFile.resolveFileInputStream+IOUtils.copy)。图片类型(jpg/jpeg/png/gif/bmp/webp/tiff/svg)不强制下载,直接内联输出。 - 文件不存在:HTTP 200,响应体纯文本
"找不到指定文件"(通过response.getWriter().print(...)写出)。 - 异常:源码吞
IOException/Exception仅e.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「统一响应结构」)。
data:null(成功时仅返回 errcode=0)。
成功示例:
失败示例(文件类型不合法):
失败示例(等待转换超时):