JiuMuMesParent/common/servicebase/src/main/java/com/mes/tools/WebSocketServer.java
File was deleted JiuMuMesParent/common/servicebase/src/main/java/com/mes/websocket/WebSocketServer.java
New file @@ -0,0 +1,170 @@ package com.mes.websocket; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Semaphore; /** * WebSocketServer class * * @author zsh * @date 2025/07/04 */ @ServerEndpoint(value = "/api/talk/{webSocketName}") @Component public class WebSocketServer { /** 日志记录器,记录 WebSocketServer 类运行时日志信息 */ private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class); /** 单次消息允许的最大字符数(超出则进行分块) */ private static final int MAX_MESSAGE_SIZE = 50000; /** 用于限制并发连接数量的信号量,控制最大并发数为 100 */ private static final Semaphore SEMAPHORE = new Semaphore(100); /** * 用户名与 WebSocket 实例映射表,支持一个用户对应多个连接。 * 使用线程安全的 ConcurrentHashMap 存储,保证高并发下的数据一致性。 */ public static final Map<String, List<WebSocketServer>> SESSIONMAP = new ConcurrentHashMap<>(); // public static final Map<String, ArrayList<WebSocketServer>> sessionMap = new ConcurrentHashMap<>(); /** 当前连接对应的用户名 */ private String webSocketName; /** 当前连接的 WebSocket 会话对象 */ private Session session; /** 线程安全的消息缓存,用于记录当前连接收到的所有消息 */ private final List<String> messages = new CopyOnWriteArrayList<>(); /** * 连接建立 */ @OnOpen public void onOpen(Session session, @PathParam("webSocketName") String webSocketName) { this.webSocketName = webSocketName; this.session = session; SESSIONMAP.computeIfAbsent(webSocketName, k -> new CopyOnWriteArrayList<>()) .add(this); log.info("用户连接: webSocketName={}, 当前会话数: {}", webSocketName, SESSIONMAP.getOrDefault(webSocketName, Collections.emptyList()).size()); } /** * 连接关闭 */ @OnClose public void onClose() { List<WebSocketServer> sessions = SESSIONMAP.get(webSocketName); if (sessions != null) { sessions.remove(this); if (sessions.isEmpty()) { SESSIONMAP.remove(webSocketName); } log.info("用户断开: webSocketName={}, 剩余会话数: {}", webSocketName, SESSIONMAP.getOrDefault(webSocketName, Collections.emptyList()).size()); } } /** * 接收消息 */ @OnMessage public void onMessage(String message) { log.info("收到消息: webSocketName={}, content={}", webSocketName, message); JSONObject obj = JSONUtil.parseObj(message); // 存储消息历史 messages.add(obj.getStr("data")); } /** * 错误处理 */ @OnError public void onError(Throwable error) { log.error("WebSocket错误: webSocketName={}", webSocketName, error); } /** * 向当前用户的所有会话发送消息 */ public void sendToWeb(String webSocketName, String message) { List<WebSocketServer> sessions = SESSIONMAP.get(webSocketName); if (sessions == null) { return; } sessions.forEach(ws -> { try { SEMAPHORE.acquire(); ws.sendChunkedMessage(message); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { log.error("推送失败: webSocketName={}", webSocketName, e); } finally { SEMAPHORE.release(); } }); } /** * 分块发送大消息 */ private void sendChunkedMessage(String message) { if (!session.isOpen()) { return; } try { if (message.length() <= MAX_MESSAGE_SIZE) { session.getBasicRemote().sendText(message); return; } // 分块发送 int chunks = (int) Math.ceil((double) message.length() / MAX_MESSAGE_SIZE); for (int i = 0; i < chunks; i++) { int start = i * MAX_MESSAGE_SIZE; int end = Math.min(start + MAX_MESSAGE_SIZE, message.length()); String chunk = message.substring(start, end) + (i == chunks - 1 ? "<END>" : ""); session.getBasicRemote().sendText(chunk); } } catch (IOException e) { log.error("消息发送失败: webSocketName={}", webSocketName, e); } } public List<WebSocketServer> getWebSocketServer(String name) { return SESSIONMAP.get(name); } public static Set<String> getOnlineUsers() { return SESSIONMAP.keySet(); } public List<String> getMessages() { return Collections.unmodifiableList(messages); } public void clearMessages() { messages.clear(); } } JiuMuMesParent/common/servicebase/src/main/java/com/mes/websocket/WebSocketUtils.java
New file @@ -0,0 +1,31 @@ package com.mes.websocket; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @Author : zhoush * @Date: 2025/6/27 10:01 * @Description: */ @Slf4j @Component public class WebSocketUtils { @Resource WebSocketServer webSocketServer; @Resource ObjectMapper objectMapper; public <T> void sendToWeb(String webSocketName, T t) { try { String message = objectMapper.writeValueAsString(t); webSocketServer.sendToWeb(webSocketName, message); } catch (JsonProcessingException ex) { log.info("{}发送数据失败:{}", "rawGlassStorage", ex.getMessage()); } } } JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/service/impl/EnergyConsumptionServiceImpl.java
@@ -1,14 +1,14 @@ package com.mes.energy.service.impl; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mes.energy.entity.EnergyConsumption; import com.mes.energy.mapper.EnergyConsumptionMapper; import com.mes.energy.service.EnergyConsumptionService; import com.mes.tools.WebSocketServer; import cn.hutool.json.JSONObject; import com.mes.websocket.WebSocketServer; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class EnergyConsumptionServiceImpl extends ServiceImpl<EnergyConsumptionMapper, EnergyConsumption> implements EnergyConsumptionService { @@ -19,10 +19,10 @@ message.set("type", "energy_update"); message.set("data", consumption); ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("energy"); List<WebSocketServer> servers = WebSocketServer.SESSIONMAP.get("energy"); if (servers != null) { for (WebSocketServer server : servers) { server.sendMessage(message.toString()); server.sendToWeb("",message.toString()); } } } JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/job/AddTask.java
@@ -1,25 +1,22 @@ package com.mes.job; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.mes.md.entity.*; import com.mes.md.mapper.MachineMapper; import com.mes.md.entity.KBBTJPDrawingBP; import com.mes.md.entity.Tasking; import com.mes.md.mapper.TaskingMapper; import com.mes.md.service.*; import com.mes.service.ModbusTcp; import com.mes.service.PlcAgreement; import com.mes.service.PlcParameter; import com.mes.tools.WebSocketServer; import com.mes.utils.HexUtil; import com.mes.utils.Result; import com.mes.md.service.KBBTJPDrawingBPService; import com.mes.md.service.ProjectService; import com.mes.md.service.TaskingLogService; import com.mes.websocket.WebSocketServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.*; import java.util.Calendar; import java.util.Date; import java.util.List; /** * @author SNG-010 @@ -69,12 +66,12 @@ JSONObject jsonObject = new JSONObject(); List<KBBTJPDrawingBP> list =kBBTJPDrawingBPService.notReceiveKBBTJPDrawingBP(); jsonObject.append("content", list); ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get("notReceiveTask"); List<WebSocketServer> sendwServer = WebSocketServer.SESSIONMAP.get("notReceiveTask"); if (sendwServer != null) { for (WebSocketServer webserver : sendwServer) { if (webserver != null) { try { webserver.sendMessage(jsonObject.toString()); webserver.sendToWeb("",jsonObject.toString()); List<String> messages = webserver.getMessages(); if (!messages.isEmpty()) { // // 将最后一个消息转换为整数类型的列表 JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/job/MachineTask.java
@@ -2,24 +2,19 @@ import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.mes.common.S7objectFlipSlice; import com.mes.common.S7objectMachine; import com.mes.common.S7objectMarking; import com.mes.device.PlcParameterInfo; import com.mes.device.PlcParameterObject; import com.mes.md.entity.*; import com.mes.md.mapper.GlassInfoMapper; import com.mes.md.mapper.MachineMapper; import com.mes.md.mapper.TaskingMapper; import com.mes.md.service.*; import com.mes.tools.WebSocketServer; import com.mes.websocket.WebSocketServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -50,6 +45,8 @@ KBBTJPDrawingBPService kBBTJPDrawingBPService; @Autowired LineConfigurationService lineConfigurationService; @Resource WebSocketServer webSocketServer; @Autowired private GlassInfoMapper glassInfoMapper; public List<Map> sendRecords = new ArrayList<>(); @@ -241,33 +238,42 @@ this.webSocketServer(jsonObject); } public void webSocketServer(JSONObject jsonObject) { try { String sessionMapName=jsonObject.getJSONArray("sessionMapName").get(0).toString(); ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get(sessionMapName); if (sendwServer != null) { for (WebSocketServer webserver : sendwServer) { if (webserver != null) { try { webserver.sendMessage(jsonObject.toString()); List<String> messages = webserver.getMessages(); if (!messages.isEmpty()) { // // 将最后一个消息转换为整数类型的列表 webserver.clearMessages(); } }catch (Exception e) { } } else { log.info("Home is closed"); } } } }catch (Exception e) { webSocketServer.sendToWeb(sessionMapName, jsonObject.toString()); } catch (Exception ex) { log.info("{}发送数据失败:{}", "rawGlassStorage", ex.getMessage()); } } // public void webSocketServer(JSONObject jsonObject) { // try { // String sessionMapName=jsonObject.getJSONArray("sessionMapName").get(0).toString(); // ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get(sessionMapName); // if (sendwServer != null) { // for (WebSocketServer webserver : sendwServer) { // try { // webserver.sendMessage(jsonObject.toString()); // List<String> messages = webserver.getMessages(); // if (!messages.isEmpty()) { // // // 将最后一个消息转换为整数类型的列表 // webserver.clearMessages(); // } // }catch (Exception e) { // if (webserver != null) { // // } else { // log.info("Home is closed"); // } // } // // } // } // }catch (Exception e) { // // } // // } } JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/job/PLCCleaning.java
@@ -2,25 +2,20 @@ import cn.hutool.json.JSONObject; import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; import com.mes.common.S7object; import com.mes.common.S7objectCleaning; import com.mes.common.S7objectMachine; import com.mes.common.S7objectMarking; import com.mes.device.PlcParameterInfo; import com.mes.device.PlcParameterObject; import com.mes.md.entity.Machine; import com.mes.md.entity.Tasking; import com.mes.md.mapper.MachineMapper; import com.mes.md.service.TaskingService; import com.mes.tools.WebSocketServer; import com.mes.websocket.WebSocketServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * @author SNG-010 @@ -67,12 +62,12 @@ List<Tasking> taskingList=taskingService.findMachineTask(machine); jsonObject.append("taskingList", taskingList); jsonObject.append("machine", machine); ArrayList<WebSocketServer> sendwServer = WebSocketServer.sessionMap.get("cleaning"); List<WebSocketServer> sendwServer = WebSocketServer.SESSIONMAP.get("cleaning"); if (sendwServer != null) { for (WebSocketServer webserver : sendwServer) { if (webserver != null) { try { webserver.sendMessage(jsonObject.toString()); webserver.sendToWeb("",jsonObject.toString()); List<String> messages = webserver.getMessages(); if (!messages.isEmpty()) { // // 将最后一个消息转换为整数类型的列表 JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/mechanicalMonitor/controller/MechanicalMonitorController.java
@@ -1,17 +1,17 @@ package com.mes.mechanicalMonitor.controller; import cn.hutool.json.JSONObject; import com.mes.mechanicalMonitor.entity.MechanicalMonitor; import com.mes.mechanicalMonitor.service.MechanicalMonitorService; import com.mes.tools.WebSocketServer; import com.mes.utils.Result; import com.mes.websocket.WebSocketServer; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import cn.hutool.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.HashMap; import java.util.List; import java.util.Map; @Api(tags = "设备状态监控") @@ -42,10 +42,10 @@ @ResponseBody public Result updateMechanicalStatus(@RequestBody JSONObject status) { try { ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("mechanicalMonitor"); List<WebSocketServer> servers = WebSocketServer.SESSIONMAP.get("mechanicalMonitor"); if (servers != null) { for (WebSocketServer server : servers) { server.sendMessage(status.toString()); server.sendToWeb("",status.toString()); } } return Result.build(200, "状态更新成功", null); JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/mechanicalMonitor/service/impl/MechanicalMonitorServiceImpl.java
@@ -1,15 +1,15 @@ package com.mes.mechanicalMonitor.service.impl; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mes.mechanicalMonitor.entity.MechanicalMonitor; import com.mes.mechanicalMonitor.mapper.MechanicalMonitorMapper; import com.mes.mechanicalMonitor.service.MechanicalMonitorService; import com.mes.tools.WebSocketServer; import cn.hutool.json.JSONObject; import com.mes.websocket.WebSocketServer; import org.springframework.stereotype.Service; import java.util.List; import java.util.Date; import java.util.ArrayList; import java.util.List; @Service public class MechanicalMonitorServiceImpl extends ServiceImpl<MechanicalMonitorMapper, MechanicalMonitor> @@ -52,10 +52,10 @@ message.set("type", "status_change"); message.set("data", monitor); ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("mechanicalMonitor"); List<WebSocketServer> servers = WebSocketServer.SESSIONMAP.get("mechanicalMonitor"); if (servers != null) { for (WebSocketServer server : servers) { server.sendMessage(message.toString()); server.sendToWeb("",message.toString()); } } } JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/plannedAmount/service/impl/PlannedAmountImpl.java
@@ -5,10 +5,10 @@ import com.mes.plannedAmount.entity.PlannedAmount; import com.mes.plannedAmount.mapper.PlannedAmountMapper; import com.mes.plannedAmount.service.PlannedAmountService; import com.mes.tools.WebSocketServer; import com.mes.websocket.WebSocketServer; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class PlannedAmountImpl extends ServiceImpl<PlannedAmountMapper, PlannedAmount> implements PlannedAmountService { @@ -19,10 +19,10 @@ message.set("type", "planned_update"); message.set("data", value); ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("value"); List<WebSocketServer> servers = WebSocketServer.SESSIONMAP.get("value"); if (servers != null) { for (WebSocketServer server : servers) { server.sendMessage(message.toString()); server.sendToWeb("",message.toString()); } } } JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/yield/service/impl/YieldServiceImpl.java
@@ -1,18 +1,14 @@ package com.mes.yield.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.mes.websocket.WebSocketServer; import com.mes.yield.entity.Yield; import com.mes.yield.mapper.YieldMapper; import com.mes.yield.service.YieldService; import com.mes.tools.WebSocketServer; import cn.hutool.json.JSONObject; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @Service public class YieldServiceImpl extends ServiceImpl<YieldMapper, Yield> implements YieldService { @@ -23,10 +19,10 @@ message.set("type", "yield_update"); message.set("data", yield); ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("yield"); List<WebSocketServer> servers = WebSocketServer.SESSIONMAP.get("yield"); if (servers != null) { for (WebSocketServer server : servers) { server.sendMessage(message.toString()); server.sendToWeb("",message.toString()); } } }