引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
声明Spring Boot需要用WebSocket
package cn.codersy.wiki.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* 声明需要使用WebSocket
* @author TenMoons
* @date 2021-08-14 22:35
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
编写WebSocket服务端
package cn.codersy.wiki.websocket;
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.HashMap;
/**
* WebSocket服务器端
* @author TenMoons
* @date 2021-08-14 22:36
*/
@Component
@ServerEndpoint("/ws/{token}")
public class WebSocketServer {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class);
// 每个客户端分发一个token
private String token = "";
// 存放所有的连接
private static HashMap<String, Session> map = new HashMap<>();
// 连接成功
@OnOpen
public void onOpen(Session session, @PathParam("token") String token) {
map.put(token, session);
this.token = token;
LOGGER.info("新连接: [token]: {},[session-id]: {},总连接数: {}",
token, session.getId(), map.size());
}
// 连接关闭
@OnClose
public void onClose(Session session) {
map.remove(this.token);
LOGGER.info("连接关闭: [token]: {},[session-id]: {},总连接数: {}",
this.token, session.getId(), map.size());
}
// 连接错误
@OnError
public void one rror(Throwable throwable) {
LOGGER.error("发生错误:{}", throwable);
}
// 服务器收到消息
@OnMessage
public void onMessage(String message) {
LOGGER.info("[token] {} 收到消息: {}", this.token, message);
}
// 群发消息
public void sendInfo(String message) {
for (String token : map.keySet()) {
Session session = map.get(token);
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
LOGGER.error("[token] {} 推送消息失败: {}", token, message);
}
LOGGER.info("[token] {} 推送消息: {}", token, message);
}
}
}
前端声明ws服务器(在.env.dev
文件中)
VUE_APP_WS_SERVER=ws://127.0.0.1:8080
前端页面一打开就连接WebSocket
因此选择放在页脚的vue中实现
<script lang="ts">
import { defineComponent, onMounted } from 'vue';
import {Tool} from "@/utils/tool";
export default defineComponent({
name: 'the-footer',
setup() {
let webSocket: any;
let token: any;
const onOpen = () => {
console.log("WebSocket连接成功,状态码:", webSocket.readyState);
};
const onMessage = (e: any) => {
console.log("WebSocket收到消息:", e.data);
};
const one rror = () => {
console.log("WebSocket连接错误,状态码:", webSocket.readyState);
};
const onClose = () => {
console.log("WebSocket连接关闭,状态码", webSocket.readyState);
};
const initWebSocket = () => {
webSocket.onopen = onOpen;
webSocket.onmessage = onMessage;
webSocket.onerror = one rror;
webSocket.onclose = onClose;
};
onMounted(() => {
// 页面一打开就初始化WebSocket
if ('WebSocket' in window) {
token = Tool.uuid(10);
webSocket = new WebSocket(process.env.VUE_APP_WS_SERVER + "/ws/" + token);
initWebSocket();
// 关闭
// webSocket.close();
} else {
alert("当前浏览器不支持WebSocket");
}
});
return {
};
}
});
</script>
<style scoped>
.my-footer {
height: 70px;
background-color: #eff1f4;
display: flex;
align-items: center;
justify-content: center;
}
</style>