feat:完善tcp报文页面显示
All checks were successful
JT808 CI/CD / build-and-deploy (push) Successful in 26s

This commit is contained in:
lzh
2025-12-12 17:12:45 +08:00
parent 53558dcd6a
commit b596f0eb72
8 changed files with 67 additions and 10 deletions

View File

@@ -1,6 +1,10 @@
# Build Stage
FROM maven:3.9.9-eclipse-temurin-17 AS build
WORKDIR /app
# 使用自定义 Maven 设置(如阿里云镜像)加速构建
COPY settings.xml /usr/share/maven/conf/settings.xml
COPY pom.xml .
COPY src ./src
RUN mvn -B clean package -DskipTests

14
settings.xml Normal file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
</settings>

View File

@@ -50,7 +50,7 @@ public class DeviceController {
@PostMapping("/upload")
public CommonResult<String> receiveDeviceData(@RequestBody Map<String, Object> payload) {
// 广播日志(同时会记录到服务器日志文件)
apiLogService.broadcastLog(payload);
apiLogService.broadcastLog("API", payload);
return CommonResult.success("设备数据接收成功");
}

View File

@@ -16,12 +16,15 @@ public class Jt808NettyServer implements CommandLineRunner {
@Value("${jt808.port:20048}")
private int port;
@org.springframework.beans.factory.annotation.Autowired
private com.hua.transport.jt808.service.ApiLogService apiLogService;
private TCPServer tcpServer;
@Override
public void run(String... args) throws Exception {
log.info("Initializing JT808 TCP Server on port: {}", port);
tcpServer = new TCPServer(port);
tcpServer = new TCPServer(port, apiLogService);
tcpServer.startServer();
}

View File

@@ -20,11 +20,14 @@ import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Future;
import com.hua.transport.jt808.service.ApiLogService;
public class TCPServer {
private Logger log = LoggerFactory.getLogger(getClass());
private int port;
private ApiLogService apiLogService;
private EventLoopGroup bossGroup = null;
private EventLoopGroup workerGroup = null;
private volatile boolean isRunning = false;
@@ -32,9 +35,10 @@ public class TCPServer {
public TCPServer() {
}
public TCPServer(int port) {
public TCPServer(int port, ApiLogService apiLogService) {
this();
this.port = port;
this.apiLogService = apiLogService;
}
private void bind() throws Exception {
@@ -58,7 +62,7 @@ public class TCPServer {
Unpooled.copiedBuffer(new byte[] { 0x7e, 0x7e })));
//ch.pipeline().addLast(new PackageDataDecoder());
ch.pipeline().addLast(new TCPServerHandler());
ch.pipeline().addLast(new TCPServerHandler(apiLogService));
}
}).option(ChannelOption.SO_BACKLOG, 128) //
.childOption(ChannelOption.SO_KEEPALIVE, true);

View File

@@ -25,14 +25,20 @@ public class ApiLogService {
return emitter;
}
public void broadcastLog(Map<String, Object> payload) {
public void broadcastLog(String source, Map<String, Object> payload) {
// Log to server file
log.info("API Data Received】: {}", payload);
log.info("{} Data Received】: {}", source, payload);
// Add source to payload
// Create a new map to avoid modifying the original payload if it's used elsewhere
Map<String, Object> message = new java.util.HashMap<>(payload);
message.put("source", source);
message.put("timestamp", System.currentTimeMillis());
// Broadcast to Web UI
for (SseEmitter emitter : emitters) {
try {
emitter.send(SseEmitter.event().name("api-log").data(payload));
emitter.send(SseEmitter.event().name("log-event").data(message));
} catch (IOException e) {
emitters.remove(emitter);
}

View File

@@ -16,17 +16,23 @@ import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import com.hua.transport.jt808.service.ApiLogService;
import java.util.HashMap;
import java.util.Map;
public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
private final Logger logger = LoggerFactory.getLogger(getClass());
private final DataDecoder decoder;
private final SessionManager sessionManager;
private final ApiLogService apiLogService;
public TCPServerHandler() {
public TCPServerHandler(ApiLogService apiLogService) {
this.decoder = new DataDecoder();
this.sessionManager = SessionManager.getInstance();
this.apiLogService = apiLogService;
}
/**
@@ -44,6 +50,18 @@ public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
Integer msgId = header.getId();
logger.info("消息头部msgid={}, phone={}, flowid={}", msgId, header.getTerminalPhone(), header.getFlowId());
// Broadcast to UI
if (apiLogService != null) {
Map<String, Object> logMap = new HashMap<>();
logMap.put("msgId", String.format("0x%04x", msgId));
logMap.put("phone", header.getTerminalPhone());
logMap.put("flowId", header.getFlowId());
logMap.put("summary", "TCP Message Received");
// Add raw object if needed, or string representation
logMap.put("details", packageData.toString());
apiLogService.broadcastLog("TCP", logMap);
}
MessageHandler handler = MessageHandlerFactory.getInstance(msgId);
if(handler != null){

View File

@@ -94,6 +94,7 @@
<div v-if="logs.length === 0" class="text-muted text-center mt-5">Waiting for data...</div>
<div v-for="(log, index) in logs" :key="index" class="log-entry">
<span class="log-time">[{{ log.time }}]</span>
<span class="badge me-2" :class="log.source === 'TCP' ? 'bg-warning text-dark' : 'bg-success'">{{ log.source }}</span>
<span>{{ log.data }}</span>
</div>
</div>
@@ -140,16 +141,23 @@
setTimeout(() => this.connectSSE(), 3000);
};
this.eventSource.addEventListener('api-log', (event) => {
this.eventSource.addEventListener('log-event', (event) => {
const data = JSON.parse(event.data);
this.addLog(data);
});
},
addLog(data) {
const now = new Date().toLocaleTimeString();
const source = data.source || 'INFO';
// Remove source/timestamp from display data to avoid clutter if desired, or just show all
const displayData = { ...data };
delete displayData.source;
delete displayData.timestamp;
this.logs.unshift({
time: now,
data: typeof data === 'string' ? data : JSON.stringify(data)
source: source,
data: JSON.stringify(displayData)
});
// Keep last 50 logs
if (this.logs.length > 50) this.logs.pop();