文章目录
一、项目背景
公司有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 {
@Autowired
SimpMessagingTemplate 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 -> sessions
static final ConcurrentMap<String, CopyOnWriteArraySet<WebSocketSession>> channelSessions =
new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String channel = getChannelFromSession(session);
channelSessions.computeIfAbsent(channel, k -> new CopyOnWriteArraySet<>()).add(session);
}
@Override
public 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 {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(pushWebSocketHandler(), "/{channel}")
.addInterceptors(new ChannelInterceptor())
.setAllowedOrigins("*");
}
@Bean
public WebSocketHandler pushWebSocketHandler() {
return new PushWebSocketHandler();
}
/**
* 🌟 频道拦截器(用于获取路径参数)
*/
private static class ChannelInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public 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;
}