fix(iot): fix UnsupportedOperationException in JT808 codec
This commit is contained in:
@@ -49,7 +49,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
public byte[] encode(IotDeviceMessage message) {
|
||||
Assert.notNull(message, "消息不能为空");
|
||||
Assert.notBlank(message.getMethod(), "消息方法不能为空");
|
||||
|
||||
|
||||
try {
|
||||
// 从消息中提取必要信息
|
||||
String phone = extractPhoneNumber(message);
|
||||
@@ -61,12 +61,12 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
// === 标准物模型方法 ===
|
||||
case "thing.service.invoke" -> encodeServiceInvoke(message, phone, flowId); // 服务调用
|
||||
case "thing.property.set" -> encodePropertySet(message, phone, flowId); // 属性设置
|
||||
|
||||
|
||||
// === JT808 内部协议方法(向下兼容) ===
|
||||
case "jt808.platform.commonResp", "commonResp" -> encodeCommonResp(message, phone, flowId);
|
||||
case "jt808.platform.registerResp", "registerResp" -> encodeRegisterResp(message, phone, flowId);
|
||||
case "jt808.platform.textDown", "textDown" -> encodeTextDown(message, phone, flowId);
|
||||
|
||||
|
||||
default -> {
|
||||
log.warn("[encode][不支持的消息方法: {}]", method);
|
||||
yield new byte[0];
|
||||
@@ -82,14 +82,14 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
public IotDeviceMessage decode(byte[] bytes) {
|
||||
Assert.notNull(bytes, "待解码数据不能为空");
|
||||
Assert.isTrue(bytes.length >= 12, "数据包长度不足");
|
||||
|
||||
|
||||
try {
|
||||
// 1. 反转义(去除首尾标识符)
|
||||
byte[] unescapedBytes = protocolUtil.doEscape4Receive(bytes, 1, bytes.length - 1);
|
||||
|
||||
|
||||
// 2. 解析为 JT808 数据包
|
||||
Jt808DataPack dataPack = decoder.bytes2PackageData(unescapedBytes);
|
||||
|
||||
|
||||
// 3. 转换为统一的 IotDeviceMessage
|
||||
return convertToIotDeviceMessage(dataPack);
|
||||
} catch (Exception e) {
|
||||
@@ -104,26 +104,29 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
private IotDeviceMessage convertToIotDeviceMessage(Jt808DataPack dataPack) {
|
||||
Jt808DataPack.PackHead head = dataPack.getPackHead();
|
||||
int msgId = head.getId();
|
||||
|
||||
|
||||
// 生成消息ID(使用流水号作为标识)
|
||||
String messageId = head.getTerminalPhone() + "_" + head.getFlowId();
|
||||
|
||||
|
||||
// 根据消息ID确定物模型标准方法名
|
||||
String method = getStandardMethodName(msgId);
|
||||
Object params = parseMessageParams(dataPack, msgId);
|
||||
|
||||
|
||||
// 构建元数据(保留在 params 中,用于调试和追踪)
|
||||
if (params instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> paramsMap = (Map<String, Object>) params;
|
||||
// 确保 paramsMap 是可变的,防止 parseMessageParams 返回不可变 Map 导致 put 报错
|
||||
Map<String, Object> paramsMap = new HashMap<>((Map<String, Object>) params);
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("jt808MsgId", String.format("0x%04X", msgId));
|
||||
metadata.put("terminalPhone", head.getTerminalPhone());
|
||||
metadata.put("flowId", head.getFlowId());
|
||||
metadata.put("encryptionType", head.getEncryptionType());
|
||||
paramsMap.put("_metadata", metadata);
|
||||
// 更新 params 引用,确保使用的是包含 metadata 的可变 Map
|
||||
params = paramsMap;
|
||||
}
|
||||
|
||||
|
||||
// 创建 IotDeviceMessage
|
||||
IotDeviceMessage message = IotDeviceMessage.of(messageId, method, params, null, null, null);
|
||||
message.setReportTime(LocalDateTime.now());
|
||||
@@ -132,7 +135,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
|
||||
/**
|
||||
* 根据 JT808 消息ID获取物模型标准方法名
|
||||
*
|
||||
*
|
||||
* 映射关系:
|
||||
* - 0x0002 心跳 -> thing.state.update(设备状态更新)
|
||||
* - 0x0200 位置上报 -> thing.property.post(属性上报)
|
||||
@@ -146,20 +149,20 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
return switch (msgId) {
|
||||
// 设备状态类
|
||||
case 0x0002 -> IotDeviceMessageMethodEnum.STATE_UPDATE.getMethod(); // 心跳 -> 状态更新
|
||||
|
||||
|
||||
// 属性上报类
|
||||
case 0x0200 -> IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(); // 位置信息汇报 -> 属性上报
|
||||
case 0x0704 -> IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(); // 批量位置上传 -> 属性上报
|
||||
|
||||
|
||||
// 事件上报类
|
||||
case 0x0006 -> IotDeviceMessageMethodEnum.EVENT_POST.getMethod(); // 按键事件 -> 事件上报
|
||||
|
||||
|
||||
// 内部协议类(不映射到标准方法,使用 JT808 特定方法名)
|
||||
case 0x0001 -> "jt808.terminal.commonResp"; // 终端通用应答
|
||||
case 0x0100 -> "jt808.terminal.register"; // 终端注册
|
||||
case 0x0102 -> "jt808.terminal.auth"; // 终端鉴权
|
||||
case 0x0003 -> "jt808.terminal.logout"; // 终端注销
|
||||
|
||||
|
||||
// 未知消息
|
||||
default -> "jt808.unknown.0x" + Integer.toHexString(msgId);
|
||||
};
|
||||
@@ -170,18 +173,18 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
private Object parseMessageParams(Jt808DataPack dataPack, int msgId) {
|
||||
byte[] bodyBytes = dataPack.getBodyBytes();
|
||||
|
||||
|
||||
// 针对不同消息类型进行特殊解析,返回符合物模型标准的格式
|
||||
return switch (msgId) {
|
||||
// thing.property.post - 返回 properties
|
||||
case 0x0200, 0x0704 -> parseLocationInfoAsProperties(dataPack);
|
||||
|
||||
|
||||
// thing.state.update - 返回 state 信息
|
||||
case 0x0002 -> parseHeartbeatAsState();
|
||||
|
||||
|
||||
// thing.event.post - 返回 event 信息
|
||||
case 0x0006 -> parseButtonEventAsEvent(dataPack);
|
||||
|
||||
|
||||
// JT808 内部协议消息 - 保持原有格式
|
||||
case 0x0100 -> parseRegisterInfo(dataPack);
|
||||
case 0x0102 -> parseAuthInfo(bodyBytes);
|
||||
@@ -201,7 +204,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
|
||||
/**
|
||||
* 解析按键事件为事件上报格式(thing.event.post)
|
||||
*
|
||||
*
|
||||
* 物模型标准格式:
|
||||
* {
|
||||
* "eventId": "button_event",
|
||||
@@ -217,15 +220,15 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
private Map<String, Object> parseButtonEventAsEvent(Jt808DataPack dataPack) {
|
||||
Jt808ButtonEvent event = decoder.toButtonEventMsg(dataPack);
|
||||
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
|
||||
// 统一使用一个事件标识符,通过 isLongPress 参数区分短按和长按
|
||||
result.put("eventId", "button_event");
|
||||
|
||||
|
||||
// 事件时间戳
|
||||
result.put("eventTime", System.currentTimeMillis());
|
||||
|
||||
|
||||
// 事件参数(包含 isLongPress 字段用于区分短按和长按)
|
||||
Map<String, Object> eventParams = new HashMap<>();
|
||||
eventParams.put("keyId", event.getKeyId());
|
||||
@@ -234,13 +237,13 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
eventParams.put("keyNumber", event.getKeyNumber());
|
||||
eventParams.put("isLongPress", event.getIsLongPress());
|
||||
result.put("params", eventParams);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析位置信息为属性上报格式(thing.property.post)
|
||||
*
|
||||
*
|
||||
* 物模型标准格式:params 直接就是属性键值对
|
||||
* {
|
||||
* "latitude": 31.123456,
|
||||
@@ -251,10 +254,10 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
private Map<String, Object> parseLocationInfoAsProperties(Jt808DataPack dataPack) {
|
||||
Jt808LocationInfo locationInfo = decoder.toLocationInfoUploadMsg(dataPack);
|
||||
|
||||
|
||||
// 物模型属性集合(所有属性平铺在同一层)
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
|
||||
|
||||
// === 基础位置信息(核心属性) ===
|
||||
properties.put("latitude", locationInfo.getLatitude());
|
||||
properties.put("longitude", locationInfo.getLongitude());
|
||||
@@ -262,13 +265,13 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
properties.put("speed", locationInfo.getSpeed());
|
||||
properties.put("direction", locationInfo.getDirection());
|
||||
properties.put("time", locationInfo.getTime());
|
||||
|
||||
|
||||
// 状态和告警字段(转为整数便于处理)
|
||||
properties.put("warningFlag", locationInfo.getWarningFlagField());
|
||||
properties.put("status", locationInfo.getStatusField());
|
||||
|
||||
|
||||
// === 扩展信息(物模型属性) ===
|
||||
|
||||
|
||||
// 电池信息
|
||||
if (locationInfo.getBatteryInfo() != null) {
|
||||
Jt808BatteryInfo batteryInfo = locationInfo.getBatteryInfo();
|
||||
@@ -282,17 +285,17 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
properties.put("iccid", batteryInfo.getIccid());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 里程
|
||||
if (locationInfo.getMileage() != null) {
|
||||
properties.put("mileage", locationInfo.getMileage());
|
||||
}
|
||||
|
||||
|
||||
// 信号强度
|
||||
if (locationInfo.getSignalStrength() != null) {
|
||||
properties.put("signalStrength", locationInfo.getSignalStrength());
|
||||
}
|
||||
|
||||
|
||||
// 蓝牙设备列表
|
||||
if (locationInfo.getBluetoothInfos() != null && !locationInfo.getBluetoothInfos().isEmpty()) {
|
||||
List<Map<String, Object>> bluetoothList = new ArrayList<>();
|
||||
@@ -308,12 +311,12 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
}
|
||||
properties.put("bluetoothDevices", bluetoothList);
|
||||
}
|
||||
|
||||
|
||||
// 保留原始扩展字段(用于调试和高级用途)
|
||||
if (locationInfo.getExtensions() != null && !locationInfo.getExtensions().isEmpty()) {
|
||||
properties.put("_rawExtensions", locationInfo.getExtensions());
|
||||
}
|
||||
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -324,9 +327,9 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
// 解析注册消息体
|
||||
com.viewsh.module.iot.gateway.codec.jt808.entity.Jt808RegisterInfo registerInfo =
|
||||
com.viewsh.module.iot.gateway.codec.jt808.entity.Jt808RegisterInfo registerInfo =
|
||||
decoder.toRegisterMsg(dataPack);
|
||||
|
||||
|
||||
result.put("provinceId", registerInfo.getProvinceId());
|
||||
result.put("cityId", registerInfo.getCityId());
|
||||
result.put("manufacturerId", registerInfo.getManufacturerId());
|
||||
@@ -365,7 +368,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
if (bodyBytes == null || bodyBytes.length == 0) {
|
||||
return Map.of();
|
||||
}
|
||||
|
||||
|
||||
// 尝试解析为字符串,如果失败则返回十六进制
|
||||
try {
|
||||
String str = new String(bodyBytes, Jt808Constants.DEFAULT_CHARSET);
|
||||
@@ -375,7 +378,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
|
||||
return Map.of("rawData", bytesToHex(bodyBytes));
|
||||
}
|
||||
|
||||
@@ -387,7 +390,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
int replyFlowId = ((Number) params.getOrDefault("replyFlowId", 0)).intValue();
|
||||
int replyId = ((Number) params.getOrDefault("replyId", 0)).intValue();
|
||||
byte replyCode = ((Number) params.getOrDefault("replyCode", 0)).byteValue();
|
||||
|
||||
|
||||
return encoder.encodeCommonResp(phone, replyFlowId, replyId, replyCode, flowId);
|
||||
}
|
||||
|
||||
@@ -399,7 +402,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
int replyFlowId = ((Number) params.getOrDefault("replyFlowId", 0)).intValue();
|
||||
byte replyCode = ((Number) params.getOrDefault("replyCode", 0)).byteValue();
|
||||
String authToken = (String) params.get("authToken");
|
||||
|
||||
|
||||
return encoder.encodeRegisterResp(phone, replyFlowId, replyCode, authToken, flowId);
|
||||
}
|
||||
|
||||
@@ -410,15 +413,15 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
Map<String, Object> params = getParamsAsMap(message);
|
||||
byte flag = ((Number) params.getOrDefault("flag", 0)).byteValue();
|
||||
String content = (String) params.getOrDefault("content", "");
|
||||
|
||||
|
||||
return encoder.encodeTextInfoDown(phone, flag, content, flowId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码服务调用(thing.service.invoke)
|
||||
*
|
||||
*
|
||||
* 根据服务标识符映射到不同的 JT808 指令
|
||||
*
|
||||
*
|
||||
* 消息格式:
|
||||
* {
|
||||
* "identifier": "服务标识符",
|
||||
@@ -429,29 +432,29 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
private byte[] encodeServiceInvoke(IotDeviceMessage message, String phone, int flowId) {
|
||||
Map<String, Object> params = getParamsAsMap(message);
|
||||
|
||||
|
||||
// 获取服务标识符
|
||||
String serviceIdentifier = (String) params.get("identifier");
|
||||
if (StrUtil.isBlank(serviceIdentifier)) {
|
||||
log.error("[encodeServiceInvoke][服务标识符为空]");
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
||||
// 获取服务参数
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> serviceParams = (Map<String, Object>) params.getOrDefault("params", new HashMap<>());
|
||||
|
||||
|
||||
// 根据服务标识符路由到不同的 JT808 指令
|
||||
return switch (serviceIdentifier) {
|
||||
case "TTS" -> {
|
||||
// 语音播报服务 -> JT808 文本信息下发 (0x8300)
|
||||
String ttsText = (String) serviceParams.getOrDefault("tts_text", "");
|
||||
int ttsFlag = ((Number) serviceParams.getOrDefault("tts_flag", 4)).intValue(); // 默认 4-TTS 播读
|
||||
|
||||
|
||||
log.info("[encodeServiceInvoke][TTS 语音播报] phone={}, flag={}, text={}", phone, ttsFlag, ttsText);
|
||||
yield encoder.encodeTextInfoDown(phone, (byte) ttsFlag, ttsText, flowId);
|
||||
}
|
||||
|
||||
|
||||
case "locationQuery" -> {
|
||||
// 位置查询服务 -> JT808 位置信息查询 (0x8201)
|
||||
log.info("[encodeServiceInvoke][位置查询] phone={}", phone);
|
||||
@@ -459,7 +462,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
log.warn("[encodeServiceInvoke][位置查询服务暂未实现]");
|
||||
yield new byte[0];
|
||||
}
|
||||
|
||||
|
||||
default -> {
|
||||
log.warn("[encodeServiceInvoke][不支持的服务标识符: {}]", serviceIdentifier);
|
||||
yield new byte[0];
|
||||
@@ -469,9 +472,9 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
|
||||
/**
|
||||
* 编码属性设置(thing.property.set)
|
||||
*
|
||||
*
|
||||
* 属性设置映射到 JT808 的参数设置指令 (0x8103)
|
||||
*
|
||||
*
|
||||
* 消息格式:
|
||||
* {
|
||||
* "properties": {
|
||||
@@ -482,23 +485,23 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
private byte[] encodePropertySet(IotDeviceMessage message, String phone, int flowId) {
|
||||
Map<String, Object> params = getParamsAsMap(message);
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> properties = (Map<String, Object>) params.get("properties");
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
log.error("[encodePropertySet][属性列表为空]");
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
||||
// 将物模型属性映射到 JT808 参数
|
||||
Map<Integer, Object> jt808Params = mapPropertiesToJt808Params(properties);
|
||||
if (jt808Params.isEmpty()) {
|
||||
log.warn("[encodePropertySet][没有可映射的 JT808 参数]");
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
|
||||
log.info("[encodePropertySet][属性设置] phone={}, params={}", phone, jt808Params);
|
||||
|
||||
|
||||
// TODO: 实现 encoder.encodeParamSettings(phone, jt808Params, flowId);
|
||||
log.warn("[encodePropertySet][参数设置指令暂未实现]");
|
||||
return new byte[0];
|
||||
@@ -506,19 +509,19 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
|
||||
/**
|
||||
* 将物模型属性映射到 JT808 参数
|
||||
*
|
||||
*
|
||||
* 映射关系参考 JT808 协议标准:
|
||||
* - 0x0029: 心跳发送间隔
|
||||
* - 0x0027: 位置汇报间隔
|
||||
* - 0x0028: 休眠时汇报间隔
|
||||
* - 等等...
|
||||
*
|
||||
*
|
||||
* @param properties 物模型属性
|
||||
* @return JT808 参数映射(参数ID -> 参数值)
|
||||
*/
|
||||
private Map<Integer, Object> mapPropertiesToJt808Params(Map<String, Object> properties) {
|
||||
Map<Integer, Object> jt808Params = new HashMap<>();
|
||||
|
||||
|
||||
properties.forEach((identifier, value) -> {
|
||||
Integer paramId = switch (identifier) {
|
||||
case "heartbeatInterval" -> 0x0029; // 心跳发送间隔(单位:秒)
|
||||
@@ -531,22 +534,22 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
// 更多映射关系可根据实际需求添加
|
||||
default -> null;
|
||||
};
|
||||
|
||||
|
||||
if (paramId != null) {
|
||||
jt808Params.put(paramId, value);
|
||||
log.debug("[mapPropertiesToJt808Params][属性映射] {} -> 0x{} = {}",
|
||||
log.debug("[mapPropertiesToJt808Params][属性映射] {} -> 0x{} = {}",
|
||||
identifier, Integer.toHexString(paramId), value);
|
||||
} else {
|
||||
log.warn("[mapPropertiesToJt808Params][未知的属性标识符: {}]", identifier);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return jt808Params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取终端手机号
|
||||
*
|
||||
*
|
||||
* 优先级:
|
||||
* 1. 从 params._deviceName 中获取(下发场景,IotTcpDownstreamHandler 自动注入)
|
||||
* 2. 从 params._metadata.terminalPhone 中获取(上行消息回复场景)
|
||||
@@ -557,9 +560,9 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
log.error("[extractPhoneNumber][params 不是 Map 类型,消息: {}]", message);
|
||||
throw new IllegalArgumentException("消息参数格式错误,params 必须是 Map 类型");
|
||||
}
|
||||
|
||||
|
||||
Map<?, ?> params = (Map<?, ?>) message.getParams();
|
||||
|
||||
|
||||
// 1. 优先从 _deviceName 获取(下发场景,由 IotTcpDownstreamHandler 注入)
|
||||
Object deviceName = params.get("_deviceName");
|
||||
if (deviceName != null && StrUtil.isNotBlank(deviceName.toString())) {
|
||||
@@ -571,7 +574,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
log.warn("[extractPhoneNumber][_deviceName 不是纯数字: {}]", deviceNameStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2. 从 metadata 中获取(上行消息回复场景)
|
||||
if (params.get("_metadata") instanceof Map) {
|
||||
Map<?, ?> metadata = (Map<?, ?>) params.get("_metadata");
|
||||
@@ -580,7 +583,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
return terminalPhone.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 3. 从 phone 字段获取(向下兼容,不推荐)
|
||||
Object phone = params.get("phone");
|
||||
if (phone != null && StrUtil.isNotBlank(phone.toString())) {
|
||||
@@ -589,7 +592,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
return phoneStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4. 如果都获取不到,抛出异常
|
||||
log.error("[extractPhoneNumber][无法提取终端手机号,params: {}]", params);
|
||||
throw new IllegalArgumentException(
|
||||
@@ -598,19 +601,19 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
|
||||
/**
|
||||
* 提取流水号
|
||||
*
|
||||
*
|
||||
* 对于下发消息,如果没有指定流水号,则生成一个随机流水号
|
||||
*/
|
||||
private int extractFlowId(IotDeviceMessage message) {
|
||||
if (message.getParams() instanceof Map) {
|
||||
Map<?, ?> params = (Map<?, ?>) message.getParams();
|
||||
|
||||
|
||||
// 尝试获取显式指定的流水号
|
||||
Object flowId = params.get("flowId");
|
||||
if (flowId instanceof Number) {
|
||||
return ((Number) flowId).intValue();
|
||||
}
|
||||
|
||||
|
||||
// 尝试从 metadata 中获取(上行消息的流水号)
|
||||
if (params.get("_metadata") instanceof Map) {
|
||||
Map<?, ?> metadata = (Map<?, ?>) params.get("_metadata");
|
||||
@@ -620,7 +623,7 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 生成随机流水号(1-65535)
|
||||
return (int) (System.currentTimeMillis() % 65535) + 1;
|
||||
}
|
||||
@@ -663,8 +666,8 @@ public class IotJt808DeviceMessageCodec implements IotDeviceMessageCodec {
|
||||
*/
|
||||
public static boolean isJt808Format(byte[] data) {
|
||||
// 检查起止标识符 0x7e
|
||||
return data != null && data.length >= 12
|
||||
&& data[0] == (byte) Jt808Constants.PKG_DELIMITER
|
||||
return data != null && data.length >= 12
|
||||
&& data[0] == (byte) Jt808Constants.PKG_DELIMITER
|
||||
&& data[data.length - 1] == (byte) Jt808Constants.PKG_DELIMITER;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user