# 数据桥接对接文档 本文面向需要和 岩安测控 对接的第三方系统,覆盖两类能力: 1. 第三方系统查询设备及其物模型。 2. 第三方系统获取设备上报数据,包括 岩安测控 主动推送和第三方主动查询。 本文基于当前仓库已有接口和数据桥接实现整理。默认服务根地址记为 `{BASE_URL}`,例如 `http://1.116.124.85:8080`。 ## 对接方式总览 ```mermaid flowchart LR Device[设备] --> Protocol[MQTT/TCP/HTTP/CoAP 等接入] Protocol --> 岩安测控[岩安测控 数据处理] 岩安测控 --> Store[(MySQL/TDengine)] 岩安测控 --> Rule[数据流脚本/规则引擎] Rule --> PushHTTP[主动推送 HTTP] Rule --> PushMQTT[主动桥接 MQTT] Rule --> PushDB[写入第三方数据库] Third[第三方系统] --> API[REST API 主动查询] API --> 岩安测控 ``` | 场景 | 推荐方式 | 说明 | | --- | --- | --- | | 获取设备清单 | REST API 主动查询 | 查询 `iot_device` 设备列表或按设备编号查询详情。 | | 获取设备物模型 | REST API 主动查询 | 查询产品级/设备级物模型,包含属性、事件、服务、计算模型。 | | 获取实时值 | REST API 主动查询 | 查询设备运行时缓存值。 | | 获取历史上报数据 | REST API 主动查询 | 查询数据中心历史接口,支持按设备、时间范围、物模型标识符过滤。 | | 上报数据实时同步给第三方 | 数据桥接主动推送 | 通过数据流脚本触发 HTTP、MQTT 或数据库桥接。 | | 第三方系统周期同步 | REST API 定时拉取 | 第三方按时间窗口分页/分段查询历史数据。 | ## 认证 除安全配置中明确放行的匿名接口外,REST API 默认需要登录 Token。 ### 登录获取 Token ```http POST {BASE_URL}/login Content-Type: application/json { "username": "admin", "password": "admin123", "code": "验证码", "uuid": "验证码uuid" } ``` 成功响应: ```json { "code": 200, "msg": "操作成功", "token": "eyJhbGciOiJIUzUxMiJ9..." } ``` 后续请求头: ```http Authorization: Bearer {token} ``` 如果系统关闭验证码或使用内部服务账号,可按部署配置调整登录参数。第三方生产对接建议单独创建服务账号,并只授予以下最小权限: | 能力 | 权限标识 | | --- | --- | | 设备查询 | `iot:device:list`, `iot:device:query` | | 物模型查询 | `iot:model:list`, `iot:model:query` | | 历史数据查询 | `dataCenter:history:list` | | 数据分析查询 | `dataCenter:analysis:list` | | 数据桥接配置 | `iot:bridge:list`, `iot:bridge:add`, `iot:bridge:edit`, `iot:bridge:query` | | 数据流脚本配置 | `iot:script:list`, `iot:script:add`, `iot:script:edit`, `iot:script:query` | ## 通用响应 普通接口返回 `AjaxResult`: ```json { "code": 200, "msg": "操作成功", "data": {} } ``` 分页接口返回 `TableDataInfo`: ```json { "code": 200, "msg": "查询成功", "total": 100, "rows": [] } ``` 常见约定: - `code=200` 表示成功。 - 设备编号 `serialNumber` 在上报和查询中通常会转为大写处理,第三方建议统一传大写。 - 时间字段建议使用 `yyyy-MM-dd HH:mm:ss`。 ## 查询设备 ### 设备分页列表 ```http GET {BASE_URL}/iot/device/list?pageNum=1&pageSize=20&deviceName=xxx&serialNumber=ABC001&productId=1 Authorization: Bearer {token} ``` 说明: - Controller:`DeviceController.list` - 权限:`iot:device:list` - 返回:分页设备列表。 - 常用过滤字段来自 `Device` 对象,实际可用字段包括 `deviceId`、`deviceName`、`serialNumber`、`productId`、`tenantId`、`deptId`、`status` 等。 ### 设备简短列表 适合第三方做设备下拉或轻量同步。 ```http GET {BASE_URL}/iot/device/shortList?pageNum=1&pageSize=100&productId=1 Authorization: Bearer {token} ``` ### 查询所有设备简短列表 ```http GET {BASE_URL}/iot/device/all Authorization: Bearer {token} ``` ### 按设备 ID 查询详情 ```http GET {BASE_URL}/iot/device/{deviceId} Authorization: Bearer {token} ``` ### 按设备编号查询详情 ```http GET {BASE_URL}/iot/device/getDeviceBySerialNumber/{serialNumber} Authorization: Bearer {token} ``` 示例: ```http GET {BASE_URL}/iot/device/getDeviceBySerialNumber/ABC001 Authorization: Bearer {token} ``` ## 查询设备物模型 岩安测控 的物模型主要由 `productId + identifier` 定义。设备级计算物模型或特殊覆盖会结合 `serialNumber` 处理。 ### 按产品 ID 和设备编号查询物模型 推荐第三方使用该接口,它会从缓存中合并产品级物模型和设备级处理结果。 ```http GET {BASE_URL}/iot/model/listByProductIdAndSerialNumber?productId=1&serialNumber=ABC001 Authorization: Bearer {token} ``` 说明: - Controller:`ThingsModelController.listByProductIdAndSerialNumber` - 权限:`iot:model:list` - 返回:`ThingsModelDTO` 列表。 典型返回项字段: | 字段 | 含义 | | --- | --- | | `modelId` | 物模型 ID。 | | `identifier` | 物模型标识符,历史数据查询和推送数据中使用该字段作为变量名。 | | `modelName` | 物模型名称。 | | `type` | 物模型类型,通常表示属性/功能/事件等。 | | `datatype` | 数据类型定义,例如 number、string、bool、enum 等。 | | `specs` | 枚举、单位、取值范围等扩展规格。 | | `modelOrder` | 排序。 | ### 查询设备变量概况 ```http GET {BASE_URL}/iot/device/listThingsModel?deviceId=100&pageNum=1&pageSize=50 Authorization: Bearer {token} ``` 可选过滤: - `modelName`:按物模型名称模糊过滤。 - `type`:按物模型类型过滤。 ### 查询产品物模型列表 ```http GET {BASE_URL}/iot/model/list?pageNum=1&pageSize=100&productId=1 Authorization: Bearer {token} ``` ### 获取缓存 JSON 物模型 ```http GET {BASE_URL}/iot/model/cache/{productId} Authorization: Bearer {token} ``` 适用于需要拿完整 TSL JSON 的场景。 ## 查询实时数据 ### 查询设备运行时状态 ```http GET {BASE_URL}/iot/runtime/running?serialNumber=ABC001 Authorization: Bearer {token} ``` 说明: - Controller:`DeviceRuntimeController.runState` - 返回:物模型当前值列表。 - 数据来源:运行时缓存/物模型缓存,不适合替代历史审计。 典型返回: ```json { "code": 200, "msg": "操作成功", "data": [ { "id": "temperature", "name": "温度", "value": "26.5", "type": 1, "datatype": { "type": "decimal", "unit": "℃" } } ] } ``` ## 第三方主动查询设备上报数据 ### 推荐接口:数据中心历史查询 ```http POST {BASE_URL}/data/center/deviceHistory Authorization: Bearer {token} Content-Type: application/json { "deviceId": 100, "serialNumber": "ABC001", "beginTime": "2026-05-24 00:00:00", "endTime": "2026-05-24 23:59:59", "identifierList": [ { "identifier": "temperature", "type": 1 }, { "identifier": "humidity", "type": 1 } ] } ``` 说明: - Controller:`DataCenterController.deviceHistory` - 权限:`dataCenter:history:list` - `serialNumber` 必填。 - `identifierList` 建议传入,避免一次拉取全部变量导致响应过大。 - `type` 与物模型类型保持一致,常见属性数据为 `1`,以实际物模型返回值为准。 典型返回结构: ```json { "code": 200, "msg": "操作成功", "data": [ { "2026-05-24 10:00:00": [ { "temperature": "26.5" }, { "humidity": "60" } ] }, { "2026-05-24 10:01:00": [ { "temperature": "26.7" }, { "humidity": "59" } ] } ] } ``` ### 设备日志列表 适合按原始日志粒度查询。 ```http GET {BASE_URL}/iot/deviceLog/list?pageNum=1&pageSize=50&serialNumber=ABC001&beginTime=2026-05-24 00:00:00&endTime=2026-05-24 23:59:59 Authorization: Bearer {token} ``` 说明: - Controller:`DeviceLogController.list` - 权限:`iot:device:list` - 返回:分页日志行,字段来自 `DeviceLog`。 ### 设备历史数据 GET 查询 ```http GET {BASE_URL}/iot/deviceLog/history?serialNumber=ABC001&beginTime=2026-05-24 00:00:00&endTime=2026-05-24 23:59:59 Authorization: Bearer {token} ``` 返回按 `identifier` 分组的历史数据,适合较简单的查询场景。 ### 按时间聚合的历史数据 ```http GET {BASE_URL}/iot/deviceLog/historyGroupByCreateTime?pageNum=1&pageSize=100&serialNumber=ABC001&beginTime=2026-05-24 00:00:00&endTime=2026-05-24 23:59:59 Authorization: Bearer {token} ``` ### 网关计算物模型历史 ```http POST {BASE_URL}/data/center/deviceHistoryCalculated Authorization: Bearer {token} Content-Type: application/json { "deviceId": 100, "serialNumber": "GW001", "beginTime": "2026-05-24 00:00:00", "endTime": "2026-05-24 23:59:59", "identifierList": [ { "identifier": "avg_temperature", "type": 1 } ] } ``` ### 周期拉取建议 第三方主动查询历史数据时,建议使用滑动时间窗口: 1. 首次同步:按小时或天分段拉取。 2. 增量同步:每 1 至 5 分钟拉取一次 `[lastSyncTime, now - 10s]`。 3. 去重键:`serialNumber + identifier + time`。 4. 重试:失败窗口不要丢弃,下次继续从 `lastSuccessEndTime` 拉取。 5. 大设备量:先同步设备列表,再按设备分批拉取,避免单次请求过大。 ## 岩安测控 主动推送给第三方系统 岩安测控 当前主动推送走“数据流脚本 + 数据桥接”机制。设备上报后,`RuleProcess.processRuleScript(...)` 会按产品和事件类型找到启用的数据流脚本,然后执行脚本动作: | 脚本动作 | `scriptAction` | 桥接组件 | 用途 | | --- | ---: | --- | --- | | HTTP 推送 | 3 | `httpBridge` | 调用第三方 HTTP 接口。 | | MQTT 桥接 | 4 | `mqttBridge` | 发布到第三方 MQTT Broker。 | | 数据库存储 | 5 | `databaseBridge` | 写入第三方数据库。 | 设备上报事件类型: | 事件 | `scriptEvent` | 说明 | | --- | ---: | --- | | 设备上报 | 1 | 设备属性/数据上报后触发。 | | 平台下发 | 2 | 平台服务/指令下发前后触发。 | | 设备上线 | 3 | 设备上线触发。 | | 设备离线 | 4 | 设备离线触发。 | | HTTP 桥接入口数据 | 5 | 第三方调用 `/bridge/get|post|put` 后触发。 | | MQTT 桥接入口数据 | 6 | MQTT 输入桥接触发,按脚本配置处理。 | ### 主动 HTTP 推送配置 1. 新增数据桥接。 ```http POST {BASE_URL}/iot/bridge Authorization: Bearer {token} Content-Type: application/json { "name": "推送到第三方业务系统", "enable": "1", "type": 3, "direction": 2, "route": "https://third.example.com/iot/report", "configJson": "{\"method\":\"POST\",\"hostUrl\":\"https://third.example.com/iot/report\",\"requestHeaders\":\"{\\\"Authorization\\\":\\\"Bearer xxx\\\"}\",\"requestQuerys\":\"{}\",\"requestConfig\":\"\",\"requestBody\":\"\"}" } ``` 字段说明: | 字段 | 说明 | | --- | --- | | `type=3` | HTTP 推送。 | | `direction=2` | 输出方向。 | | `route` | 展示/路由字段,实际 HTTP 地址以 `configJson.hostUrl` 为准。 | | `configJson.method` | HTTP 方法,如 `POST`。 | | `configJson.hostUrl` | 第三方接收地址。 | | `configJson.requestHeaders` | 请求头 JSON 字符串。 | | `configJson.requestQuerys` | Query 参数 JSON 字符串。 | | `configJson.requestBody` | 自定义请求体模板;为空时默认使用脚本上下文 payload。 | 2. 新增数据流脚本。 下面脚本展示的是核心意图:取得 `MsgContext`,设置桥接 ID,必要时重写 `payload/topic`。不同 LiteFlow 脚本语言的上下文变量写法可能不同,落地时以当前环境脚本校验结果为准。 ```http POST {BASE_URL}/iot/script Authorization: Bearer {token} Content-Type: application/json { "applicationName": "岩安测控", "scriptName": "设备上报转第三方HTTP", "scriptType": "script", "scriptLanguage": "groovy", "scriptPurpose": 1, "scriptEvent": 1, "scriptAction": 3, "productId": 1, "enable": 1, "bridgeId": 10, "scriptData": "def cxt = _meta.getContextBean(com.岩安测控.ruleEngine.context.MsgContext.class); cxt.setPayload(cxt.getPayload()); cxt.setData('httpBridgeID', 10);" } ``` 脚本关键点: - `scriptPurpose=1` 表示数据流。 - `scriptEvent=1` 表示设备上报触发。 - `scriptAction=3` 表示执行 HTTP 推送组件。 - `productId` 表示该产品下设备上报时触发。 - 脚本必须向上下文写入 `httpBridgeID`,值为桥接配置 `bridge.id`;HTTP 桥接组件会从上下文读取该 ID。 - 脚本可改写 `payload`,从而控制推送给第三方的报文。 ### 推荐 HTTP 推送报文 如果第三方希望使用稳定格式,建议脚本把 payload 改造成如下 JSON: ```json { "event": "property.post", "productId": 1, "serialNumber": "ABC001", "protocolCode": "ModbusRtu", "reportTime": "2026-05-24 10:00:00", "data": [ { "identifier": "temperature", "value": "26.5" }, { "identifier": "humidity", "value": "60" } ], "rawPayload": "[{\"id\":\"temperature\",\"value\":\"26.5\"}]" } ``` 当前默认上下文 payload 通常是设备上报解析后的物模型数据 JSON,字段形态可能随协议解析结果变化。生产对接建议在脚本中统一出站格式,避免第三方直接依赖内部 payload。 ### 主动 MQTT 桥接配置 1. 新增 MQTT 桥接。 ```http POST {BASE_URL}/iot/bridge Authorization: Bearer {token} Content-Type: application/json { "name": "第三方MQTT桥接", "enable": "1", "type": 4, "direction": 2, "route": "third/iot/report", "configJson": "{\"name\":\"third-mqtt\",\"hostUrl\":\"broker.example.com:1883\",\"username\":\"user\",\"password\":\"pass\",\"clientId\":\"岩安测控-bridge\"}" } ``` 2. 新增脚本。 ```json { "applicationName": "岩安测控", "scriptName": "设备上报转第三方MQTT", "scriptType": "script", "scriptLanguage": "groovy", "scriptPurpose": 1, "scriptEvent": 1, "scriptAction": 4, "productId": 1, "enable": 1, "bridgeId": 11, "scriptData": "def cxt = _meta.getContextBean(com.岩安测控.ruleEngine.context.MsgContext.class); cxt.setTopic('third/iot/' + cxt.getSerialNumber() + '/property/post'); cxt.setData('mqttBridgeID', 11);" } ``` 说明: - MQTT 桥接组件使用 `cxt.getTopic()` 作为发布主题。 - 脚本必须写入 `mqttBridgeID`;MQTT 桥接组件会从上下文读取该 ID。 - `payload` 默认透传,建议按第三方格式重写。 ### 写入第三方数据库 1. 配置数据库桥接数据源。 数据库桥接组件读取 `MultipleDataSource`,字段包括: | 字段 | 说明 | | --- | --- | | `databaseSource` | 数据库类型,支持 MySQL、SQLServer、Oracle、PostgreSQL、H2。 | | `host` | 地址,包含主机和端口。 | | `dataBaseName` | 数据库名。 | | `userName` | 用户名。 | | `password` | 密码。 | | `sql` | 要执行的 SQL,可使用上下文占位符替换。 | 2. 新增数据流脚本,写入 `databaseBridgeID`。 ```json { "scriptPurpose": 1, "scriptEvent": 1, "scriptAction": 5, "productId": 1, "enable": 1, "scriptData": "def cxt = _meta.getContextBean(com.岩安测控.ruleEngine.context.MsgContext.class); cxt.setData('databaseBridgeID', 20);" } ``` 注意:数据库桥接当前通过拼接后的 SQL 执行,生产环境必须控制 SQL 模板来源和字段转义,避免把不可信 payload 直接拼入 SQL。 ## 第三方调用 岩安测控 桥接入口 岩安测控 也提供了桥接入口,第三方可以把数据送入 岩安测控 的数据流脚本: | 方法 | 地址 | 说明 | | --- | --- | --- | | GET | `{BASE_URL}/bridge/get` | Query/Header 进入上下文。 | | POST | `{BASE_URL}/bridge/post` | Body 进入上下文 payload。 | | PUT | `{BASE_URL}/bridge/put` | Body 进入上下文 payload。 | 这些入口会以: ```text scriptPurpose=1 scriptEvent=5 route=/bridge/get|/bridge/post|/bridge/put ``` 查询并执行数据流脚本。 安全注意:当前安全配置未默认放行 `/bridge/**`,因此仍需要 Token,除非部署侧自行放开。 ## 推荐对接方案 ### 方案 A:实时同步优先 适用:第三方需要尽快拿到设备上报数据。 1. 第三方提供 HTTP 接收地址或 MQTT Broker。 2. 岩安测控 配置 `bridge`。 3. 岩安测控 为对应产品配置数据流脚本。 4. 第三方收到推送后按 `serialNumber + identifier + reportTime` 入库去重。 5. 第三方定时调用历史查询接口补偿漏推窗口。 推荐组合: - 实时:HTTP 推送或 MQTT 桥接。 - 补偿:`POST /data/center/deviceHistory`。 ### 方案 B:第三方定时拉取 适用:第三方不开放公网回调地址,或只需要分钟级/小时级同步。 1. 调用 `/iot/device/list` 或 `/iot/device/shortList` 同步设备。 2. 调用 `/iot/model/listByProductIdAndSerialNumber` 同步物模型。 3. 按设备调用 `/data/center/deviceHistory` 拉取上报数据。 4. 使用滑动窗口和去重键保证幂等。 ### 方案 C:第三方数据库落库 适用:第三方只提供数据库账号,不提供 API。 1. 配置数据库连接。 2. 为产品配置数据流脚本。 3. 数据库桥接执行 SQL 写入第三方库。 不建议把该方案作为首选,原因是数据库账号权限、SQL 模板安全和网络连通性风险更高。 ## 字段映射建议 第三方侧建议建立如下最小模型。 ### 设备表 | 字段 | 来源 | | --- | --- | | `device_id` | `iot_device.deviceId` | | `serial_number` | `iot_device.serialNumber` | | `device_name` | `iot_device.deviceName` | | `product_id` | `iot_device.productId` | | `status` | `iot_device.status` | | `tenant_id` | `iot_device.tenantId` | ### 物模型表 | 字段 | 来源 | | --- | --- | | `model_id` | `ThingsModelDTO.modelId` | | `product_id` | 查询入参或返回字段 | | `identifier` | `ThingsModelDTO.identifier` | | `name` | `ThingsModelDTO.modelName` | | `type` | `ThingsModelDTO.type` | | `datatype` | `ThingsModelDTO.datatype` | ### 设备数据表 | 字段 | 来源 | | --- | --- | | `serial_number` | 设备编号 | | `product_id` | 设备所属产品 | | `identifier` | 物模型标识符 | | `value` | 上报值 | | `report_time` | 历史接口返回的时间或推送报文时间 | | `source` | `pull` 或 `push` | | `raw_payload` | 原始推送/查询报文 | ## 幂等、重试和安全 - 推送接口必须幂等,建议第三方以 `serialNumber + identifier + reportTime` 去重。 - 岩安测控 主动推送失败当前主要依赖组件日志排查,建议第三方同时做主动拉取补偿。 - 第三方主动查询必须按时间窗口限制范围,避免一次拉取全量历史。 - HTTP 推送建议使用 HTTPS、固定 Token 或签名头。 - MQTT 桥接建议使用独立账号和最小 Topic 权限。 - 数据库桥接建议只授予 INSERT 权限,避免执行 DDL 或高危 SQL。 ## 当前实现注意点 - `岩安测控-mq` 当前核心是 JVM 内本地阻塞队列,不是外部 RocketMQ 的强持久化链路。 - 主动 HTTP 推送的默认 payload 由规则脚本上下文决定,生产对接应在脚本中统一出站报文。 - 数据桥接脚本查询按 `productId + scriptPurpose + scriptEvent + enable` 等条件筛选;产品维度必须配置正确。 - 业务表关系大多没有数据库外键,第三方不要依赖数据库外键判断关联,应以 API 返回和业务字段为准。