跳转至

报表执行(ReportController)

报表执行接口:报表显示(HTML 重定向脚本)/ 报表基本信息 / 报表显示(jrxml,含查询表单参数注入)/ 导出字段列表 / 导出 Excel / 导出 PDF / 查询表单模板 / 报表册下报表列表 / 自定义数据源列信息。

  • 接口类型:REST 资源(@Controller 继承 AbstractRuntimeController;类级**无** produces 声明,方法返回类型为 String / Resource / void(写回 HttpServletResponse),由 @ResponseBody 或返回类型为 Resource 的方法经 Spring Jackson 序列化为 JSON,接口类型按返回类型判定为 REST 资源,据源码)
  • 基址:${myapps.context-path.runtime:}/api/runtime
  • Tag:runtime

公共说明

  • 鉴权(据源码):类级基址位于 /api/runtime/**,在 RestSecurityHandlerInterceptor 覆盖范围内。豁免判定按 URI 字面匹配,本控制器有两个端点命中豁免规则——
  • #3 showJrxmlReport(/api/runtime/{applicationId}/reports/{reportId}/showjrxml):据源码豁免——拦截器 uri.endsWith("/showjrxml") 命中,无需 accessToken(用于运行时直接渲染报表 HTML)。
  • #9 getCustomColumnsInfos(/api/runtime/getCustomColumnsInfos):据源码豁免——拦截器 uri.indexOf("/getCustomColumnsInfos") >= 0 命中,无需 accessToken。
  • 其余端点(#1/#2/#4/#5/#6/#7/#8):需 accessToken(或 debugToken),可通过 Cookie / 请求头 / query 参数任一方式传递。控制器内 getUser()(继承自 AbstractRuntimeController)必须能取到非空 WebUser,否则在 DesUtil.decryptTextByUserId(applicationId, getUser().getId()) 时即抛 NPE。
  • 注:#3 与 #9 虽然拦截器豁免,但控制器源码仍调用 getUser() / DesUtil.decryptTextByUserId(..., getUser().getId())。#3 容忍 user == null(fallback 用 body 中 userid 构造临时 WebUser);#9 不容忍 null,实际调用仍需登录态(与 detail.md 中豁免端点同理)。
  • 路径变量 {applicationId} / {reportId}:必填,经 DES 加密(按当前执行用户密钥),服务端在方法入口处 DesUtil.decryptTextByUserId(applicationId, getUser().getId()) 与 DesUtil.decryptTextByUserId(reportId, getUser().getId()) 解密。
  • 响应结构:本控制器响应**非**统一 Resource 直接返回——
  • #1/#3:返回 String(@ResponseBody),分别为 JS 重定向脚本 / HTML 路径字符串或错误消息;
  • #2/#4/#7/#8:返回 Resource(与统一 Resource 结构一致);
  • #5/#6:void,直接写回 HttpServletResponse 输出流为 Excel/PDF 文件下载(produces = "text/html;charset=UTF-8"),非 JSON;
  • #9:返回 List<QueryColumnInfo>(@ResponseBody),直接是数组而非 Resource。
  • 完整规则见各端点小节。
  • HTTP 状态码:#3/#4/#5/#6/#7/#8 标注 @ResponseStatus(HttpStatus.OK)。

1. 报表显示(重定向脚本)

按 reportId 加载报表定义,将报表导出为 HTML 文件得到路径,返回 <script>window.location='<contextPath>';</script> 字符串供前端跳转。reportId 为空时返回字符串 "请指定报表!"。

  • 接口类型:REST 资源(返回 String,@ResponseBody)
  • 请求方式:@RequestMapping(未限定 method,支持 GET / POST 等所有方法)
  • 请求路径:/{applicationId}/reports/{reportId}/show(完整:{runtime-context}/api/runtime/{applicationId}/reports/{reportId}/show)
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)

请求示例

GET /api/runtime/__APPID__/reports/__REPORTID__/show HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:String(非 Resource);Content-Type 由 Spring 内容协商决定(典型为 text/plain 或 text/html)。

成功示例(字符串字面量):

<script>window.location='/reports/__REPORTID__/html/xxx.html';</script>

未指定报表示例:

请指定报表!


2. 获取报表基本信息

按 reportId 加载并返回报表定义(ReportService.doView),reportId 为空时返回 error(500, "请指定报表!", null)。

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

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)

请求示例

GET /api/runtime/__APPID__/reports/__REPORTID__/info HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 data:Report,报表定义实体(含 name/dataSourceType/viewId/subReportId/calaculateType 等字段)。

成功示例:

{
  "errcode": 0,
  "errmsg": "ok",
  "data": {
    "id": "__REPORTID__",
    "name": "销售月报",
    "dataSourceType": "VIEW",
    "viewId": "__VIEWID__"
  },
  "errors": null
}

失败示例:

{ "errcode": 500, "errmsg": "请指定报表!", "data": null, "errors": null }


3. 报表显示(jrxml,POST 提交查询参数)

POST 提交查询参数 JSON body(被注入 ParamsTable),按 reportId 加载报表定义,递归处理子报表,最终生成主报表 HTML 文件路径并返回字符串。注意:

  • 本端点据拦截器 uri.endsWith("/showjrxml") 豁免,无需 accessToken;但源码也容忍 getUser() 为 null:为空时取 body 中 userid 构造临时 WebUser,并按 body 中 domainId(若存在)设置企业域。
  • 错误返回字符串前缀:"msg:请指定报表!" / "msg:已知系统异常!<异常消息>" / "msg:未知系统异常!ExceptionName:<类名>,ExceptionMsg:<消息>"。

  • 接口类型:REST 资源(返回 String,@ResponseBody,produces = "text/html;charset=UTF-8")

  • 请求方式:POST
  • 请求路径:/{applicationId}/reports/{reportId}/showjrxml(完整:{runtime-context}/api/runtime/{applicationId}/reports/{reportId}/showjrxml)
  • 鉴权:否(据源码:拦截器 uri.endsWith("/showjrxml") 豁免;但控制器内 getUser() 为 null 时 fallback body.userid)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文);user==null 时**不解密**(按原值使用)
reportId path string 是 报表id(DES 加密密文);user==null 时**不解密**
content body string(JSON) 否 查询参数 JSON;解析出的键值对全部注入 ParamsTable
docid query string 否 文档Id(DES 加密密文),用于作为打印模板时的表单数据源;user==null 时**不解密**,默认空字符串
请求体(可选)

JSON 对象,常见字段:userid(无登录态时用作 fallback WebUser id)、domainId(无登录态时设置企业域)、以及各查询表单字段。

{
  "userid": "__USERID__",
  "domainId": "__DOMAINID__",
  "startDate": "2026-01-01"
}

请求示例

POST /api/runtime/__APPID__/reports/__REPORTID__/showjrxml HTTP/1.1
Content-Type: application/json

{
  "startDate": "2026-01-01"
}

响应

结构:String(非 Resource),Content-Type: text/html;charset=UTF-8。

成功示例(主报表 HTML 文件路径):

/reports/__REPORTID__/html/xxx.html

失败示例(字符串字面量):

msg:请指定报表!

msg:已知系统异常!<异常消息>
msg:未知系统异常!ExceptionName:<类名>,ExceptionMsg:<消息>

4. 获取报表导出字段

解析报表对应 .jrxml 文件的列头与列明细字段(按 X 坐标对齐),返回导出字段名列表。表头与明细列数不一致或抛 ClassCastException 时返回 success("ok", null)。

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

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)

请求示例

GET /api/runtime/__APPID__/reports/__REPORTID__/columns HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 data:List<String>,列头文本集合(按 X 坐标排序);表头与明细列数不一致时为 null。

成功示例:

{
  "errcode": 0,
  "errmsg": "ok",
  "data": ["月份", "销售额", "成本"],
  "errors": null
}

失败示例:

{ "errcode": 500, "errmsg": "请指定报表!", "data": null, "errors": null }

其他失败消息:"已知系统异常!<异常消息>"(CommonException)、"未知系统异常!ExceptionName:<类名>,ExceptionMsg:<消息>"。


5. 报表导出 Excel

POST 提交查询参数与 columns 字段列表,按 reportId 加载报表定义,递归处理子报表,生成主报表 Excel 文件并以附件形式下载。produces = "text/html;charset=UTF-8"(实际响应体为 Excel 二进制流)。

  • 接口类型:REST 资源(文件下载,二进制响应;返回 void)
  • 请求方式:POST
  • 请求路径:/{applicationId}/reports/{reportId}/exportexcel(完整:{runtime-context}/api/runtime/{applicationId}/reports/{reportId}/exportexcel)
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)
content body string(JSON) 否 查询参数 JSON;含可选 columns: List<String>(导出列名过滤)
请求体(可选)
{
  "columns": ["月份", "销售额"],
  "domainId": "__DOMAINID__"
}

请求示例

POST /api/runtime/__APPID__/reports/__REPORTID__/exportexcel HTTP/1.1
Content-Type: application/json
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

{
  "columns": ["月份", "销售额"]
}

响应

结构:二进制 Excel 文件(.xls)附件下载;不返回 JSON Resource。

  • 成功:HTTP 200,Content-Type: application/x-download; charset=<encoding>,Content-Disposition: attachment; filename="<reportName>.xls"(按 USER-AGENT 区分 Firefox 与其他),响应体为 ActivityRunTimeServiceImpl.doFileDownload(file, outputStream) 写出的 .xls 字节流。
  • 失败:源码吞 CommonException / Exception 仅 e.printStackTrace(),无错误响应体。

6. 报表导出 PDF

POST 提交查询参数,按 reportId 加载报表定义,递归处理子报表,生成主报表 PDF 文件并以附件形式下载。produces = "text/html;charset=UTF-8"(实际响应体为 PDF 二进制流)。

  • 接口类型:REST 资源(文件下载,二进制响应;返回 void)
  • 请求方式:POST
  • 请求路径:/{applicationId}/reports/{reportId}/exportpdf(完整:{runtime-context}/api/runtime/{applicationId}/reports/{reportId}/exportpdf)
  • 鉴权:是(需 accessToken,据源码)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)
content body string(JSON) 否 查询参数 JSON,键值对注入 ParamsTable
docid query/body string 否 文档Id(无 @RequestParam 注解,Spring 默认按 query 解析;用于作为打印模板时的表单数据源)

请求示例

POST /api/runtime/__APPID__/reports/__REPORTID__/exportpdf?docid=__ENC_DOCID__ HTTP/1.1
Content-Type: application/json
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

{
  "domainId": "__DOMAINID__"
}

响应

结构:二进制 PDF 文件(.pdf)附件下载;不返回 JSON Resource。

  • 成功:HTTP 200,Content-Type: application/x-download; charset=<encoding>,Content-Disposition: attachment; filename="<reportName>.pdf"(按 USER-AGENT 区分 Firefox 与其他),响应体为 ActivityRunTimeServiceImpl.doFileDownload(file, outputStream) 写出的 .pdf 字节流。
  • 失败:源码吞 CommonException / Exception 仅 e.printStackTrace(),无错误响应体。

7. 获取查询表单模板

按 reportId 加载报表定义;按数据源类型(视图数据源 → 视图查询表单;其他 → 报表 dataSourceSearchForm)定位查询表单,生成表单 HTML 模板字符串与字段属性列表。

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

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportId path string 是 报表id(DES 加密密文)

请求示例

GET /api/runtime/__APPID__/reports/__REPORTID__/searchformtemplate HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 data:Map,固定字段: - fields (List<Map<String,Object>>):查询表单各字段属性列表; - document (Document):基于查询表单创建的 searchDocument; - template (String):表单 HTML 模板字符串(含隐藏字段 dy_refreshObj,封装 formid/docid/userid/mapVal); - style (Object,可选):表单样式(仅当 form.style 非空时存在)。

成功示例:

{
  "errcode": 0,
  "errmsg": "ok",
  "data": {
    "fields": [{ "name": "startDate", "type": "DATE" }],
    "document": { "id": "__DOCID__", "formid": "__FORMID__" },
    "template": "<input type=\"hidden\" id=\"dy_refreshObj\" formid=\"__FORMID__\" ... />"
  },
  "errors": null
}

失败示例:

{ "errcode": 500, "errmsg": "<异常信息>", "data": null, "errors": null }


8. 获取当前报表册下的报表

按 reportGroupId 加载报表册,按 reportGroup.reportIds(以 ; 分隔)逐项加载报表名,组装为 {reportId: reportName} Map 嵌入返回。

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

请求参数

参数名 位置 类型 必填 说明
applicationId path string 是 软件id(DES 加密密文)
reportGroupId path string 是 报表册id(明文,源码未对该变量做 DES 解密)

请求示例

GET /api/runtime/__APPID__/reportgroups/__REPORTGROUPID__/reports HTTP/1.1
Cookie: accessToken=eyJhbGciOiJIUzI1NiJ9...

响应

结构:统一 Resource(见 ../index.md「统一响应结构」)。 data:JSONObject,固定含 data 字段(Map<String,String>,key 为报表Id、value 为报表名);服务层异常被吞时仅 e.printStackTrace(),返回的 data 字段为空 JSONObject(无 data 内层 key)。

成功示例:

{
  "errcode": 0,
  "errmsg": "ok",
  "data": {
    "data": {
      "__REPORTID1__": "销售月报",
      "__REPORTID2__": "库存日报"
    }
  },
  "errors": null
}

说明:源码用 json.put("data", map) 后再 success("ok", json),故 data 字段内嵌一层 data。


9. 获取报表自定义数据源的列信息

按自定义数据源脚本(scriptString)解析返回列信息列表。本端点据拦截器 uri.indexOf("/getCustomColumnsInfos") >= 0 豁免,无需 accessToken;但控制器内 getUser() 不容忍 null,实际调用仍需登录态。

  • 接口类型:REST 资源(返回 List<QueryColumnInfo>,@ResponseBody;直接数组而非 Resource 包装)
  • 请求方式:POST
  • 请求路径:/getCustomColumnsInfos(完整:{runtime-context}/api/runtime/getCustomColumnsInfos)
  • 鉴权:否(据源码:拦截器 uri.indexOf("/getCustomColumnsInfos") >= 0 豁免;但控制器内仍需 getUser() 非空)
  • Tag:runtime

请求参数

参数名 位置 类型 必填 说明
scriptString body string 是 自定义数据源脚本字符串
applicationId query string 否 软件id(DES 加密密文);无 @RequestParam 注解,Spring 按 query 参数解析

请求示例

POST /api/runtime/getCustomColumnsInfos?applicationId=__ENC_APPID__ HTTP/1.1
Content-Type: application/json

"var rows = []; rows.push({name:'字段1', type:'STRING'}); rows;"

响应

结构:**非**统一 Resource —— @ResponseBody 直接返回 List<QueryColumnInfo>(JSON 数组),无 errcode/errmsg/data/errors 包裹,据源码如实记录。

成功示例:

[
  { "name": "字段1", "type": "STRING", "alias": "字段1" },
  { "name": "字段2", "type": "NUMBER", "alias": "字段2" }
]