status: review created: 2026-05-11 complexity: 🔴高
当前 forge-report-ui 报表动态数据主要依赖内部接口、外部接口或静态数据。业务希望新增一种直接通过数据库查询渲染报表的数据加载方式:用户在 admin 端维护数据连接和数据集,报表组件选择数据集后即可按配置查询数据库并渲染,不需要再为每个图表单独开发数据接口。
该能力不能只服务大屏报表。后续 AI 生成报表、ChatBI、数据问答、自动指标推荐等场景都需要复用数据连接、数据集、字段元数据和统一查询执行能力,因此本次按平台级数据资产能力设计。
目标:
forge-report-ui 新增「数据库数据集」数据加载模式,选择数据连接/数据集后直接查询数据库渲染图表。forge-report-server 私有包或报表私有表中。dynamicRequestParams 结构,不再引入第二套参数表达式。forge-report-ui 已有动态接口数据配置和 dynamicRequestParams 机制,可把登录人上下文、筛选组件值、预设时间范围等注入请求参数。forge-report-ui/src/api/http.ts 是报表组件动态数据请求执行入口。forge-report-ui/src/store/modules/chartEditStore/chartEditStore.d.ts 中 RequestConfigType 已保存动态请求相关配置。forge-report-server 依赖 forge-plugin-system、forge-plugin-ai、forge-plugin-external,可以继续依赖新增平台插件。forge-admin-server 已依赖 generator、external、ai 等业务插件,可以增加数据资产管理插件。forge-plugin-generator 里已有 gen_datasource,但它是代码生成器私有模型,不适合作为平台级数据连接:
tenant_id、create_dept、schema_name 等平台标准字段。gen_datasource 上继续扩展。id, tenant_id, create_by, create_time, create_dept, update_by, update_time。pageNum + pageSize。@ApiEncrypt / @ApiDecrypt。TABLE:单表数据集,基于表名、字段、筛选、排序生成查询 SQL。SQL:SQL 数据集,由用户输入查询 SQL,系统做安全校验和参数绑定。| 术语 | 说明 |
|---|---|
| 数据连接 | 一个可访问数据库的连接配置,例如 MySQL 数据库连接 |
| 数据集 | 可被报表/AI/ChatBI 使用的数据查询定义,可能是单表或 SQL |
| 字段配置 | 数据集输出字段的业务语义和展示配置 |
| 运行时查询 | 报表预览、发布页、AI 分析等场景按数据集执行查询 |
| 动态参数 | 来自登录人上下文、画布筛选组件、预设值或自定义值的查询参数 |
新增平台级插件:
forge/forge-framework/forge-plugin-parent/forge-plugin-data/
├── controller/
│ ├── DataConnectionController.java
│ ├── DataDatasetController.java
│ └── DataDatasetRuntimeController.java
├── service/
│ ├── DataConnectionService.java
│ ├── DataDatasetService.java
│ ├── DataDatasetFieldService.java
│ └── DataQueryExecutor.java
├── service/impl/
├── mapper/
├── entity/
├── dto/
├── vo/
├── enums/
├── support/
│ ├── JdbcDataSourceProvider.java
│ ├── SqlSafetyValidator.java
│ ├── SqlParameterBinder.java
│ ├── TableQueryBuilder.java
│ └── DatasetResultMapper.java
└── resources/mapper/
依赖关系:
forge-plugin-data 是平台业务插件。forge-admin-server 依赖 forge-plugin-data,提供 admin 端管理页面 API。forge-report-server 依赖 forge-plugin-data,提供报表运行时查询 API。forge-plugin-data,复用数据集元数据和查询执行器。前端入口:
forge-admin-ui:新增数据资产管理菜单,用于维护数据连接和数据集。forge-report-ui:新增报表组件数据加载模式「数据库数据集」。平台级数据连接表。
CREATE TABLE `ai_report_data_connection` (
`id` bigint NOT NULL COMMENT '主键ID', -- 自增
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
`connection_code` varchar(64) NOT NULL COMMENT '连接编码',
`connection_name` varchar(100) NOT NULL COMMENT '连接名称',
`db_type` varchar(32) NOT NULL COMMENT '数据库类型:MYSQL/POSTGRESQL/ORACLE/SQLSERVER',
`driver_class_name` varchar(200) NOT NULL COMMENT '驱动类名',
`jdbc_url` varchar(1000) NOT NULL COMMENT 'JDBC连接地址',
`username` varchar(128) NOT NULL COMMENT '用户名',
`password_cipher` varchar(500) DEFAULT NULL COMMENT '密码密文',
`schema_name` varchar(128) DEFAULT NULL COMMENT '模式名/数据库名',
`test_sql` varchar(200) NOT NULL DEFAULT 'SELECT 1' COMMENT '测试SQL',
`pool_config_json` json DEFAULT NULL COMMENT '连接池配置JSON',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
`description` varchar(500) DEFAULT NULL COMMENT '描述',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_data_connection_code_tenant` (`tenant_id`, `connection_code`),
KEY `idx_data_connection_status` (`tenant_id`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台数据连接';
字段规则:
connection_code 同租户唯一,用于 AI、ChatBI 通过稳定编码引用。password_cipher 只存密文,新增/修改时加密;查询详情返回 hasPassword=true,不返回密文。jdbc_url 详情页可返回脱敏值,编辑时密码留空表示不修改。schema_name 用于 MySQL database、PostgreSQL schema、Oracle schema 等元数据查询范围。pool_config_json 首期可为空,后续扩展最大连接数、最小空闲、连接超时等配置。平台级数据集表。
CREATE TABLE `ai_report_data_dataset` (
`id` bigint NOT NULL COMMENT '主键ID', -- 自增
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
`dataset_code` varchar(64) NOT NULL COMMENT '数据集编码',
`dataset_name` varchar(100) NOT NULL COMMENT '数据集名称',
`connection_id` bigint NOT NULL COMMENT '数据连接ID',
`dataset_type` varchar(20) NOT NULL COMMENT '数据集类型:TABLE/SQL',
`table_name` varchar(200) DEFAULT NULL COMMENT '单表模式表名',
`sql_text` longtext DEFAULT NULL COMMENT 'SQL模式查询SQL',
`param_schema_json` json DEFAULT NULL COMMENT '参数定义JSON',
`default_order_json` json DEFAULT NULL COMMENT '默认排序JSON',
`max_rows` int NOT NULL DEFAULT 1000 COMMENT '最大返回行数',
`timeout_seconds` int NOT NULL DEFAULT 15 COMMENT '查询超时时间秒',
`cache_enabled` tinyint NOT NULL DEFAULT 0 COMMENT '是否启用缓存:1是 0否',
`cache_ttl_seconds` int DEFAULT NULL COMMENT '缓存秒数',
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
`description` varchar(500) DEFAULT NULL COMMENT '描述',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_data_dataset_code_tenant` (`tenant_id`, `dataset_code`),
KEY `idx_data_dataset_connection` (`tenant_id`, `connection_id`),
KEY `idx_data_dataset_status` (`tenant_id`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台数据集';
字段规则:
dataset_type=TABLE 时 table_name 必填,sql_text 为空。dataset_type=SQL 时 sql_text 必填,table_name 可为空。param_schema_json 定义 SQL 参数或单表筛选参数,供报表配置、AI、ChatBI 识别。max_rows 默认 1000,运行时请求的 limit 不得超过该值。timeout_seconds 默认 15,避免慢 SQL 拖垮报表页。param_schema_json 示例:
[
{
"paramName": "startTime",
"label": "开始时间",
"dataType": "DATETIME",
"required": false,
"defaultValue": null,
"operator": ">=",
"fieldName": "create_time"
},
{
"paramName": "regionCode",
"label": "区域编码",
"dataType": "STRING",
"required": false,
"defaultValue": null,
"operator": "=",
"fieldName": "region_code"
}
]
数据集字段配置表。
CREATE TABLE `ai_report_data_dataset_field` (
`id` bigint NOT NULL COMMENT '主键ID',
`tenant_id` bigint NOT NULL DEFAULT 1 COMMENT '租户ID',
`dataset_id` bigint NOT NULL COMMENT '数据集ID',
`field_name` varchar(128) NOT NULL COMMENT '字段名/SQL别名',
`field_label` varchar(128) DEFAULT NULL COMMENT '字段显示名',
`source_column` varchar(128) DEFAULT NULL COMMENT '来源列名',
`db_type` varchar(100) DEFAULT NULL COMMENT '数据库字段类型',
`data_type` varchar(32) NOT NULL DEFAULT 'STRING' COMMENT '标准类型:STRING/NUMBER/DATE/DATETIME/BOOLEAN',
`field_role` varchar(20) NOT NULL DEFAULT 'DIMENSION' COMMENT '字段角色:DIMENSION/MEASURE',
`default_agg` varchar(20) DEFAULT NULL COMMENT '默认聚合:SUM/COUNT/AVG/MAX/MIN',
`query_enabled` tinyint NOT NULL DEFAULT 1 COMMENT '是否可筛选',
`display_enabled` tinyint NOT NULL DEFAULT 1 COMMENT '是否可展示',
`sensitive_level` varchar(20) NOT NULL DEFAULT 'NONE' COMMENT '敏感级别:NONE/MASK/HIDDEN',
`mask_rule` varchar(100) DEFAULT NULL COMMENT '脱敏规则',
`dict_type` varchar(100) DEFAULT NULL COMMENT '字典类型',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
`description` varchar(500) DEFAULT NULL COMMENT '描述',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_dept` bigint DEFAULT NULL COMMENT '创建部门',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_data_dataset_field` (`tenant_id`, `dataset_id`, `field_name`),
KEY `idx_data_dataset_field_dataset` (`tenant_id`, `dataset_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台数据集字段';
字段规则:
field_name 对 SQL 数据集必须取查询结果列别名。field_role=DIMENSION 适合分组、分类轴、筛选项。field_role=MEASURE 适合数值展示和聚合。sensitive_level=HIDDEN 的字段不返回运行时查询结果。sensitive_level=MASK 的字段返回前按 mask_rule 脱敏。TABLE 数据集由系统生成查询:
SELECT <selected_fields>
FROM <safe_table_name>
WHERE 1 = 1
AND <field_filter_1>
AND <field_filter_2>
ORDER BY <safe_order_fields>
LIMIT ?
规则:
table_name,禁止前端直接传任意表名执行。data_dataset_field,禁止前端直接传任意字段名执行。param_schema_json 和动态参数解析结果。display_enabled=1 的字段。SQL 数据集由管理员输入查询 SQL,例如:
SELECT
city_code AS cityCode,
city_name AS cityName,
SUM(order_amount) AS orderAmount
FROM ads_city_order
WHERE stat_date >= :startTime
AND stat_date <= :endTime
AND (:cityCode IS NULL OR city_code = :cityCode)
GROUP BY city_code, city_name
ORDER BY orderAmount DESC
规则:
SELECT 或 WITH ... SELECT 查询。INSERT、UPDATE、DELETE、DROP、ALTER、CREATE、TRUNCATE、MERGE、CALL、EXEC。:paramName,执行前转换为 ? 并绑定参数。SELECT * FROM (
<validated_sql>
) t
LIMIT ?
不同数据库 limit 方言后续通过 DbDialect 扩展,首期 MySQL 优先。
| 标准类型 | 输入来源 | 后端绑定类型 |
|---|---|---|
| STRING | 文本、下拉、区域 | String |
| NUMBER | 数字输入、分页 | BigDecimal / Long |
| DATE | 日期选择 | LocalDate |
| DATETIME | 日期时间、T-N预设 | LocalDateTime |
| BOOLEAN | 开关 | Boolean |
动态参数为空时:
required=true:返回参数校验错误,不执行查询。required=false:TABLE 查询跳过该条件;SQL 查询绑定 null。所有管理接口走 forge-admin-server,运行时接口可同时由 forge-admin-server 和 forge-report-server 暴露。开启前端加密链路的接口必须按请求/响应补齐 @ApiDecrypt / @ApiEncrypt。
| 操作 | 接口 | 方法 | 说明 |
|---|---|---|---|
| 分页 | /data/connection/page |
GET | 按名称、类型、状态分页 |
| 列表 | /data/connection/list |
GET | 返回启用连接,用于下拉 |
| 详情 | /data/connection/:id |
GET | 返回脱敏详情 |
| 新增 | /data/connection |
POST | 新增连接,密码加密 |
| 修改 | /data/connection |
PUT | 修改连接,密码为空则不变 |
| 删除 | /data/connection/:id |
DELETE | 被数据集引用时禁止删除 |
| 测试 | /data/connection/:id/test |
POST | 测试已保存连接 |
| 临时测试 | /data/connection/test |
POST | 测试未保存连接 |
| 表列表 | /data/connection/:id/tables |
GET | 按关键字分页读取数据库表 |
| 字段列表 | /data/connection/:id/tables/:tableName/fields |
GET | 读取表字段 |
详情响应示例:
{
"id": 1001,
"connectionCode": "sales_dw",
"connectionName": "销售数仓",
"dbType": "MYSQL",
"driverClassName": "com.mysql.cj.jdbc.Driver",
"jdbcUrl": "jdbc:mysql://10.***.***.15:3306/sales_dw",
"username": "report_user",
"hasPassword": true,
"schemaName": "sales_dw",
"status": 1,
"description": "销售分析数据源"
}
| 操作 | 接口 | 方法 | 说明 |
|---|---|---|---|
| 分页 | /data/dataset/page |
GET | 按名称、连接、类型、状态分页 |
| 列表 | /data/dataset/list |
GET | 返回启用数据集,用于报表选择 |
| 详情 | /data/dataset/:id |
GET | 返回数据集和字段配置 |
| 新增 | /data/dataset |
POST | 新增 TABLE 或 SQL 数据集 |
| 修改 | /data/dataset |
PUT | 修改数据集 |
| 删除 | /data/dataset/:id |
DELETE | 被报表引用时允许提示风险,首期可软约束 |
| 同步字段 | /data/dataset/:id/sync-fields |
POST | 从表或 SQL 预览结果同步字段 |
| 字段保存 | /data/dataset/:id/fields |
PUT | 批量保存字段配置 |
| 预览 | /data/dataset/:id/preview |
POST | 管理端预览数据 |
数据集保存请求示例:
{
"datasetCode": "sales_city_day",
"datasetName": "城市日销售数据集",
"connectionId": 1001,
"datasetType": "TABLE",
"tableName": "ads_city_sales_day",
"paramSchema": [
{
"paramName": "startTime",
"label": "开始时间",
"dataType": "DATE",
"required": false,
"operator": ">=",
"fieldName": "stat_date"
}
],
"maxRows": 1000,
"timeoutSeconds": 15,
"status": 1
}
| 操作 | 接口 | 方法 | 说明 |
|---|---|---|---|
| 执行数据集 | /data/dataset/runtime/query |
POST | 报表/AI/ChatBI 统一查询入口 |
| 获取元数据 | /data/dataset/runtime/:id/metadata |
GET | 返回数据集字段、参数定义、类型信息 |
运行时查询请求:
{
"datasetId": 10001,
"params": {
"startTime": "2026-05-01",
"endTime": "2026-05-11",
"cityCode": "110000"
},
"fields": ["cityName", "orderAmount"],
"pageNum": 1,
"pageSize": 50,
"outputMode": "ECHARTS_DATASET"
}
运行时查询响应:
{
"dimensions": ["cityName", "orderAmount"],
"source": [
{ "cityName": "北京", "orderAmount": 120000 },
{ "cityName": "上海", "orderAmount": 98000 }
],
"total": 2,
"pageNum": 1,
"pageSize": 50,
"fields": [
{ "fieldName": "cityName", "fieldLabel": "城市", "dataType": "STRING", "fieldRole": "DIMENSION" },
{ "fieldName": "orderAmount", "fieldLabel": "订单金额", "dataType": "NUMBER", "fieldRole": "MEASURE" }
]
}
新增菜单建议:
数据资产
├── 数据连接
└── 数据集管理
数据连接页面:
AiCrudPage。数据集页面:
AiCrudPage 加定制弹窗。/data/dataset/:id/preview。在图表数据配置中新增数据加载模式:
type DataFetchMode = 'static' | 'ajax' | 'request' | 'dataset'
新增请求配置字段:
interface DatasetRequestConfig {
datasetId?: string | number
datasetName?: string
datasetFields?: string[]
datasetParams?: Record<string, any>
dynamicRequestParams?: DynamicRequestParamBinding[]
pageNum?: number
pageSize?: number
maxRows?: number
outputMode?: 'ECHARTS_DATASET'
}
配置流程:
option.dataset。运行时流程:
dataset。resolveDynamicRequestParams() 解析动态参数。Params 合并为 params。/forge-report-api/data/dataset/runtime/query。{ dimensions, source } 写入图表 option.dataset。组件配置中保存数据集模式:
{
"requestConfig": {
"requestDataType": "dataset",
"datasetId": 10001,
"datasetName": "城市日销售数据集",
"datasetFields": ["cityName", "orderAmount"],
"pageNum": 1,
"pageSize": 50,
"maxRows": 1000,
"dynamicRequestParams": [
{
"id": "param_startTime",
"enabled": true,
"target": "Params",
"paramName": "startTime",
"source": "preset",
"sourceKey": "relativeTimeRange.start",
"presetType": "relativeTimeRange",
"presetOffsetDays": -7
}
]
}
}
password_cipher。:paramName 形式,不允许字符串拼接。data:connection:listdata:connection:adddata:connection:editdata:connection:removedata:connection:testdata:dataset:listdata:dataset:adddata:dataset:editdata:dataset:removedata:dataset:previewAI 生成报表可读取:
AI 不直接读取密码或 JDBC URL,只通过数据集元数据和运行时查询接口工作。
ChatBI 可基于 data_dataset 和 data_dataset_field 构建语义层:
default_agg 作为默认指标聚合方式。dict_type 作为枚举值解释来源。param_schema_json 作为可问答筛选条件。预留 DbDialect:
DbDialect
├── quoteIdentifier(name)
├── buildLimitSql(sql, limit)
├── buildPagedSql(sql, pageNum, pageSize)
├── queryTables(connection, schemaName, keyword, page)
└── queryColumns(connection, schemaName, tableName)
首期实现 MySQL;PostgreSQL、Oracle、SQLServer 后续按同一接口扩展。
datasetId、字段选择和动态参数,不保存连接密码、SQL 明文副本。| 场景 | 提示 |
|---|---|
| 数据连接不存在 | 数据连接不存在或已删除 |
| 数据连接禁用 | 数据连接已禁用 |
| 测试连接失败 | 数据连接测试失败,请检查地址、用户、密码和网络 |
| 数据集不存在 | 数据集不存在或已删除 |
| 数据集禁用 | 数据集已禁用 |
| SQL 不安全 | SQL 仅允许单条查询语句 |
| 参数缺失 | 缺少必填参数:{paramName} |
| 查询超时 | 数据集查询超时,请缩小筛选范围 |
| 返回行数超限 | 查询结果超过最大行数限制 |
后端:
forge-plugin-data。forge-framework/forge-plugin-parent/pom.xml 增加模块。forge-admin-server/pom.xml 增加依赖。forge-report-server/pom.xml 增加依赖。前端:
forge-admin-ui 新增数据资产管理页面。forge-report-ui 新增数据集 API 封装。forge-report-ui 图表数据配置面板新增数据集模式。forge-report-ui 数据请求执行链路新增 dataset 分支。chartEditStore 类型和默认配置扩展。兼容性:
后端测试:
前端测试:
forge-admin-ui 数据连接页面构建通过。forge-admin-ui 数据集字段配置交互验证。forge-report-ui 数据加载模式切换后配置能保存到报表 JSON。验证命令:
cd forge && mvn -pl forge-framework/forge-plugin-parent/forge-plugin-data,forge-admin-server,forge-report-server -am compile -DskipTests
source ~/.nvm/nvm.sh && nvm use v20.19.0 && cd forge-admin-ui && pnpm build
source ~/.nvm/nvm.sh && nvm use v20.19.0 && cd forge-report-ui && pnpm build
forge-plugin-data 模块。{ dimensions, source }。RequestConfigType 和默认配置。| 风险 | 应对 |
|---|---|
| SQL 注入 | SQL 安全校验 + 命名参数 + PreparedStatement |
| 慢 SQL 拖垮服务 | 查询超时 + 最大行数 + 后续缓存扩展 |
| 密码泄露 | 密文存储 + 脱敏返回 + 日志屏蔽 |
| 不同数据库方言差异 | DbDialect 抽象,首期 MySQL 优先 |
| 报表动态参数触发死循环 | 只监听被绑定的筛选组件值,不监听图表 dataset |
| 平台能力被报表私有化 | 插件放在 forge-plugin-data,admin/report/AI 共同依赖 |