fix: 数据补报解析
All checks were successful
iot-test-platform CI/CD / build-and-deploy (push) Successful in 24s

This commit is contained in:
lzh
2025-12-15 15:34:01 +08:00
parent 3456fc65b9
commit 1b2c50683a
8 changed files with 235 additions and 25 deletions

View File

@@ -32,6 +32,8 @@ public class Consts {
public static final Integer MSGID_PARAM_QUERY_RESP = 0x0104;
/** 按键事件上报 **/
public static final Integer MSGID_BUTTON_EVENT = 0x0006;
/** 定位数据批量上传 **/
public static final Integer MSGID_LOCATION_BATCH_UPLOAD = 0x0704;
/** 平台通用应答 **/

View File

@@ -0,0 +1,52 @@
package com.iot.transport.jt808.entity.request;
import com.iot.transport.jt808.entity.DataPack;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.ArrayList;
import java.util.List;
/**
* 定位数据批量上传消息 (0x0704)
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BatchLocationPack extends DataPack {
/**
* 数据项个数
*/
private int count;
/**
* 位置数据类型
* 0正常位置批量汇报
* 1盲区补报
*/
private int type;
/**
* 位置数据列表
* 每个元素都是一个完整的 LocationPack (解析内容相同)
*/
private List<LocationPack> items;
public BatchLocationPack() {
this.items = new ArrayList<>();
}
public BatchLocationPack(DataPack packageData) {
this();
this.channel = packageData.getChannel();
this.checkSum = packageData.getCheckSum();
this.bodyBytes = packageData.getBodyBytes();
this.packHead = packageData.getPackHead();
}
public void addItem(LocationPack item) {
this.items.add(item);
}
}

View File

@@ -9,6 +9,7 @@ import com.iot.transport.jt808.entity.DataPack.PackHead;
import com.iot.transport.jt808.entity.request.LocationPack;
import com.iot.transport.jt808.entity.request.RegisterPack;
import com.iot.transport.jt808.entity.request.ButtonEventPack;
import com.iot.transport.jt808.entity.request.BatchLocationPack;
import com.iot.transport.jt808.entity.request.RegisterPack.TerminalRegInfo;
import com.iot.transport.jt808.util.BCDUtil;
import com.iot.transport.jt808.util.BitUtil;
@@ -226,10 +227,48 @@ public class DataDecoder {
ret.setKeyState(this.parseIntFromBytes(data, 1, 1));
}
return ret;
}
public BatchLocationPack toBatchLocationPack(DataPack packageData) {
BatchLocationPack ret = new BatchLocationPack(packageData);
byte[] data = ret.getBodyBytes();
// 1. 数据项个数 (WORD)
int count = this.parseIntFromBytes(data, 0, 2);
ret.setCount(count);
// 2. 位置数据类型 (BYTE)
ret.setType(this.parseIntFromBytes(data, 2, 1));
// 3. 循环解析位置数据项
int index = 3;
for (int i = 0; i < count; i++) {
if (index + 2 > data.length) break;
// 每一项的数据长度 (WORD)
int itemLen = this.parseIntFromBytes(data, index, 2);
index += 2;
if (index + itemLen > data.length) break;
// 提取该项的字节数组
byte[] itemBytes = new byte[itemLen];
System.arraycopy(data, index, itemBytes, 0, itemLen);
// 使用 toLocationInfoUploadMsg 复用解析逻辑
// 构造一个临时的 DataPack
DataPack itemPack = new DataPack();
itemPack.setBodyBytes(itemBytes);
LocationPack loc = this.toLocationInfoUploadMsg(itemPack);
ret.addItem(loc);
index += itemLen;
}
return ret;
}
public LocationPack toLocationInfoUploadMsg(DataPack packageData) {
LocationPack ret = new LocationPack(packageData);
final byte[] data = ret.getBodyBytes();

View File

@@ -9,6 +9,7 @@ import com.iot.transport.jt808.service.handler.terminal.LocationUploadHandler;
import com.iot.transport.jt808.service.handler.terminal.LoginOutHandler;
import com.iot.transport.jt808.service.handler.terminal.RegisterHandler;
import com.iot.transport.jt808.service.handler.terminal.ButtonEventHandler;
import com.iot.transport.jt808.service.handler.terminal.BatchLocationHandler;
public class MessageHandlerFactory {
@@ -24,6 +25,7 @@ public class MessageHandlerFactory {
handlerMap.put(Consts.MSGID_AUTHENTICATION, AuthenticationHandler.class); // 终端鉴权
handlerMap.put(Consts.MSGID_LOCATION_UPLOAD, LocationUploadHandler.class); // 位置信息汇报
handlerMap.put(Consts.MSGID_BUTTON_EVENT, ButtonEventHandler.class); // 按键事件上报
handlerMap.put(Consts.MSGID_LOCATION_BATCH_UPLOAD, BatchLocationHandler.class); // 批量定位上传
}

View File

@@ -25,6 +25,7 @@ import com.iot.transport.jt808.entity.request.BatteryVersionInfo;
import com.iot.transport.jt808.entity.request.BluetoothInfo;
import com.iot.transport.jt808.entity.request.LocationPack;
import com.iot.transport.jt808.entity.request.ButtonEventPack;
import com.iot.transport.jt808.entity.request.BatchLocationPack;
import java.util.List;
public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
@@ -135,6 +136,32 @@ public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
} catch (Exception e) {
logMap.put("details", packageData.toString() + " (Parse Error: " + e.getMessage() + ")");
}
} else if (msgId == Consts.MSGID_LOCATION_BATCH_UPLOAD || msgId == 0x0704) {
try {
BatchLocationPack batchPack = this.decoder.toBatchLocationPack(packageData);
logMap.put("details", "Batch Upload: " + batchPack.getCount() + " items");
logMap.put("type", "badge");
logMap.put("id", header.getTerminalPhone());
// Use the latest location item to update the UI
if (batchPack.getItems() != null && !batchPack.getItems().isEmpty()) {
LocationPack lastLoc = batchPack.getItems().get(batchPack.getItems().size() - 1);
// Location
Map<String, Object> locMap = new HashMap<>();
locMap.put("lat", lastLoc.getLatitude());
locMap.put("lon", lastLoc.getLongitude());
logMap.put("location", locMap);
// Battery
BatteryVersionInfo batInfo = lastLoc.getBatteryVersionInfo();
if (batInfo != null) {
logMap.put("battery", batInfo.getBatteryLevel());
}
}
} catch (Exception e) {
logMap.put("details", packageData.toString() + " (Parse Error: " + e.getMessage() + ")");
}
} else {
logMap.put("details", packageData.toString());
}

