spring中利用websocket打造最简易的双向通讯
首先引入pom,该pom根据spring-boot的版本自动选择
fastjson用于将websocket传输的消息体序列化为对象
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.50</version>
</dependency>
新建WebSocketServer.java
① @ServerEndpoint标注对应websocket的链接地址,如以下前端通过ws://localhost:8080/test/1
连接
② onlineSessionClientMap存储当前在线客户端集合
@ServerEndpoint(value = "/test/{id}")
@Slf4j
@Component
public class WebSocketServer {
//在线客户端集合
private static final Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();
/**
* 连接创建成功
*
* @param id
* @param session
*/
@OnOpen
public void onOpen(@PathParam("id") String id, Session session) {
System.out.println("开启连接" + id);
onlineSessionClientMap.put(id, session);
}
/**
* 连接关闭回调
*
* @param id
* @param session
*/
@OnClose
public void onClose(@PathParam("id") String id, Session session) {
//从map集合中移除
System.out.println("断开连接" + id);
onlineSessionClientMap.remove(id);
}
/**
* 收到消息后的回调
*
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
Message msg = JSONObject.parseObject(message, Message.class);
if (msg != null && msg.getTo() != null) {
Session fromSession = onlineSessionClientMap.get(msg.getFrom());
if (fromSession != null) {
// 前端会通过JSON.parse解析message
fromSession.getAsyncRemote().sendText(message);
}
Session toSession = onlineSessionClientMap.get(msg.getTo());
if (toSession != null) {
toSession.getAsyncRemote().sendText(message);
}
}
}
/**
* 发生错误时的回调
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
}
}
以上的消息实体Message如下
创建Message.java,利用lombok快速生成构造方法,以及get,set方法。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
// 发送方
private String from;
// 接收方
private String to;
// 消息内容
private String content;
}
现在已经完成了基础内容的接收发送,需要将WebSocketServer装配到Spring当中。
新建WebConfig.java
@Configuration
public class WebConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
ServerEndpointExporter exporter = new ServerEndpointExporter();
exporter.setAnnotatedEndpointClasses(WebSocketServer.class);
return exporter;
}
}
完工~接下来看前端部分
我的vue3项目已经装好antdesign-for-vue
看代码
<script setup>
const route = useRoute()
// route.params.id 获取路由上的参数
const es = new WebSocket('ws://localhost:8080/test/' + route.params.id)
es.onopen = function (e) {
console.log('连接成功', e);
}
es.onerror = function (e) {
console.log('连接失败', e);
}
es.onclose = function (e) {
console.log('连接关闭', e);
}
es.onmessage = function (e) {
msgList.value.push(JSON.parse(e.data))
}
const inputValue = ref('')
const toValue = ref('')
const send = () => {
// 后端定义的Message消息体是这样子的
es.send(JSON.stringify({
from: route.params.id,
to: toValue.value,
content: inputValue.value
}))
inputValue.value = ''
}
const close = () => {
es.close()
}
const msgList = ref([])
</script>
<template>
<div class="h-64">
<p>收到消息:</p>
<p v-for="msg in msgList">{{ msg.from }}说:{{ msg.content }}</p>
</div>
<a-space>
<a-input v-model:value="inputValue" @keydown.enter="send"></a-input>
<a-input class="w-10" v-model:value="toValue"></a-input>
<a-button type="primary" @click="send">发送</a-button>
<a-button type="primary" @click="close">关闭</a-button>
</a-space>
</template>
启动项目,打开http://localhost:5173/#/test/1
路由自己配置,主要为了获取路由上的参数,界面如下
再打开一个页面http://localhost:5173/#/test/2
假设参数为1的要给参数为2的发送实时消息,输入发送内容,发送目标填2
发送之后1和2会看到如下
切换到2,也发送消息
到此,最简易版本的双向通讯搭建完成。