文章目录
- 一、项目背景
- 二、使用方式
- 1.vue2+java+spring
- pom.xml
- RealtimeMonitor.vue
- MonitorTaskExe.java
- WSTopicEnum.java
- WServerHelper.java
- 2.vue3+java+springboot
- pom.xml
- TopologyView.vue
- AlarmDataInquiryController.java
- PushService.java
- PushWebSocketHandler.java
- WebSocketConfig.java
- RepeaterNetStateEntity.java
一、项目背景
公司有2个项目,项目一采用vue2,项目二采用vue3,目前分别记录。
二、使用方式
1.vue2+java+spring
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>ems-common</artifactId><groupId>com.hero.lte.ems</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>ems-common-websocket</artifactId>
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>4.2.3.RELEASE</version></dependency><!-- http://mvnrepository.com/artifact/org.eclipse.jetty.websocket/websocket-server --><dependency><groupId>org.eclipse.jetty.websocket</groupId><artifactId>websocket-server</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>log4j-over-slf4j</artifactId></dependency><dependency><groupId>com.hero.lte.ems</groupId><artifactId>other</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>
RealtimeMonitor.vue
data() {return {websocketSetting: [{ topic: '/user/#/realTimeMonitoring', clientId: 'monitoring', callback: this.websocketCallback }]}
}methods: {websocketInit() {socketInstance.init(this.websocketSetting);},websocketCallback(msg) {const data = JSON.parse(msg.body);const CPUUtilization = data.CPUUsage;this.$refs.realtimeCpuMonitor.getMonitorData(CPUUtilization);const memoryTotal = data.memoryTotal;const memoryUsage = data.memoryUsage;const memoryUsageRatio = data.memoryUsageRatio;this.$refs.realtimeMemoryMonitor.getMonitorData(memoryTotal, memoryUsage, memoryUsageRatio);const diskTotal = data.diskTotal;const diskUsage = data.diskUsage;const diskUtilization = data.diskUsageRatio;this.$refs.realtimeDiskMonitor.getMonitorData(diskTotal, diskUsage, diskUtilization);},mounted() {this.websocketInit();},beforeDestroy() {for (let i = 0; i < this.websocketSetting.length; i++) {socketInstance.stopReceiveTopicMsg(this.websocketSetting[i].clientId, this.websocketSetting[i].topic);}
}
MonitorTaskExe.java
import com.hero.lte.ems.websocket.server.WServerHelper;@Resource
WServerHelper serverHelper;private void realTimeMonitoring() {serverHelper.push2OneClient(WSTopicEnum.realTimeMonitoring.name(),"monitoring",JSONObject.toJSONString(jsonObj));
}
WSTopicEnum.java
package com.hero.lte.ems.websocket.enums;public enum WSTopicEnum {ElementServer,OamTaskServer,TrackReportServer,TrackTaskServer,ObserveReportServer,ObserveTaskServer,SpectrumServer,TSTaskServer,CurrentEventServer,AlarmCountServer,PmTaskServer,MsgDispathServer,AutoAlarmServer,PmCurrenttimeWsServer,NodeEventPushServer,CurrentAlarmServer,RackBoardStatusServer,MMLServer,VmQueryWsServer,VmUpdateWsServer,PocVersionServer,DHCPServer,VmQueryVersionServer,ConfigExportServer,ConsistencyServer,ConfigImportMMLServer,realTimeMonitoring,monitorServiceProcess,configBackup,ExecuteTheTaskImmediately,BatchInitNECfgServer,uploadConfigServer;public static WSTopicEnum formatEnum(String value){for(WSTopicEnum status : WSTopicEnum.values()){if(status.name().equalsIgnoreCase(value)){return status;}}return null;}
}
WServerHelper.java
package com.hero.lte.ems.websocket.server;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;@Component
public class WServerHelper {@AutowiredSimpMessagingTemplate messagingTemplate;public void push2OneClient(String topic,String channlId ,Object msg) {this.messagingTemplate.convertAndSend("/user/"+channlId+"/"+topic, msg);}public void push2AllClient(String topic,Object msg) {this.messagingTemplate.convertAndSend("/topic/"+topic, msg);}}
2.vue3+java+springboot
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>data-service-solution</artifactId><groupId>com.xnms</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>xnms-data-service</artifactId><version>1.0.0</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><dependency><groupId>com.xnms</groupId><artifactId>xnms-data-contract</artifactId><version>${project.version}</version></dependency><dependency><groupId>com.xnms</groupId><artifactId>xnms-data-service-api</artifactId><version>${project.version}</version></dependency><!-- Fastjson dependency --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.30</version> <!-- 使用最新版本的fastjson --></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- Spring Boot WebSocket 支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.7</version></dependency><!-- MySQL Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><!-- Apache POI for Excel --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version></dependency><dependency><groupId>org.apache.xmlbeans</groupId><artifactId>xmlbeans</artifactId><version>5.1.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.60.Final</version></dependency></dependencies></project>
TopologyView.vue
let webSocket = null;const connectWebSocket = (url) => {if (webSocket &&(webSocket.readyState === WebSocket.OPEN ||webSocket.readyState === WebSocket.CONNECTING)) {return;}webSocket = new WebSocket(url);webSocket.onopen = () => console.log("TopologyView.vue WebSocket已连接");webSocket.onmessage = handleWebSocketMessage;webSocket.onclose = () => console.log("TopologyView.vue WebSocket已关闭");webSocket.onerror = (error) =>console.error("TopologyView.vue WebSocket错误:", error);
};// WebSocket处理逻辑
const handleWebSocketMessage = (event) => {try {const message = JSON.parse(event.data);......} catch (error) {console.error("TopologyView.vue WebSocket消息处理错误:", error);}
};onUnmounted(() => {if (webSocket &&(webSocket.readyState === WebSocket.OPEN ||webSocket.readyState === WebSocket.CONNECTING)) {webSocket.close();}
});onMounted(async () => {connectWebSocket("/ws/topoView");
}
AlarmDataInquiryController.java
@Operation(summary = "根据站点ID集合查询站点详细信息")
@GetMapping(value = "/testWebsocketRepeaterNetState")
public ResponseModel<List<Repeater>> testWebsocketRepeaterNetState(@RequestParam String repeaterId, @RequestParam Integer rptState, @RequestParam String serialNo){RepeaterNetStateEntity repeaterNetStateEntity = new RepeaterNetStateEntity();repeaterNetStateEntity.setRepeaterId(repeaterId);repeaterNetStateEntity.setRptState(rptState);repeaterNetStateEntity.setSerialNo(serialNo);pushService.messageDataFormatting("topoView", repeaterNetStateEntity);return ResponseModel.ofSuccess();
}
PushService.java
package com.xnms.data.service.service.impl.websocket;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;@Service
public class PushService {/*** 🌟 向指定频道推送消息* @param channel 频道名称(对应URL路径)* @param message 消息内容*/public void pushToChannel(String channel, String message) {CopyOnWriteArraySet<WebSocketSession> sessions = PushWebSocketHandler.channelSessions.get(channel);if (sessions != null) {sessions.forEach(session -> {try {if (session.isOpen()) {session.sendMessage(new TextMessage(message));}} catch (IOException e) {// 处理异常}});}}/*** 🌟 广播所有频道* @param message 消息内容*/public void broadcast(String message) {PushWebSocketHandler.channelSessions.values().forEach(sessions -> {sessions.forEach(session -> {try {if (session.isOpen()) {session.sendMessage(new TextMessage(message));}} catch (IOException e) {// 处理异常}});});}/*** 数据格式化*/public void messageDataFormatting(String path, Object data){ObjectMapper objectMapper = new ObjectMapper();String message = null;try {message = objectMapper.writeValueAsString(data);} catch (JsonProcessingException e) {throw new RuntimeException(e);}this.pushToChannel(path, message);}}
PushWebSocketHandler.java
package com.xnms.data.service.service.impl.websocket;import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;public class PushWebSocketHandler extends TextWebSocketHandler {// 🌟 多频道存储结构:channel -> sessionsstatic final ConcurrentMap<String, CopyOnWriteArraySet<WebSocketSession>> channelSessions =new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {String channel = getChannelFromSession(session);channelSessions.computeIfAbsent(channel, k -> new CopyOnWriteArraySet<>()).add(session);}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {String channel = getChannelFromSession(session);CopyOnWriteArraySet<WebSocketSession> sessions = channelSessions.get(channel);if (sessions != null) {sessions.remove(session);if (sessions.isEmpty()) {channelSessions.remove(channel);}}}private String getChannelFromSession(WebSocketSession session) {return (String) session.getAttributes().get("channel");}
}
WebSocketConfig.java
package com.xnms.data.service.service.impl.websocket;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import java.util.Map;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(pushWebSocketHandler(), "/{channel}").addInterceptors(new ChannelInterceptor()).setAllowedOrigins("*");}@Beanpublic WebSocketHandler pushWebSocketHandler() {return new PushWebSocketHandler();}/*** 🌟 频道拦截器(用于获取路径参数)*/private static class ChannelInterceptor extends HttpSessionHandshakeInterceptor {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,WebSocketHandler wsHandler, Map<String, Object> attributes) {String channel = ((ServletServerHttpRequest) request).getServletRequest().getRequestURI().split("/")[1];attributes.put("channel", channel);try {return super.beforeHandshake(request, response, wsHandler, attributes);} catch (Exception e) {throw new RuntimeException(e);}}}
}
RepeaterNetStateEntity.java
package com.xnms.data.service.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class RepeaterNetStateEntity {private String repeaterId;private int rptState;private String serialNo;
}