SpringBoot + Vue实现websocket
后端代码
pom.xml增加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
增加ServerEndpointExporter Bean
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Author zhangyugu
* @Date 2022/3/28 5:00 下午
* @Version 1.0
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
增加websocket事件的监听器和发送消息工具类 WebSocketHandler,增加该类后SpringBoot服务接收到形如 /ws/xxx 的url请求将进入如下代码逻辑。
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ServerEndpoint(value = "/ws/{token}")
@Component
public class WebSocketHandler {
static Map<String, Session> sessions = new HashMap<>();
/**
* 打开连接
* @param session
* @param token 当前登录用户的token,用于标识该连接的用户
*/
@OnOpen
public void open(Session session, @PathParam("token") String token) {
if(StringUtils.isBlank(token)) {
return;
}
sessions.put(token, session);
}
/**
* 关闭连接
* @param session
*/
@OnClose
public void close(Session session) {
Iterator<Map.Entry<String, Session>> itr = sessions.entrySet().iterator();
while(itr.hasNext()) {
Map.Entry<String, Session> entry = itr.next();
if(entry.getValue().equals(session)) {
itr.remove();
}
}
}
/**
* 收到消息
* @param session
* @param msg
*/
@OnMessage
public void onMessage(Session session, String msg) {
log.debug("getMsg from {}:{}", session.getId(), msg);
}
/**
* 发送消息的方法
* @param token
* @param msg
* @throws IOException
*/
public static void sendMsg(String token, String msg) throws IOException {
Session session = sessions.get(token);
if(session!=null) {
session.getBasicRemote().sendText(msg);
}
}
}
前端代码
<template>
<div>
<input type="text" v-model="inputMessage">
<button @click="sendMessage">发送</button>
<div>接收到消息:<br>
{{receivedMsg}}
</div>
</div>
</template>
<script>
export default {
data() {
return {
socket: null,
receivedMsg: '',
inputMessage: ''
};
},
mounted() {
// Create a new WebSocket connection
let baseUrl = "localhost:2222";
let token = "xx";//登录得到的token
this.socket = new WebSocket(`ws://${baseUrl}/ws/${token}`);
// Set up event listeners
this.socket.onopen = (event) => {
console.log('WebSocket connection opened.');
};
this.socket.onmessage = (event) => {
this.receivedMsg += event.data;
};
this.socket.onerror = (error) => {
console.error('WebSocket Error:', error);
};
this.socket.onclose = (event) => {
console.log('WebSocket connection closed.');
};
// 定时检查连接是否正常,不正常则重连
this.timer = setInterval(() => {
if (this.socket) {
if (this.socket.readyState == 1) {
try {
this.socket.send('heartbeat');
console.log('heartbeat');
} catch (err){
console.log('断线:' + err);
this.connect();
}
} else if(this.socket.readyState == 3) {
console.log('reconnect');
this.connect();
}
}
}, 10000);
},
methods: {
connect() {
// Create a new WebSocket connection
let baseUrl = "localhost:2222";
let token = "xx";//登录得到的token
this.socket = new WebSocket(`ws://${baseUrl}/ws/${token}`);
},
sendMessage() {
if (this.socket && this.inputMessage) {
this.socket.send(this.inputMessage);
this.inputMessage = ''; // Clear the input field after sending
}
}
},
beforeDestroy() {
// Close the WebSocket connection when the component is destroyed
if (this.socket) {
this.socket.close();
}
if (this.timer) {
clearInterval(this.timer);
}
}
};
</script>