This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
# Build Stage
|
# Build Stage
|
||||||
FROM maven:3.9.9-eclipse-temurin-17 AS build
|
FROM maven:3.9.9-eclipse-temurin-17 AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 使用自定义 Maven 设置(如阿里云镜像)加速构建
|
||||||
|
COPY settings.xml /usr/share/maven/conf/settings.xml
|
||||||
|
|
||||||
COPY pom.xml .
|
COPY pom.xml .
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
RUN mvn -B clean package -DskipTests
|
RUN mvn -B clean package -DskipTests
|
||||||
|
|||||||
14
settings.xml
Normal file
14
settings.xml
Normal 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>
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ public class DeviceController {
|
|||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public CommonResult<String> receiveDeviceData(@RequestBody Map<String, Object> payload) {
|
public CommonResult<String> receiveDeviceData(@RequestBody Map<String, Object> payload) {
|
||||||
// 广播日志(同时会记录到服务器日志文件)
|
// 广播日志(同时会记录到服务器日志文件)
|
||||||
apiLogService.broadcastLog(payload);
|
apiLogService.broadcastLog("API", payload);
|
||||||
|
|
||||||
return CommonResult.success("设备数据接收成功");
|
return CommonResult.success("设备数据接收成功");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,15 @@ public class Jt808NettyServer implements CommandLineRunner {
|
|||||||
@Value("${jt808.port:20048}")
|
@Value("${jt808.port:20048}")
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
@org.springframework.beans.factory.annotation.Autowired
|
||||||
|
private com.hua.transport.jt808.service.ApiLogService apiLogService;
|
||||||
|
|
||||||
private TCPServer tcpServer;
|
private TCPServer tcpServer;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
log.info("Initializing JT808 TCP Server on port: {}", port);
|
log.info("Initializing JT808 TCP Server on port: {}", port);
|
||||||
tcpServer = new TCPServer(port);
|
tcpServer = new TCPServer(port, apiLogService);
|
||||||
tcpServer.startServer();
|
tcpServer.startServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,14 @@ import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
|||||||
import io.netty.handler.timeout.IdleStateHandler;
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
|
|
||||||
|
import com.hua.transport.jt808.service.ApiLogService;
|
||||||
|
|
||||||
public class TCPServer {
|
public class TCPServer {
|
||||||
|
|
||||||
private Logger log = LoggerFactory.getLogger(getClass());
|
private Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private int port;
|
private int port;
|
||||||
|
private ApiLogService apiLogService;
|
||||||
private EventLoopGroup bossGroup = null;
|
private EventLoopGroup bossGroup = null;
|
||||||
private EventLoopGroup workerGroup = null;
|
private EventLoopGroup workerGroup = null;
|
||||||
private volatile boolean isRunning = false;
|
private volatile boolean isRunning = false;
|
||||||
@@ -32,9 +35,10 @@ public class TCPServer {
|
|||||||
public TCPServer() {
|
public TCPServer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TCPServer(int port) {
|
public TCPServer(int port, ApiLogService apiLogService) {
|
||||||
this();
|
this();
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
this.apiLogService = apiLogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bind() throws Exception {
|
private void bind() throws Exception {
|
||||||
@@ -58,7 +62,7 @@ public class TCPServer {
|
|||||||
Unpooled.copiedBuffer(new byte[] { 0x7e, 0x7e })));
|
Unpooled.copiedBuffer(new byte[] { 0x7e, 0x7e })));
|
||||||
//ch.pipeline().addLast(new PackageDataDecoder());
|
//ch.pipeline().addLast(new PackageDataDecoder());
|
||||||
|
|
||||||
ch.pipeline().addLast(new TCPServerHandler());
|
ch.pipeline().addLast(new TCPServerHandler(apiLogService));
|
||||||
}
|
}
|
||||||
}).option(ChannelOption.SO_BACKLOG, 128) //
|
}).option(ChannelOption.SO_BACKLOG, 128) //
|
||||||
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
|||||||
@@ -25,14 +25,20 @@ public class ApiLogService {
|
|||||||
return emitter;
|
return emitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void broadcastLog(Map<String, Object> payload) {
|
public void broadcastLog(String source, Map<String, Object> payload) {
|
||||||
// Log to server file
|
// 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
|
// Broadcast to Web UI
|
||||||
for (SseEmitter emitter : emitters) {
|
for (SseEmitter emitter : emitters) {
|
||||||
try {
|
try {
|
||||||
emitter.send(SseEmitter.event().name("api-log").data(payload));
|
emitter.send(SseEmitter.event().name("log-event").data(message));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
emitters.remove(emitter);
|
emitters.remove(emitter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,23 @@ import io.netty.handler.timeout.IdleState;
|
|||||||
import io.netty.handler.timeout.IdleStateEvent;
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
import io.netty.util.ReferenceCountUtil;
|
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)
|
public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
private final DataDecoder decoder;
|
private final DataDecoder decoder;
|
||||||
private final SessionManager sessionManager;
|
private final SessionManager sessionManager;
|
||||||
|
private final ApiLogService apiLogService;
|
||||||
|
|
||||||
|
|
||||||
public TCPServerHandler() {
|
public TCPServerHandler(ApiLogService apiLogService) {
|
||||||
this.decoder = new DataDecoder();
|
this.decoder = new DataDecoder();
|
||||||
this.sessionManager = SessionManager.getInstance();
|
this.sessionManager = SessionManager.getInstance();
|
||||||
|
this.apiLogService = apiLogService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,6 +51,18 @@ public class TCPServerHandler extends ChannelInboundHandlerAdapter { // (1)
|
|||||||
|
|
||||||
logger.info("消息头部:msgid={}, phone={}, flowid={}", msgId, header.getTerminalPhone(), header.getFlowId());
|
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);
|
MessageHandler handler = MessageHandlerFactory.getInstance(msgId);
|
||||||
if(handler != null){
|
if(handler != null){
|
||||||
handler.process(packageData);
|
handler.process(packageData);
|
||||||
|
|||||||
@@ -94,6 +94,7 @@
|
|||||||
<div v-if="logs.length === 0" class="text-muted text-center mt-5">Waiting for data...</div>
|
<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">
|
<div v-for="(log, index) in logs" :key="index" class="log-entry">
|
||||||
<span class="log-time">[{{ log.time }}]</span>
|
<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>
|
<span>{{ log.data }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -140,16 +141,23 @@
|
|||||||
setTimeout(() => this.connectSSE(), 3000);
|
setTimeout(() => this.connectSSE(), 3000);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.eventSource.addEventListener('api-log', (event) => {
|
this.eventSource.addEventListener('log-event', (event) => {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
this.addLog(data);
|
this.addLog(data);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
addLog(data) {
|
addLog(data) {
|
||||||
const now = new Date().toLocaleTimeString();
|
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({
|
this.logs.unshift({
|
||||||
time: now,
|
time: now,
|
||||||
data: typeof data === 'string' ? data : JSON.stringify(data)
|
source: source,
|
||||||
|
data: JSON.stringify(displayData)
|
||||||
});
|
});
|
||||||
// Keep last 50 logs
|
// Keep last 50 logs
|
||||||
if (this.logs.length > 50) this.logs.pop();
|
if (this.logs.length > 50) this.logs.pop();
|
||||||
|
|||||||
Reference in New Issue
Block a user