From 0717201c585940f23f12d6a6e4f09d97185c54ef Mon Sep 17 00:00:00 2001 From: shan <1653261938@qq.com> Date: Wed, 24 Dec 2025 18:21:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=E5=8E=BB=E6=8E=89redis=E4=B8=80?= =?UTF-8?q?=E7=9B=B4=E7=BC=93=E5=AD=98=E6=97=A0=E7=94=A8=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=B3=A8=E8=A7=A32.=E5=AE=9E=E7=8E=B0adapter=E4=B8=8E=E4=B8=BB?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=88=9D=E6=AD=A5=E6=8E=A5=E6=94=B6=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=8A=A5=E6=96=873=E4=B8=BB=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E6=8E=A5=E6=94=B6websocket=E6=8A=A5=E6=96=87=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E5=88=86=E7=89=87=E6=8E=A5=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adxp-adapter/pom.xml | 11 + .../com/qaup/adxp/adapter/dto/AllXml.java | 398 ++++++++++++++++++ .../qaup/adxp/adapter/dto/FlightMessage.java | 9 + .../adxp/adapter/service/AdxpSdkService.java | 266 +++++++++++- .../websocket/AdxpWebSocketHandler.java | 13 + doc/requirement/official_api.md | 3 +- .../common/model/FlightNotification.java | 6 +- .../config/ADXPWebSocketConfig.java | 21 +- .../datacollector/dao/DataCollectorDao.java | 75 ++-- .../service/DataCollectorService.java | 49 ++- .../AdxpFlightServiceWebSocketClient.java | 238 ++++++++++- .../websocket/AdxpWebSocketStarter.java | 20 + .../service/DataProcessingService.java | 34 ++ .../impl/LocationRuleQueryServiceImpl.java | 2 +- 14 files changed, 1071 insertions(+), 74 deletions(-) create mode 100644 adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/AllXml.java create mode 100644 qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpWebSocketStarter.java diff --git a/adxp-adapter/pom.xml b/adxp-adapter/pom.xml index 15035e7d..94c3590b 100644 --- a/adxp-adapter/pom.xml +++ b/adxp-adapter/pom.xml @@ -108,6 +108,17 @@ dom4j 1.6.1 + + org.junit.jupiter + junit-jupiter + test + + + org.springframework.boot + spring-boot-starter-test + test + + diff --git a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/AllXml.java b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/AllXml.java new file mode 100644 index 00000000..bd506c58 --- /dev/null +++ b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/AllXml.java @@ -0,0 +1,398 @@ +package com.qaup.adxp.adapter.dto; + +public class AllXml { + // 将原始的 XML 字符串存储为常量 + public static final String XML_ARR = "\n" + + "\n" + + " \n" + + " ADXP_NAOMS_O_DYN_ARR\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " \n" + + " be58e345-7bcf-4cbb-915f-28c16f0e09a4\n" + + " 20171208140658867\n" + + " 20171208140658867\n" + + " \n" + + " \n" + + " \n" + + " 4155920\n" + + " CZ3158-A-20170906230500\n" + + " TAO\n" + + " ARR\n" + + " 20170906230500\n" + + " \n" + + " \n" + + ""; + + + // + public static final String XML_CRAFTSEAT = "\n" + + "\n" + + " \n" + + " ADXP_NAOMS_O_DYN_CRAFTSEAT\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " \n" + + " 9a6b67e0-f061-4d0d-9a6a-f31328283d54\n" + + " 20171208140658867\n" + + " 20171208140658867\n" + + " \n" + + " \n" + + " \n" + + " 4155920\n" + + " CZ3158-D-20170906230500\n" + + " \n" + + " \n" + + " 32\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + // 存储 XML 字符串作为常量 + public static final String XML_DFIE = "\n" + + "\n" + + " \n" + + " ADXP_NAOMS_O_DYN_DFIE\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " \n" + + " 97b79684-f755-41a1-82ab-f7e34352c6af\n" + + " 20171208140658867\n" + + " 20171208140658867\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 4155920\n" + + " CZ3158-A-20170906230500\n" + + " 4155935\n" + + " CZ3158-D-20170906230500\n" + + " 20170906\n" + + " 20170906\n" + + " 20170906230500\n" + + " SC\n" + + " 4753\n" + + " D\n" + + " A\n" + + " CRJ200\n" + + " B738L\n" + + " W/Z\n" + + " 1\n" + + " T1\n" + + " 1\n" + + " 一级特勤保障\n" + + " 1\n" + + " \n" + + " \n" + + " TAO\n" + + " ALT\n" + + " 20170906232200\n" + + " 20170906232500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " HHA\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 20170906232200\n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " SC\n" + + " 1234\n" + + " SC1234\n" + + " \n" + + " \n" + + " MU\n" + + " 2345\n" + + " MU2345\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " SC\n" + + " 1234\n" + + " SC1234\n" + + " D\n" + + " TAO\n" + + " HGH\n" + + " SZX\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + public static final String XML_DFDL ="\n" + + "\n" + + "\n" + + " ADXP_NAOMS_O_DYN_DFDL\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " ADXP\n" + + " FIDS\n" + + " \n" + + " 20171208140658867\n" + + " 20171208140658867\n" + + "\n" + + "\n" + + "5-3\n" + + " \n" + + " \n" + + " 4155920\n" + + " CZ3158-A-20170906230500\n" + + " 4155935\n" + + " CZ3158-D-20170906230500\n" + + " 20170906\n" + + " 20170906\n" + + " 20170906230500\n" + + " SC\n" + + " 4753\n" + + " D\n" + + " A\n" + + " CRJ200\n" + + " B738L\n" + + " W/Z\n" + + " 1\n" + + " T1\n" + + " 1\n" + + " 一级特勤保障\n" + + " 1\n" + + " BOR\n" + + " BOR\n" + + " \n" + + " \n" + + " TAO\n" + + " ALT\n" + + " 20170906232200\n" + + " 20170906232500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " HHA\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 20170906232200\n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " SC\n" + + " 1234\n" + + " SC1234\n" + + " \n" + + " \n" + + " MU\n" + + " 2345\n" + + " MU2345\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " SC\n" + + " 1234\n" + + " SC1234\n" + + " D\n" + + " TAO\n" + + " HGH\n" + + " SZX\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " TAO\n" + + " D\n" + + " CAN\n" + + " 取消\n" + + " 1001\n" + + " 20170906234200\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " D\n" + + " 20170920173100\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920175500\n" + + " 20170920175800\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " E35\n" + + " D\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " CZ\n" + + " 0701\n" + + " N\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 32\n" + + " D\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 32\n" + + " D\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 32\n" + + "12\n" + + " D\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 32\n" + + " 20170920173500\n" + + " 20170920171500\n" + + " 20170920173500\n" + + " 20170920173500\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n" + + ""; + + + public static final String XML_RUNWAY = "\n" + + "\n" + + " \n" + + " " + + "\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " \n" + + " \n" + + " 20200331103923314\n" + + " 20200331103923314\n" + + " \n" + + " \n" + + " \n" + + " QDCDM\n" + + " SC8775-D-20200331132500\n" + + " 35L\n" + + " \n" + + " \n" + + " \n" + + ""; + + public static final String XML_AXOT = "\n" + + "\n" + + " \n" + + " ADXP_NAOMS_O_CDM_AXOT\n" + + " 1.0\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " \n" + + " \n" + + " 20200331103923314\n" + + " 20200331103923314\n" + + " \n" + + " \n" + + " \n" + + " HCDM\n" + + " SC8775-D-20200331132500\n" + + " 202003311401\n" + + " \n" + + " \n" + + ""; + + public static final String XML_TISFLIGHT = "\n" + + "\n" + + " \n" + + " ADXP_NAOMS_O_DYN_TISFLIGHT\n" + + " 1.0\n" + + " ADXP\n" + + " naomsdevc\n" + + " \n" + + " 5b2fc9a7-c40b-4d53-8267-9e9ff36cb7a8\n" + + " 20251110133327781\n" + + " 20251110133327781\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 41317B75FC8311BCE0633D411CAC4CEB\n" + + " CDG4969\n" + + " CDG\n" + + " ZSQD\n" + + " ZLXY\n" + + " 20251104123500\n" + + " 20251104145000\n" + + " \n" + + " \n" + + " 132\n" + + " 道口22\n" + + " 前3后3;\n" + + " WFG\n" + + " \n" + + " \n" + + " DEP\n" + + " APE\n" + + " TXI\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; +} diff --git a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/FlightMessage.java b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/FlightMessage.java index 4c676342..43f914aa 100644 --- a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/FlightMessage.java +++ b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/dto/FlightMessage.java @@ -37,4 +37,13 @@ public class FlightMessage { public void setContent(String content) { this.content = content; } + + @Override + public String toString() { + return "FlightMessage{" + + "serviceCode='" + serviceCode + '\'' + + ", actionCode='" + actionCode + '\'' + + ", content='" + content + '\'' + + '}'; + } } diff --git a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/service/AdxpSdkService.java b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/service/AdxpSdkService.java index 5906c54c..517ed578 100644 --- a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/service/AdxpSdkService.java +++ b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/service/AdxpSdkService.java @@ -15,13 +15,32 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.StringWriter; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; + +import org.w3c.dom.*; +import org.xml.sax.SAXException; + +import javax.xml.parsers.*; +import java.io.*; + @Service public class AdxpSdkService { @@ -223,7 +242,6 @@ public class AdxpSdkService { try { MessageResult result = adxpClient.receiveMessage(); - // 使用统一的错误码处理方法 if (handleMessageResultError(result)) { return Collections.emptyList(); @@ -235,17 +253,24 @@ public class AdxpSdkService { List messages = new ArrayList<>(); MessageList messageList = result.getMessageList(); - + + // 处理XML字符串 + List messageStringList = result.getMessageStringList(); + + if (messageList != null && messageList.getMsg() != null) { - for (MsgType msg : messageList.getMsg()) { + for (int i = 0; i < messageList.getMsg().size(); i++) { + MsgType msg = messageList.getMsg().get(i); // 获取 MsgType + String messageString = messageStringList.get(i); // 获取对应的字符串 HeadType head = msg.getHead(); Object body = msg.getBody(); if (head != null && body != null) { + log.info("本条消息的接收到消息头{},消息体{}", head.getSvcServiceCode(), messageString); FlightMessage flightMessage = new FlightMessage( head.getSvcServiceCode(), null, // actionCode 在 body 中 - body.toString() + messageString ); messages.add(flightMessage); } @@ -270,8 +295,46 @@ public class AdxpSdkService { /** * 处理接收到的消息并广播到WebSocket客户端 */ - private void processMessages(List messages) { + private void processMessages(List messages) throws ParserConfigurationException, IOException, SAXException { if (messages != null && !messages.isEmpty()) { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + for (FlightMessage message : messages){ + String txt = message.getContent(); + log.info("接收到的XML字符串:{}", txt); + // 解析 XML 字符串 + DocumentBuilder builder = factory.newDocumentBuilder(); + InputStream is = new ByteArrayInputStream(txt.getBytes("UTF-8")); + Document document = builder.parse(is); + + log.info("事件的类型是{}",message.getServiceCode()); + switch (message.getServiceCode()){ + case "ADXP_NAOMS_O_DYN_DFDL": + handleDFDL(document); + break; + case "ADXP_NAOMS_O_DYN_CRAFTSEAT": + handleCRAFTSEAT(document); + break; + case "ADXP_NAOMS_O_DYN_ARR": + handleARR(document); + break; + case "ADXP_NAOMS_O_DYN_DFIE": + handleDFIE(document); + break; + case "ADXP_NAOMS_O_CDM_AXOT": + handleAXOT(document); + break; + case "ADXP_NAOMS_O_CDM_RUNWAY": + handleRUNWAY(document); + break; + case "ADXP_NAOMS_O_DYN_TISFLIGHT": + handleTISFLIGHT(document); + break; + default: + System.out.println("未定义的消息"); + break; + } + } + try { log.info("接收到 {} 条消息,准备广播", messages.size()); // 将消息广播到WebSocket客户端 @@ -371,4 +434,197 @@ public class AdxpSdkService { return health; } + + /** + *向数据中台发送 动态航班请求事件RQDF + */ + public MessageResult sendMessage(List message) { + if (!connected) { + log.error("ADXP数据中台未连接,无法发送消息"); + return null; + } + String xml = "\n" + + "\n" + + "\n" + + " ADXP_NAOMS_O_DYN_RQDF\n" + + " 1.0\n" + + " ADXP\n" + + " FIDS\n" + + " ADXP\n" + + " NAOMS\n" + + " \n" + + " 2017120814065886\n" + + " 20171208140658867\n" + + "\n" + + "\n" + + " \n" + + " 20171209\n" + + " \n" + + "\n" + + ""; + List xmls = new ArrayList<>(); + xmls.add( xml); + adxpClient.sendMessage(xmls); + return null; + } + + /** + * 处理 动态航班响应事件DFDL 消息 + * @param document + */ + private static void handleDFDL(Document document) { + // 获取 元素下的 + NodeList dynFlightNodes = document.getElementsByTagName("DynFlight"); + if (dynFlightNodes.getLength() > 0) { + Element dynFlight = (Element) dynFlightNodes.item(0); + + // 提取所需的值 + String flightId = getElementValue(dynFlight, "FlightId"); + String inOut = getElementValue(dynFlight, "InOut"); + String runwayNum = getElementValue(dynFlight, "RunwayNum"); + + // 输出提取的值 + System.out.println("FlightId: " + flightId); + System.out.println("InOut: " + inOut); + System.out.println("RunwayNum: " + runwayNum); + + // 获取 CraftseatList 并提取 Code + NodeList craftseatListNodes = dynFlight.getElementsByTagName("CraftseatList"); + if (craftseatListNodes.getLength() > 0) { + Element craftseatList = (Element) craftseatListNodes.item(0); + NodeList craftseatNodes = craftseatList.getElementsByTagName("Craftseat"); + + for (int i = 0; i < craftseatNodes.getLength(); i++) { + Element craftseat = (Element) craftseatNodes.item(i); + + // 提取 Code + String code = getElementValue(craftseat, "Code"); + + // 输出提取的值 + System.out.println("Craftseat Code: " + code); + } + } + } + } + + /** + * 处理 运行跑道响应事件RUNWAY 消息 + * @param document + */ + private static void handleRUNWAY(Document document) { + // 获取 元素 + NodeList flightList = document.getElementsByTagName("Flight"); + if (flightList.getLength() > 0) { + Element flightElement = (Element) flightList.item(0); + + // 提取 BizKey + String bizKey = getElementValue(flightElement, "BizKey"); + System.out.println("BizKey: " + bizKey); + + // 提取 RUNWAYDEP + String runwayDep = getElementValue(flightElement, "RUNWAYDEP"); + System.out.println("RUNWAYDEP: " + runwayDep); + + // 提取 RUNWAYARR + String runwayArr = getElementValue(flightElement, "RUNWAYARR"); + System.out.println("RUNWAYARR: " + runwayArr); + } + } + private static void handleCRAFTSEAT(Document document) { + // 获取 元素 + NodeList dynFlightList = document.getElementsByTagName("DynFlight"); + if (dynFlightList.getLength() > 0) { + Element dynFlightElement = (Element) dynFlightList.item(0); + + // 提取 FlightId + String flightId = getElementValue(dynFlightElement, "FlightId"); + System.out.println("FlightId: " + flightId); + + // 获取 CraftseatList 元素 + NodeList craftseatList = dynFlightElement.getElementsByTagName("Craftseat"); + if (craftseatList.getLength() > 0) { + Element craftseatElement = (Element) craftseatList.item(0); + + // 提取 Code + String code = getElementValue(craftseatElement, "Code"); + System.out.println("Code: " + code); + } + } + } + private static void handleARR(Document document) { + // 获取 元素 + NodeList dynFlightNodes = document.getElementsByTagName("DynFlight"); + if (dynFlightNodes.getLength() > 0) { + Element dynFlight = (Element) dynFlightNodes.item(0); + + // 提取所需的值 + String flightId = getElementValue(dynFlight, "FlightId"); + String bizKey = getElementValue(dynFlight, "BizKey"); + System.out.println("FlightId: " + flightId); + System.out.println("BizKey: " + bizKey); + } + } + private static void handleAXOT(Document document) { + // 获取 元素 + NodeList bodyNodes = document.getElementsByTagName("Body"); + if (bodyNodes.getLength() > 0) { + Element body = (Element) bodyNodes.item(0); + + // 获取 元素 + NodeList flightNodes = body.getElementsByTagName("Flight"); + if (flightNodes.getLength() > 0) { + Element flight = (Element) flightNodes.item(0); + + // 提取 BizKey 元素的值 + String bizKey = getElementValue(flight, "BizKey"); + System.out.println("BizKey: " + bizKey); + } + } + } + private static void handleDFIE(Document document) { + // 获取 元素 + NodeList dynFlightNodes = document.getElementsByTagName("DynFlight"); + if (dynFlightNodes.getLength() > 0) { + Element dynFlight = (Element) dynFlightNodes.item(0); + // 提取所需的值 + String flightId = getElementValue(dynFlight, "FlightId"); + String inOut = getElementValue(dynFlight, "InOut"); + String runwayNum = getElementValue(dynFlight, "RunwayNum"); + String bizKey = getElementValue(dynFlight, "BizKey"); + + System.out.println("FlightId: " + flightId); + System.out.println("InOut: " + inOut); + System.out.println("RunwayNum: " + runwayNum); + System.out.println("BizKey: " + bizKey); + } + } + + private static void handleTISFLIGHT(Document document) { + // 获取 元素 + NodeList tisFlightNodes = document.getElementsByTagName("TisFlight"); + if (tisFlightNodes.getLength() > 0) { + Element tisFlight = (Element) tisFlightNodes.item(0); + + // 提取所需的值 + String fuId = getElementValue(tisFlight, "FuId"); + String state = getElementValue(tisFlight, "State"); + String contactCross = getElementValue(tisFlight, "ContactCross"); + + // 打印提取的内容 + System.out.println("FuId: " + fuId); + System.out.println("State: " + state); + System.out.println("ContactCross: " + contactCross); + } + } + + + // 获取元素的值 + private static String getElementValue(Element parentElement, String tagName) { + NodeList nodeList = parentElement.getElementsByTagName(tagName); + if (nodeList.getLength() > 0) { + return nodeList.item(0).getTextContent(); + } + return null; + } + } diff --git a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/websocket/AdxpWebSocketHandler.java b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/websocket/AdxpWebSocketHandler.java index dc02107d..25306539 100644 --- a/adxp-adapter/src/main/java/com/qaup/adxp/adapter/websocket/AdxpWebSocketHandler.java +++ b/adxp-adapter/src/main/java/com/qaup/adxp/adapter/websocket/AdxpWebSocketHandler.java @@ -2,6 +2,7 @@ package com.qaup.adxp.adapter.websocket; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.qaup.adxp.adapter.dto.AllXml; import com.qaup.adxp.adapter.dto.FlightMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +42,18 @@ public class AdxpWebSocketHandler extends TextWebSocketHandler { // 可以处理一些控制命令,比如心跳 if ("ping".equals(message.getPayload())) { session.sendMessage(new TextMessage("pong")); + List messages = new CopyOnWriteArrayList<>(); + FlightMessage mgARR = new FlightMessage("ADXP_NAOMS_O_DYN_ARR", "pong", AllXml.XML_ARR); + messages.add(mgARR); + FlightMessage mgDFIE = new FlightMessage("ADXP_NAOMS_O_DYN_DFIE", "pong", AllXml.XML_DFIE); + messages.add(mgDFIE); + FlightMessage mgRUNWAY = new FlightMessage("ADXP_NAOMS_O_CDM_RUNWAY", "pong", AllXml.XML_RUNWAY); + messages.add(mgRUNWAY); + FlightMessage mgCRAFTSEAT = new FlightMessage("ADXP_NAOMS_O_DYN_CRAFTSEAT", "pong", AllXml.XML_CRAFTSEAT); + messages.add(mgCRAFTSEAT); + FlightMessage mgTISFLIGHT = new FlightMessage("ADXP_NAOMS_O_DYN_TISFLIGHT", "pong", AllXml.XML_TISFLIGHT); + messages.add(mgTISFLIGHT); + broadcastMessages(messages); log.debug("发送心跳响应到客户端: sessionId={}", session.getId()); } } diff --git a/doc/requirement/official_api.md b/doc/requirement/official_api.md index 08a40d51..122cb857 100644 --- a/doc/requirement/official_api.md +++ b/doc/requirement/official_api.md @@ -19,7 +19,8 @@ 数据来源:接入并转发从空管接收到的融合数据 -1. 接口地址: +1. 接口地址: + 弃用接口地址: 2. 请求方式:get,需要在 Header 中携带认证信息,字段名为 Authorization,值为认证接口返回的token diff --git a/qaup-collision/src/main/java/com/qaup/collision/common/model/FlightNotification.java b/qaup-collision/src/main/java/com/qaup/collision/common/model/FlightNotification.java index efcabc73..7acb897c 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/common/model/FlightNotification.java +++ b/qaup-collision/src/main/java/com/qaup/collision/common/model/FlightNotification.java @@ -134,8 +134,10 @@ public class FlightNotification { * 检查通知是否有效 */ public boolean isValid() { +// return flightNo != null && !flightNo.trim().isEmpty() +// && type != null +// && eventTime != null; return flightNo != null && !flightNo.trim().isEmpty() - && type != null - && eventTime != null; + && type != null; } } \ No newline at end of file diff --git a/qaup-collision/src/main/java/com/qaup/collision/datacollector/config/ADXPWebSocketConfig.java b/qaup-collision/src/main/java/com/qaup/collision/datacollector/config/ADXPWebSocketConfig.java index 7fdc9e66..d5385ec6 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/datacollector/config/ADXPWebSocketConfig.java +++ b/qaup-collision/src/main/java/com/qaup/collision/datacollector/config/ADXPWebSocketConfig.java @@ -6,12 +6,31 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.client.WebSocketClient; import org.springframework.web.socket.client.standard.StandardWebSocketClient; +import java.util.HashMap; +import java.util.Map; + @Configuration public class ADXPWebSocketConfig { @Bean public WebSocketClient webSocketClient() { - return new StandardWebSocketClient(); + StandardWebSocketClient client = new StandardWebSocketClient(); + + Map props = new HashMap<>(); + // ====== JSR-356 标准配置(一定生效)====== + props.put("javax.websocket.maxTextMessageBufferSize", 10 * 1024 * 1024); // 10MB + props.put("javax.websocket.maxBinaryMessageBufferSize", 10 * 1024 * 1024); + + // ====== Tomcat 实现专用(有则更稳)====== + props.put("org.apache.tomcat.websocket.textBufferSize", 10 * 1024 * 1024); + props.put("org.apache.tomcat.websocket.binaryBufferSize", 10 * 1024 * 1024); + + client.setUserProperties(props); + + client.setUserProperties(props); + + return client; + //return new StandardWebSocketClient(); } @Bean diff --git a/qaup-collision/src/main/java/com/qaup/collision/datacollector/dao/DataCollectorDao.java b/qaup-collision/src/main/java/com/qaup/collision/datacollector/dao/DataCollectorDao.java index db53ee71..62ccabd2 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/datacollector/dao/DataCollectorDao.java +++ b/qaup-collision/src/main/java/com/qaup/collision/datacollector/dao/DataCollectorDao.java @@ -354,44 +354,43 @@ public class DataCollectorDao { * @return 航班路由参数数据 */ public AircraftRouteParamsDTO getAircraftRouteParams(String flightNo, String routeType) { - try { - String token = authService.getToken(airportBaseUrl); - if (token == null) { - log.error("无法获取有效的认证token"); - return null; - } - - String url = UriComponentsBuilder.fromUriString(airportBaseUrl) - .path("/aircraftRouteParamsController/getRouteParams") - .queryParam("flightNo", flightNo) - .queryParam("routeType", routeType) - .toUriString(); - - HttpHeaders headers = new HttpHeaders(); - headers.set("Authorization", token); - headers.set("Content-Type", "application/json"); - - HttpEntity requestEntity = new HttpEntity<>(headers); - - ResponseEntity> response = restTemplate.exchange( - url, - HttpMethod.GET, - requestEntity, - new ParameterizedTypeReference>() {} - ); - - Response responseBody = response.getBody(); - if (responseBody != null && responseBody.getStatus() == 200) { - log.info("成功获取航班路由参数: flightNo={}, routeType={}", flightNo, routeType); - return responseBody.getData(); - } else { - log.warn("获取航班路由参数失败: {}", responseBody != null ? responseBody.getMsg() : "未知错误"); - return null; - } - } catch (Exception e) { - log.error("获取航班路由参数时发生异常: flightNo={}, routeType={}", flightNo, routeType, e); - return null; - } +// try { +// String token = authService.getToken(airportBaseUrl); +// if (token == null) { +// log.error("无法获取有效的认证token"); +// return null; +// } +// +// String url = UriComponentsBuilder.fromUriString(airportBaseUrl) +// .path("/aircraftRouteParamsController/getRouteParams") +// .queryParam("flightNo", flightNo) +// .queryParam("routeType", routeType) +// .toUriString(); +// +// HttpHeaders headers = new HttpHeaders(); +// headers.set("Authorization", token); +// headers.set("Content-Type", "application/json"); +// +// HttpEntity requestEntity = new HttpEntity<>(headers); +// ResponseEntity> response = restTemplate.exchange( +// url, +// HttpMethod.GET, +// requestEntity, +// new ParameterizedTypeReference>() {} +// ); +// Response responseBody = response.getBody(); +// if (responseBody != null && responseBody.getStatus() == 200) { +// log.info("成功获取航班路由参数: flightNo={}, routeType={}", flightNo, routeType); +// return responseBody.getData(); +// } else { +// log.warn("获取航班路由参数失败: {}", responseBody != null ? responseBody.getMsg() : "未知错误"); +// return null; +// } +// } catch (Exception e) { +// log.error("获取航班路由参数时发生异常: flightNo={}, routeType={}", flightNo, routeType, e); +// return null; +// } + return null; } /** diff --git a/qaup-collision/src/main/java/com/qaup/collision/datacollector/service/DataCollectorService.java b/qaup-collision/src/main/java/com/qaup/collision/datacollector/service/DataCollectorService.java index caec7462..5e122533 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/datacollector/service/DataCollectorService.java +++ b/qaup-collision/src/main/java/com/qaup/collision/datacollector/service/DataCollectorService.java @@ -137,7 +137,9 @@ public class DataCollectorService { return; } - log.info("通过WebSocket接收到 {} 条航班进出港通知", notifications.size()); + //log.info("通过WebSocket接收到 {} 条航班进出港通知", notifications.size()); + log.error("通过WebSocket接收到 {} 条航班进出港通知hhhhhhhhhhhhhhh", notifications.size()); + log.error("通过WebSocket接收到 {} 条航班进出港通知hhhhhhhhhhhhhhh", notifications); // 将DTO转换为业务对象并处理 for (FlightNotificationDTO dto : notifications) { @@ -681,6 +683,7 @@ public class DataCollectorService { if (adxpFlightServiceWebSocketClient != null && adxpFlightServiceWebSocketClient.isConnected()) { // WebSocket客户端已连接,消息通过WebSocket实时接收 log.debug("使用WebSocket客户端接收航班通知"); + return; } @@ -778,9 +781,32 @@ public class DataCollectorService { */ private void cacheFlightNotification(FlightNotification notification) { String cacheKey = notification.getFlightNo() + ":" + notification.getType().name(); - flightNotificationCache.put(cacheKey, notification); - log.debug("缓存航班通知: flightNo={}, type={}, 缓存数量={}", - notification.getFlightNo(), notification.getType(), flightNotificationCache.size()); + + // 检查缓存中是否已有该键值 + FlightNotification existingNotification = flightNotificationCache.get(cacheKey); + if (existingNotification != null) { + // 合并通知:新的有值的字段覆盖旧的,没有值的字段延用旧的 + FlightNotification mergedNotification = FlightNotification.builder() + .flightNo(notification.getFlightNo()) + .type(notification.getType()) + .runway(notification.getRunway() != null ? notification.getRunway() : existingNotification.getRunway()) + .contactCross(notification.getContactCross() != null ? notification.getContactCross() : existingNotification.getContactCross()) + .seat(notification.getSeat() != null ? notification.getSeat() : existingNotification.getSeat()) + .eventTime(notification.getEventTime() != null ? notification.getEventTime() : existingNotification.getEventTime()) + .eventDateTime(notification.getEventDateTime() != null ? notification.getEventDateTime() : existingNotification.getEventDateTime()) + .receivedTime(existingNotification.getReceivedTime()) // 保持接收时间不变 + .active(notification.getActive() != null ? notification.getActive() : existingNotification.getActive()) + .build(); + + flightNotificationCache.put(cacheKey, mergedNotification); + log.info("合并航班通知缓存: flightNo={}, type={}, 缓存数量={}", + notification.getFlightNo(), notification.getType(), flightNotificationCache.size()); + } else { + // 缓存中没有该键值,直接放入 + flightNotificationCache.put(cacheKey, notification); + log.info("新增航班通知缓存: flightNo={}, type={}, 缓存数量={}", + notification.getFlightNo(), notification.getType(), flightNotificationCache.size()); + } } /** @@ -813,13 +839,13 @@ public class DataCollectorService { } // 清理 flightNotificationCache - 使用 eventTime 字段判断 - int sizeBefore = flightNotificationCache.size(); - flightNotificationCache.entrySet().removeIf(entry -> { - FlightNotification notification = entry.getValue(); - long eventTime = (notification.getEventTime() != null) ? notification.getEventTime() : 0; - return (now - eventTime) > inactiveThreshold; - }); - removedFlightNotifications = sizeBefore - flightNotificationCache.size(); +// int sizeBefore = flightNotificationCache.size(); +// flightNotificationCache.entrySet().removeIf(entry -> { +// FlightNotification notification = entry.getValue(); +// long eventTime = (notification.getEventTime() != null) ? notification.getEventTime() : 0; +// return (now - eventTime) > inactiveThreshold; +// }); +// removedFlightNotifications = sizeBefore - flightNotificationCache.size(); if (removedMovingObjects > 0 || removedFlightNotifications > 0) { log.info("清理不活跃缓存对象: {} 个移动对象, {} 个航班通知; 剩余: {} 个移动对象, {} 个航班通知", @@ -842,3 +868,4 @@ public class DataCollectorService { log.info("缓存已清理"); } } + diff --git a/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpFlightServiceWebSocketClient.java b/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpFlightServiceWebSocketClient.java index a15784a0..2f765ae6 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpFlightServiceWebSocketClient.java +++ b/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpFlightServiceWebSocketClient.java @@ -4,9 +4,12 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.qaup.collision.datacollector.config.FlightSdkProperties; import com.qaup.collision.datacollector.dto.FlightNotificationDTO; +import com.qaup.collision.dataprocessing.service.DataProcessingService; +import com.qaup.common.core.redis.RedisCache; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; @@ -38,6 +41,12 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { private Thread reconnectThread; + @Autowired + private RedisCache redisCache; + + @Autowired + private DataProcessingService dataProcessingService; + public AdxpFlightServiceWebSocketClient(WebSocketClient webSocketClient, FlightSdkProperties properties) { this.webSocketClient = webSocketClient; @@ -49,7 +58,7 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { /** * 启动WebSocket客户端 */ - @PostConstruct + //@PostConstruct public void start() { if (isRunning.compareAndSet(false, true)) { log.info("启动ADXP航班通知WebSocket客户端"); @@ -75,6 +84,7 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { public void connect() { if (!properties.isConfigurationReady()) { log.warn("数据中台航班 SDK 配置不完整,WebSocket客户端将无法正常工作"); + scheduleReconnect(); return; } @@ -159,20 +169,48 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { isConnected.set(true); messageCount.set(0); // 重置消息计数 } - + + // 【新增】用于拼接 WebSocket 分片消息 + private final StringBuilder partialMessageBuffer = new StringBuilder(1024 * 1024); @Override public void handleMessage(@NonNull WebSocketSession session, @NonNull WebSocketMessage message) throws Exception { - if (message instanceof TextMessage) { - handleTextMessage(session, (TextMessage) message); + + if (!(message instanceof TextMessage textMessage)) { + return; } + + //每来一片就拼 + partialMessageBuffer.append(textMessage.getPayload()); + + //不是最后一片,直接等 + if (!textMessage.isLast()) { + return; + } + + //最后一片,才算一条完整消息 + String fullPayload = partialMessageBuffer.toString(); + partialMessageBuffer.setLength(0); + + try { + // 👇 用你原来的逻辑处理 + handleTextMessage(session, fullPayload); + } catch (Exception e) { + log.error("处理完整 WebSocket 消息失败", e); + } + + +// if (message instanceof TextMessage) { +// handleTextMessage(session, (TextMessage) message); +// } } - public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + public void handleTextMessage(WebSocketSession session, String payload) throws Exception { try { - // 解析接收到的消息 - String payload = message.getPayload(); +// // 解析接收到的消息 +// String payload = message.getPayload(); + log.debug("📥 收到WebSocket消息 ({} bytes)", payload.length()); - + // 增加消息计数 messageCount.incrementAndGet(); @@ -181,7 +219,8 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { if (!notifications.isEmpty()) { log.info("🛬 接收到 {} 条航班通知", notifications.size()); - + log.error("🛬 接收到 {} 条航班通知", notifications.size()); + // 通知所有监听器 for (Consumer> listener : messageListeners) { try { @@ -227,7 +266,7 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { @Override public boolean supportsPartialMessages() { - return false; + return true; } /** @@ -238,11 +277,17 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { // 解析FlightMessage列表 List flightMessages = objectMapper.readValue(jsonContent, new TypeReference>() {}); + + log.error("📥 收到WebSocket消息 ({})", flightMessages); + + List notifications = new java.util.ArrayList<>(); for (FlightMessage message : flightMessages) { try { + log.error("hhhhh获取消息内容: serviceCode={}", message.getServiceCode()); + log.error("hhhhh获取消息内容: content={}", message.getContent()); FlightNotificationDTO dto = parseXmlMessage(message.getServiceCode(), message.getContent()); if (dto != null) { notifications.add(dto); @@ -252,7 +297,7 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { errorCount.incrementAndGet(); } } - + log.error("notifications={}", notifications); return notifications; } catch (Exception e) { log.error("解析消息失败", e); @@ -272,13 +317,20 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { switch (serviceCode) { case "ADXP_NAOMS_O_DYN_ARR": - return parseArrival(root); + //return parseArrival(root); + return handleARR(root); case "ADXP_NAOMS_O_CDM_AXOT": return parsePushback(root); case "ADXP_NAOMS_O_CDM_RUNWAY": - return parseRunway(root); + //return parseRunway(root); + return handleRUNWAY(root); case "ADXP_NAOMS_O_DYN_CRAFTSEAT": - return parseGate(root); + //return parseGate(root); + return handleCRAFTSEAT(root); + case "ADXP_NAOMS_O_DYN_DFIE": + return handleDFIE(root); + case "ADXP_NAOMS_O_DYN_TISFLIGHT": + return handleTISFLIGHT(root); default: log.debug("未知的服务代码: {}", serviceCode); return null; @@ -312,7 +364,7 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { return dto; } - + private FlightNotificationDTO parsePushback(org.w3c.dom.Element root) { String flightNo = getTextContent(root, "FlightNumber"); String actualPushback = getTextContent(root, "ActualPushback"); @@ -439,4 +491,160 @@ public class AdxpFlightServiceWebSocketClient implements WebSocketHandler { errorCount.get(), isRunning.get()); } + + + //处理ARR事件 + private FlightNotificationDTO handleARR(org.w3c.dom.Element root) { + String flightNo = getTextContent(root, "BizKey"); + //分解BizKey + String[] arr = flightNo.split("-", 3); // 最多切 3 段 + FlightNotificationDTO dto = new FlightNotificationDTO(); + dto.setFlightNo(flightNo); + dto.setType("IN"); + // 存储到Redis + if (arr.length >= 3) { + try { + String key = "flight:" + arr[0]; // 使用航班号作为键 + redisCache.setCacheMapValue(key, "flightNumber", arr[0]); + redisCache.setCacheMapValue(key, "type", arr[1]); + redisCache.setCacheMapValue(key, "time", arr[2]); + log.info("成功将航班数据存储到Redis: flightNumber={}, type={}, time={}", arr[0], arr[1], arr[2]); + } catch (Exception e) { + log.error("存储航班数据到Redis失败: {}", e.getMessage()); + } + } + //假装模拟请求接口 + dataProcessingService.hello(arr[0]); + return dto; + } + + private FlightNotificationDTO handleDFIE(org.w3c.dom.Element root) { + String flightNo = getTextContent(root, "BizKey"); + String RunwayNum = getTextContent(root, "RunwayNum"); + String InOut = getTextContent(root, "InOut"); + //分解BizKey + String[] arr = flightNo.split("-", 3); // 最多切 3 段 + + FlightNotificationDTO dto = new FlightNotificationDTO(); + dto.setFlightNo(flightNo); + if (InOut.equals("A")){ + dto.setType("IN"); + }else { + dto.setType("OUT"); + } + dto.setRunway(RunwayNum); + + // 存储到Redis + if (arr.length >= 3) { + try { + String key = "flight:" + arr[0]; // 使用航班号作为键 + redisCache.setCacheMapValue(key, "flightNumber", arr[0]); + redisCache.setCacheMapValue(key, "type", arr[1]); + redisCache.setCacheMapValue(key, "time", arr[2]); + if (InOut.equals("A")){ + redisCache.setCacheMapValue(key, "inRunway", RunwayNum); + }else { + redisCache.setCacheMapValue(key, "outRunway", RunwayNum); + } + log.info("成功将航班数据存储到Redis: flightNumber={}, type={}, time={}", arr[0], arr[1], arr[2]); + } catch (Exception e) { + log.error("存储航班数据到Redis失败: {}", e.getMessage()); + } + } + + return dto; + } + + //处理RUNWAY事件 + private FlightNotificationDTO handleRUNWAY(org.w3c.dom.Element root) { + String flightNo = getTextContent(root, "BizKey"); + String outRunway = getTextContent(root, "RUNWAYDEP"); + String inRunway = getTextContent(root, "RUNWAYARR"); + if (inRunway.equals("")){ + log.error("inRunway为空字符串"); + } + + log.error("inRunway-{}",inRunway); + log.error("outRunway-{}",outRunway); + //分解BizKey + String[] arr = flightNo.split("-", 3); // 最多切 3 段 + FlightNotificationDTO dto = new FlightNotificationDTO(); + dto.setFlightNo(flightNo); + if (arr[1].equals("A")){ + dto.setType("IN"); + }else { + dto.setType("OUT"); + } + // 存储到Redis + if (arr.length >= 3) { + try { + String key = "flight:" + arr[0]; // 使用航班号作为键 + redisCache.setCacheMapValue(key, "flightNumber", arr[0]); + redisCache.setCacheMapValue(key, "type", arr[1]); + redisCache.setCacheMapValue(key, "time", arr[2]); + if (!inRunway.equals("")){ + redisCache.setCacheMapValue(key, "inRunway", inRunway); + } + if (!outRunway.equals("")){ + redisCache.setCacheMapValue(key, "outRunway", outRunway); + } + log.info("成功将航班数据存储到Redis: flightNumber={}, type={}, time={}", arr[0], arr[1], arr[2]); + } catch (Exception e) { + log.error("存储航班数据到Redis失败: {}", e.getMessage()); + } + } + //假装模拟请求接口 + dataProcessingService.hello(arr[0]); + return dto; + } + + //处理CRAFTSEAT事件 + private FlightNotificationDTO handleCRAFTSEAT(org.w3c.dom.Element root) { + String flightNo = getTextContent(root, "BizKey"); + String code = getTextContent(root, "Code"); + log.error("seat-{}",code); + //分解BizKey + String[] arr = flightNo.split("-", 3); // 最多切 3 段 + FlightNotificationDTO dto = new FlightNotificationDTO(); + dto.setFlightNo(flightNo); + // 存储到Redis + if (arr.length >= 3) { + try { + String key = "flight:" + arr[0]; // 使用航班号作为键 + redisCache.setCacheMapValue(key, "flightNumber", arr[0]); + redisCache.setCacheMapValue(key, "type", arr[1]); + redisCache.setCacheMapValue(key, "time", arr[2]); + redisCache.setCacheMapValue(key, "seat", code); + log.info("成功将航班数据存储到Redis: flightNumber={}, type={}, time={}", arr[0], arr[1], arr[2]); + } catch (Exception e) { + log.error("存储航班数据到Redis失败: {}", e.getMessage()); + } + } + //假装模拟请求接口 + dataProcessingService.hello(arr[0]); + return dto; + } + + private FlightNotificationDTO handleTISFLIGHT(org.w3c.dom.Element root) { + String flightNumber = getTextContent(root, "FlNo"); + String contactCross = getTextContent(root, "ContactCross"); + + FlightNotificationDTO dto = new FlightNotificationDTO(); + dto.setFlightNo(flightNumber); + dto.setType("IN"); + + String key = "flight:" + flightNumber; + + try { + redisCache.setCacheMapValue(key, "flightNumber", flightNumber); + redisCache.setCacheMapValue(key, "contactCross",contactCross); + } catch (Exception e) { + log.error("存储航班数据到Redis失败: {}", e.getMessage()); + } + + return dto; + } + + + } \ No newline at end of file diff --git a/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpWebSocketStarter.java b/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpWebSocketStarter.java new file mode 100644 index 00000000..d18e6f47 --- /dev/null +++ b/qaup-collision/src/main/java/com/qaup/collision/datacollector/websocket/AdxpWebSocketStarter.java @@ -0,0 +1,20 @@ +package com.qaup.collision.datacollector.websocket; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +public class AdxpWebSocketStarter { + + private final AdxpFlightServiceWebSocketClient client; + + public AdxpWebSocketStarter(AdxpFlightServiceWebSocketClient client) { + this.client = client; + } + + @EventListener(ApplicationReadyEvent.class) + public void startWhenReady() { + client.start(); + } +} diff --git a/qaup-collision/src/main/java/com/qaup/collision/dataprocessing/service/DataProcessingService.java b/qaup-collision/src/main/java/com/qaup/collision/dataprocessing/service/DataProcessingService.java index 97be3ca0..a9f6d17b 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/dataprocessing/service/DataProcessingService.java +++ b/qaup-collision/src/main/java/com/qaup/collision/dataprocessing/service/DataProcessingService.java @@ -15,6 +15,7 @@ import com.qaup.collision.websocket.event.VehicleStatusUpdateEvent; import com.qaup.collision.datacollector.service.DataCollectorService; import com.qaup.collision.common.model.FlightNotification; import com.qaup.collision.websocket.event.FlightNotificationEvent; +import com.qaup.common.core.redis.RedisCache; import com.qaup.system.domain.SysVehicleInfo; import lombok.extern.slf4j.Slf4j; @@ -87,6 +88,9 @@ public class DataProcessingService { @Autowired private ApplicationContext applicationContext; + @Autowired + private RedisCache redisCache; + // 从DataCollectorService获取缓存的引用 private Map activeMovingObjectsCache; @@ -488,6 +492,10 @@ public class DataProcessingService { DataCollectorService dataCollectorService = applicationContext.getBean(DataCollectorService.class); Map flightNotificationCache = dataCollectorService.getFlightNotificationCache(); + // 打印缓存数量 + log.error("航班通知缓存数量: {}", flightNotificationCache.size()); + log.error("航班通知缓存内容: {}", flightNotificationCache); + if (flightNotificationCache.isEmpty()) { log.debug("航班通知缓存为空,跳过处理"); return; @@ -1268,4 +1276,30 @@ public class DataProcessingService { log.error("❌ 发布航空器路由更新事件失败: flightNo={}", flightNo, e); } } + + /** + * 触发查询航班号对应的路由 + */ + public void hello(String flightNo){ + log.error("hello666666666666666666666666666666666666"); + String key = "flight:"+flightNo; + + String time =(String) redisCache.getCacheMapValue(key, "time"); + log.error("time是{}",time); + String inRunway = "35"; + String outRunway = "34"; + String contactCross = "F1"; + String seat = "138"; + + // 获取DataCollectorDao进行路由数据查询 + DataCollectorDao dataCollectorDao = applicationContext.getBean(DataCollectorDao.class); + AircraftRouteDTO routeData = null; + // 进港路由查询 + routeData = dataCollectorDao.getArrivalRoute( + inRunway, + outRunway, + contactCross, + seat); + log.error("routeData是{}",routeData); + } } \ No newline at end of file diff --git a/qaup-collision/src/main/java/com/qaup/collision/rule/service/impl/LocationRuleQueryServiceImpl.java b/qaup-collision/src/main/java/com/qaup/collision/rule/service/impl/LocationRuleQueryServiceImpl.java index ac0c8ee3..71b12270 100644 --- a/qaup-collision/src/main/java/com/qaup/collision/rule/service/impl/LocationRuleQueryServiceImpl.java +++ b/qaup-collision/src/main/java/com/qaup/collision/rule/service/impl/LocationRuleQueryServiceImpl.java @@ -74,7 +74,7 @@ public class LocationRuleQueryServiceImpl implements LocationRuleQueryService { // ============================================ @Override - @Cacheable(value = "locationRules", key = "#location.toString() + '_' + #vehicleType + '_' + #timestamp.toString()") + //@Cacheable(value = "locationRules", key = "#location.toString() + '_' + #vehicleType + '_' + #timestamp.toString()") public List findApplicableRules(Point location, MovingObjectType vehicleType, LocalDateTime timestamp) { try { logger.debug("查询位置适用规则: location={}, vehicleType={}, timestamp={}",