From add2093e9034ecd52f3e5f3c8e06b2f6bd18b635 Mon Sep 17 00:00:00 2001 From: "zhczyx@163.com" Date: Mon, 1 Jun 2026 11:23:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3=E5=8F=8A?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现了通过设备ID和时间范围查询设备数据的功能,包括: 1. 新增查询参数DTO和返回值VO 2. 在CommonService中添加接口定义并实现查询逻辑 3. 在CommonController中添加对外接口路由 4. 补充完整的技能文档和OpenAPI接口文档 --- .DS_Store | Bin 0 -> 10244 bytes .../business/controller/CommonController.java | 9 + .../dto/data/QueryDeviceDataParams.java | 19 ++ .../business/vo/data/DeviceDataVO.java | 41 +++ .../business/service/CommonService.java | 3 + .../service/impl/CommonServiceImpl.java | 122 +++++++++ document/.DS_Store | Bin 0 -> 6148 bytes .../openapis/query-device-data-openapi.json | 236 +++++++++++++++++ document/skills/.DS_Store | Bin 0 -> 6148 bytes document/skills/eaon_query-device-data.zip | Bin 0 -> 3850 bytes document/skills/query-device-data/SKILL.md | 239 ++++++++++++++++++ 11 files changed, 669 insertions(+) create mode 100644 .DS_Store create mode 100644 data-center-business-model/src/main/java/com/techsor/datacenter/business/dto/data/QueryDeviceDataParams.java create mode 100644 data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java create mode 100644 document/.DS_Store create mode 100644 document/openapis/query-device-data-openapi.json create mode 100644 document/skills/.DS_Store create mode 100644 document/skills/eaon_query-device-data.zip create mode 100644 document/skills/query-device-data/SKILL.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..1f8ec3ddc44805426fab0ea7644e83d56b04d435 GIT binary patch literal 10244 zcmeI1&ubGw6vy9~G!3+cf*$-)a1S1YR%;KvsE2JyLGU12@#LXD5^E*NmZb6O{sCS* zcoQrlEsCO45fu+!q=+IOJo*oah#tI(e&5WPyzQoi?55De%rf&fJ8#~5`LLPY_d-N! zvQZo(@`xyp&T_CHLz~9)++%Hzy)pu+u%5~bW7G3NWhtiVE;s^?fFs}tI0BBqZXtkY zHn)7Ak#2MZ905n5Nr3kU51plNWoV?{Ixy%I05Xfqy5W3~Par)jeJevFF@vVeQb@B@ z*%U*W<+$!yJ>SaENVA-jO+J+MtZas&w0GF|v^pu@NH;nHjzF9M=k8fLP7Ab1%QAn@ z3{35nbCsY_m@5Z!xRyV6a^}&U#~TyT`QoW~FDMYe!&N z%u3&XZ(ZuYXM9IATHf1hNdH8i;eZao_be@=AES9hQN?+QYWOrq4XPuyDn8e7@O(fO z9065jti6@5={*`5#Fs@3_VvydNR+XF-C zElPgt#ql?mU&=To$L?8`JcpnBVxIdu;K_GtAPMI7{rr-|hGcf7aQ}s6)^RM7QW`sw zOK$W8b2-=n7yd=^4pNS=Dct;&)Q;qH~KDl>;%qI^%0q&Cqo_G4GDDM}d-*4OL$nQ21TBf?<%F}yGqZ-kJZidGM?|*)BjmVY{*!)(vflWeAN4P260qqDN2O{Bs(L0 zPppkUd>(2R&Dqv-IzB7?X`60v1RMcJz!7i+x=SEq%z0e@pW6EW|L!_<)*JyxU{?`P z*}`;T5+T{zdMr4uwR`9@=-gN@G*U0Ypv&=)x*U%WT#i4A&bm6Ox97f deviceIds; + + @Schema(description = "Start time, Unix milliseconds timestamp", example = "1709870240425", required = true) + private Long startTime; + + @Schema(description = "End time, Unix milliseconds timestamp", example = "1709889240425", required = true) + private Long endTime; +} \ No newline at end of file diff --git a/data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java b/data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java new file mode 100644 index 0000000..36d8200 --- /dev/null +++ b/data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java @@ -0,0 +1,41 @@ +package com.techsor.datacenter.business.vo.data; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class DeviceDataVO { + + @Schema(description = "Device ID", example = "FFFF0001") + private String deviceId; + + @Schema(description = "Device name", example = "温度传感器") + private String deviceName; + + @Schema(description = "Raw data JSON", example = "{\"temp\":25.5}") + private String rawData; + + @Schema(description = "Device data values, comma-separated", example = "25.5") + private String dataValue; + + @Schema(description = "Receive timestamp (milliseconds)", example = "1709870240425") + private Long receiveTs; + + @Schema(description = "Status", example = "UP") + private String status; + + @Schema(description = "Alert level", example = "1") + private String alertLevel; + + @Schema(description = "Alert content", example = "温度异常") + private String alertContent; + + @Schema(description = "Building info", example = "东京建物日本桥ビル") + private String buildingInfo; + + @Schema(description = "Floor info", example = "3F") + private String floorInfo; + + @Schema(description = "Space info", example = "会議室A") + private String spaceInfo; +} \ No newline at end of file diff --git a/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java b/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java index 6dc56ff..c23a720 100644 --- a/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java +++ b/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java @@ -16,6 +16,7 @@ import com.techsor.datacenter.business.dto.common.DatacenterV1QueryParams; import com.techsor.datacenter.business.dto.common.GetFileTemporaryParams; import com.techsor.datacenter.business.dto.common.QueryBuilding; import com.techsor.datacenter.business.dto.common.QueryDataFor2D3D; +import com.techsor.datacenter.business.dto.data.QueryDeviceDataParams; import com.techsor.datacenter.business.dto.device.ApiAlarmDeviceSearchParams; import com.techsor.datacenter.business.dto.device.ApiRiliDeviceSearchParams; import com.techsor.datacenter.business.dto.device.DeviceSearchParams; @@ -88,4 +89,6 @@ public interface CommonService { SimpleDataResponse querySpaceInfoList(String authorization, ApiSpaceSearchParams searchParams); + SimpleDataResponse queryDeviceData(String apikey, QueryDeviceDataParams params); + } diff --git a/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java b/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java index 28034fd..d1671a7 100644 --- a/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java +++ b/data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java @@ -7,6 +7,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.text.MessageFormat; +import java.time.ZoneId; import java.time.Duration; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -78,6 +79,7 @@ import com.techsor.datacenter.business.dto.common.DatacenterV1QueryParams; import com.techsor.datacenter.business.dto.common.GetFileTemporaryParams; import com.techsor.datacenter.business.dto.common.QueryBuilding; import com.techsor.datacenter.business.dto.common.QueryDataFor2D3D; +import com.techsor.datacenter.business.dto.data.QueryDeviceDataParams; import com.techsor.datacenter.business.dto.device.ApiAlarmDeviceSearchParams; import com.techsor.datacenter.business.dto.device.ApiRiliDeviceSearchParams; import com.techsor.datacenter.business.dto.device.DeviceSearchParams; @@ -103,6 +105,7 @@ import com.techsor.datacenter.business.vo.device.ApiAlarmDeviceInfoVO; import com.techsor.datacenter.business.vo.device.ApiCancelAlarmDeviceInfoVO; import com.techsor.datacenter.business.vo.device.ApiRiliDeviceInfoVO; import com.techsor.datacenter.business.vo.device.DeviceVO; +import com.techsor.datacenter.business.vo.data.DeviceDataVO; import com.techsor.datacenter.business.vo.space.ApiSpaceWithAssetVO; import com.techsor.datacenter.business.vo.version.VersionVO; @@ -1977,4 +1980,123 @@ public class CommonServiceImpl implements CommonService { return SimpleDataResponse.success(deviceInfoVOs); } + + @Override + public SimpleDataResponse queryDeviceData(String apikey, QueryDeviceDataParams params) { + try { + if (CollectionUtils.isEmpty(params.getDeviceIds())) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[deviceIds] is required"); + } + if (null == params.getStartTime()) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[startTime] is required"); + } + if (null == params.getEndTime()) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[endTime] is required"); + } + + long startTime = params.getStartTime(); + long endTime = params.getEndTime(); + + if (startTime < 10000000000L) { + startTime = startTime * 1000; + } + if (endTime < 10000000000L) { + endTime = endTime * 1000; + } + + if (startTime > endTime) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "startTime must be before endTime"); + } + + if (endTime - startTime > 7 * 24 * 60 * 60 * 1000L) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "Time range must not exceed 7 days"); + } + + Map paramMap = new HashMap<>(); + paramMap.put("apikey", apikey); + ApikeyInfo2 apikeyInfo = commonOpt.getAuroraInfoByApikey(paramMap); + + if (null == apikeyInfo) { + return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "Apikey is invalid"); + } + + apikeyInfo.setAuroraPassword(DESUtil.decrypt(apikeyInfo.getAuroraPassword(), Constants.DES_SALT)); + apikeyInfo.setAuroraUsername(DESUtil.decrypt(apikeyInfo.getAuroraUsername(), Constants.DES_SALT)); + + List dateList = DateUtils.getDatesBetween(startTime, endTime, ZoneId.of("Asia/Tokyo"), "yyyy_MM_dd"); + + List resultList = new ArrayList<>(); + + Class.forName("com.mysql.cj.jdbc.Driver"); + try (Connection conn = DriverManager.getConnection( + MessageFormat.format(Constants.AURORA_URL_FORMAT, apikeyInfo.getAuroraUrl()), + apikeyInfo.getAuroraUsername(), apikeyInfo.getAuroraPassword())) { + + StringBuilder inClause = new StringBuilder(); + for (int i = 0; i < params.getDeviceIds().size(); i++) { + inClause.append("?"); + if (i < params.getDeviceIds().size() - 1) { + inClause.append(","); + } + } + + for (String dateStr : dateList) { + String table = "rawData_" + dateStr; + String sql = "select * from " + table + + " where deviceId in (" + inClause + ") and ? <= receive_ts and receive_ts <= ?" + + " order by receive_ts desc, hashId desc"; + + logger.info("queryDeviceData sql:{}", sql); + + try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) { + int idx = 1; + for (String deviceId : params.getDeviceIds()) { + preparedStatement.setString(idx++, deviceId); + } + preparedStatement.setLong(idx++, startTime); + preparedStatement.setLong(idx, endTime); + + ResultSet result = preparedStatement.executeQuery(); + + while (result.next()) { + DeviceDataVO vo = new DeviceDataVO(); + vo.setDeviceId(result.getString("deviceId")); + vo.setDeviceName(result.getString("deviceTypeName")); + vo.setRawData(result.getString("rawData")); + + String rawDataStr = result.getString("rawData"); + if (StringUtils.isNotBlank(rawDataStr)) { + try { + JSONObject rawDataObj = JSON.parseObject(rawDataStr); + List valueList = new ArrayList<>(); + for (String key : rawDataObj.keySet()) { + valueList.add(rawDataObj.get(key)); + } + vo.setDataValue(StringUtils.join(valueList, ",")); + } catch (Exception ignored) { + } + } + + vo.setReceiveTs(result.getLong("receive_ts")); + vo.setStatus(result.getString("status")); + vo.setAlertLevel(result.getString("alertLevel")); + vo.setAlertContent(result.getString("alertContent")); + vo.setBuildingInfo(result.getString("buildingInfo")); + vo.setFloorInfo(result.getString("floorInfo")); + vo.setSpaceInfo(result.getString("spaceInfo")); + resultList.add(vo); + } + } + } + } + + return SimpleDataResponse.success(resultList); + + } catch (Exception e) { + logger.error("queryDeviceData error", e); + return SimpleDataResponse.fail(ResponseCode.SERVER_ERROR, ResponseCode.SERVER_ERROR_MSG); + } + } + + } diff --git a/document/.DS_Store b/document/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e87a7d088badc82f210d6c90814eb9de9d538ba2 GIT binary patch literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aOhW3qeFtP_*94b9pr1e41so(?;IF^;wq1zKL}UUtl!py{vwicP4KkuYILs4+?y)?L3Q&PRP{6(q1#Vaq+d%(xVDJ_II6~MBbMGa9#R9;Z z*ajj3)1U%_s@Y;_&=D`0R}c{U>M7p)&Dj8 zL;v3;aYY5Fz+Wk#qgAt7;z?OsdylhPTi_eGs`Ml&mQ{N{4I@ZnG}!$Qa}nw0V(ji0@izJ^P@mTDIf); zz^4NCeW-N9mN*3Zr-Q*q0OE{kH?Dn_AXZBdTjCJN46Ou}7}Sy@MhQCeHS1d95Eyh6 zKbiN*lS@u0#ZPCxdO1o9RFnczV64DlY!}x5FX%ta|6`JNQa}p)D+S7Ib+uaZm9n=^ yUe0=LrQgs$jJ00Q;H{YGt(Y5Y#iw8Ds;zmwB@Tg3XWr>V{Ro&YGAZyE3cLf`(jj61 literal 0 HcmV?d00001 diff --git a/document/skills/eaon_query-device-data.zip b/document/skills/eaon_query-device-data.zip new file mode 100644 index 0000000000000000000000000000000000000000..8e36cdf7e703e2e3b31de1fc2d634f35730f733b GIT binary patch literal 3850 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 Ndw2fM^6Y` | 是 | 设备ID列表,由用户提供 | +| `startTime` | `Long` | 是 | 开始时间戳(毫秒,也支持秒级自动转换),由用户提供或根据用户描述计算 | +| `endTime` | `Long` | 是 | 结束时间戳(毫秒,也支持秒级自动转换),与 startTime 跨度不能超过7天,由用户提供或根据用户描述计算 | + +## 返回数据 + +返回 `SimpleDataResponse>`,其中 `data` 为设备数据列表: + +| 字段 | 类型 | 说明 | +|------|:----:|------| +| `deviceId` | String | 设备ID | +| `deviceName` | String | 设备名称 | +| `rawData` | String | 原始数据 JSON | +| `dataValue` | String | 从 rawData 解析出的数值,逗号拼接 | +| `receiveTs` | Long | 接收时间戳(毫秒) | +| `status` | String | 状态 | +| `alertLevel` | String | 告警级别 | +| `alertContent` | String | 告警内容 | +| `buildingInfo` | String | 楼宇信息 | +| `floorInfo` | String | 楼层信息 | +| `spaceInfo` | String | 空间信息 | + +## 调用示例 + +### 请求 + +``` +POST /common/queryDeviceData +Apikey: <用户提供的Apikey> +Referer: <服务端域名,例如 https://bilplartform-stg.ifmservice.jp> +``` + +```json +{ + "deviceIds": ["FFFF0001", "FFFF0002"], + "startTime": 1709870240425, + "endTime": 1709889240425 +} +``` + +### 成功响应 + +```json +{ + "code": 0, + "msg": "success", + "data": [ + { + "deviceId": "FFFF0001", + "deviceName": "温度传感器", + "rawData": "{\"temp\":25.5}", + "dataValue": "25.5", + "receiveTs": 1709870240425, + "status": "UP", + "alertLevel": null, + "alertContent": null, + "buildingInfo": "东京建物日本桥ビル", + "floorInfo": "3F", + "spaceInfo": "会議室A" + } + ] +} +``` + +### 错误响应示例 + +```json +{ + "code": 20001, + "msg": "[deviceIds] is required", + "data": null +} +``` + +## 自然语言用例映射 + +### 用例1:查询某设备最近N天的数据 + +> 用户说:**"查一下设备FFFF0001最近3天的数据"** + +``` +步骤: +1. 假设 Today's date = 2026-06-01 +2. 计算 startTime = 2026-05-30 00:00:00 JST → 毫秒时间戳 +3. 计算 endTime = 2026-06-01 23:59:59 JST → 毫秒时间戳 +4. deviceIds = ["FFFF0001"] +5. 调用接口 +``` + +### 用例2:查询多个设备特定日期的数据 + +> 用户说:**"查询FFFF0001和FT0002在2024年1月1日的数据"** + +``` +步骤: +1. 计算 startTime = 2024-01-01 00:00:00 JST → 毫秒时间戳 +2. 计算 endTime = 2024-01-01 23:59:59 JST → 毫秒时间戳 +3. deviceIds = ["FFFF0001", "FT0002"] +4. 调用接口 +``` + +### 用例3:查询设备今天的数据 + +> 用户说:**"看看FT0001今天的监测数据"** + +``` +步骤: +1. 假设 Today's date = 2026-06-01 +2. 计算 startTime = 2026-06-01 00:00:00 JST → 毫秒时间戳 +3. 计算 endTime = 当前时间 JST → 毫秒时间戳 +4. deviceIds = ["FT0001"] +5. 调用接口 +``` + +## 注意事项 + +1. `startTime` 和 `endTime` 支持毫秒和秒级时间戳(< 10000000000L 时自动按秒处理) +2. 时间跨度不能超过 **7 天**,否则接口会返回错误 +3. 跨天查询时自动查询多张 `rawData_yyyy_MM_dd` 分表并合并结果 +4. 使用 Apikey 认证,与 `/common/queryDeviceInfo` 相同的方式 +5. 所有时间计算都基于 `Asia/Tokyo` 时区 +6. Apikey 和所有请求参数均**不设置默认值**,缺失时需向用户询问补齐 +7. **Referer 头必传**:请求必须携带 `Referer` 头,否则被 `CrosXssFilter` 过滤器拦截返回 403。Referer 值需与服务端配置的 `accessControlAllowOrigin` 匹配(通常为服务域名本身,如 `https://bilplartform-stg.ifmservice.jp`) \ No newline at end of file