View File

@@ -0,0 +1,51 @@
package com.iot.transport.jt808.service.handler.terminal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.iot.transport.jt808.entity.DataPack;
import com.iot.transport.jt808.entity.DataPack.PackHead;
import com.iot.transport.jt808.entity.request.BatchLocationPack;
import com.iot.transport.jt808.entity.request.LocationPack;
import com.iot.transport.jt808.entity.response.ServerBodyPack;
import com.iot.transport.jt808.service.handler.MessageHandler;
/**
* 定位数据批量上传 (0x0704) ==> 平台通用应答
*/
public class BatchLocationHandler extends MessageHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
public BatchLocationHandler() {
super();
}
@Override
public void process(DataPack packageData) {
PackHead header = packageData.getPackHead();
logger.info("[批量定位],msgid={}, phone={},flowid={}", header.getId(), header.getTerminalPhone(), header.getFlowId());
try {
BatchLocationPack msg = this.decoder.toBatchLocationPack(packageData);
logger.info("批量定位数据: Count={}, Type={}, Items={}", msg.getCount(), msg.getType(), msg.getItems().size());
// 可以在这里处理每个 LocationPack例如入库或推送到前端
for (LocationPack item : msg.getItems()) {
// TODO: Process each location item
logger.debug(" -> Item: Lat={}, Lon={}, Time={}", item.getLatitude(), item.getLongitude(), item.getTime());
}
// 回复通用应答
int flowId = super.getFlowId(msg.getChannel());
ServerBodyPack respMsgBody = new ServerBodyPack(header.getFlowId(), header.getId(), ServerBodyPack.success);
byte[] bs = this.msgEncoder.encode4ServerCommonRespMsg(msg, respMsgBody, flowId);
super.send2Client(msg.getChannel(), bs);
} catch (Exception e) {
logger.error("[批量定位]错误, err={}", e.getMessage());
}
}
}

View File

@@ -113,7 +113,7 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark flex-shrink-0">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<i class="fas fa-network-wired me-2"></i>IoT 数据监控平台
<i class="fas fa-network-wired me-2"></i>IoT 数据测试平台
</a>
<div class="d-flex align-items-center">
<span class="text-light me-3">