From eb5513f9b656b51eac6c079df58727999d919fc4 Mon Sep 17 00:00:00 2001 From: lzh Date: Wed, 21 Jan 2026 18:04:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(iot):=20=E4=BF=AE=E5=A4=8DJT808=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E6=B6=88=E6=81=AFidentifier=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E4=B8=8D=E5=8C=B9=E9=85=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 parseButtonEventAsEvent 使用 eventId 而非 identifier - 添加消息体长度校验,防止越界访问 - 解码失败时返回 null 而非抛异常,避免断开连接 Co-Authored-By: Claude Opus 4.5 --- .../jt808/IotJt808DeviceMessageCodec.java | 18 +++++++++++---- .../iot/gateway/codec/jt808/Jt808Decoder.java | 23 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java b/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java index 568c912..6d6f7ba 100644 --- a/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java +++ b/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/IotJt808DeviceMessageCodec.java @@ -90,11 +90,20 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { // 2. 解析为 JT808 数据包 Jt808DataPack dataPack = decoder.bytes2PackageData(unescapedBytes); - // 3. 转换为统一的 IotDeviceMessage + // 3. 检查消息体是否有效(null 表示长度不匹配错误,空数组表示合法的空消息体如心跳) + if (dataPack.getBodyBytes() == null) { + // 长度不匹配,返回 null 由上层跳过该消息 + log.warn("[decode][消息体长度不匹配,跳过该消息,消息ID=0x{}]", + Integer.toHexString(dataPack.getPackHead().getId())); + return null; + } + + // 4. 转换为统一的 IotDeviceMessage(包括空消息体的消息如心跳) return convertToIotDeviceMessage(dataPack); } catch (Exception e) { log.error("[decode][JT808 消息解码失败,数据长度: {}]", bytes.length, e); - throw new RuntimeException("JT808 消息解码失败: " + e.getMessage(), e); + // 解码失败返回 null,不断开连接 + return null; } } @@ -208,7 +217,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { * * 物模型标准格式: * { - * "eventId": "button_event", + * "identifier": "button_event", * "eventTime": 1234567890, * "params": { * "keyId": 1, @@ -225,7 +234,8 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec { Map result = new HashMap<>(); // 统一使用一个事件标识符,通过 isLongPress 参数区分短按和长按 - result.put("eventId", "button_event"); + // 注意:必须使用 "identifier" 字段,以便 IotDeviceMessageUtils.getIdentifier() 正确提取 + result.put("identifier", "button_event"); // 事件时间戳 result.put("eventTime", System.currentTimeMillis()); diff --git a/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/Jt808Decoder.java b/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/Jt808Decoder.java index 25c9ce7..fb39b91 100644 --- a/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/Jt808Decoder.java +++ b/viewsh-module-iot/viewsh-module-iot-gateway/src/main/java/com/viewsh/module/iot/gateway/codec/jt808/Jt808Decoder.java @@ -43,6 +43,29 @@ public class Jt808Decoder { msgBodyByteStartIndex = 16; } + // 验证消息体长度,防止越界 + int expectedBodyLength = msgHeader.getBodyLength(); + int actualAvailableLength = data.length - msgBodyByteStartIndex - 1; // -1 for checksum + + // 检查数据长度是否足够(至少要包含消息头和校验码) + if (data.length < msgBodyByteStartIndex + 1) { + log.warn("[bytes2PackageData][数据长度不足: 头部需要={}, 实际={}, 消息ID=0x{}]", + msgBodyByteStartIndex + 1, data.length, Integer.toHexString(msgHeader.getId())); + ret.setBodyBytes(null); // 使用 null 标记错误状态 + ret.setCheckSum(0); + return ret; + } + + if (expectedBodyLength > actualAvailableLength) { + log.warn("[bytes2PackageData][消息体长度不匹配: 头部声明={}, 实际可用={}, 数据总长度={}, 消息ID=0x{}]", + expectedBodyLength, actualAvailableLength, data.length, + Integer.toHexString(msgHeader.getId())); + // 使用 null 标记长度不匹配(区别于合法的空消息体如心跳) + ret.setBodyBytes(null); + ret.setCheckSum(data[data.length - 1]); + return ret; + } + byte[] bodyBytes = new byte[msgHeader.getBodyLength()]; System.arraycopy(data, msgBodyByteStartIndex, bodyBytes, 0, bodyBytes.length); ret.setBodyBytes(bodyBytes);