目录
前言
本文目标springboot实现websocket通信并且实现聊天功能。
一、websockt是什么?
WebSocket 是一种在单个 TCP 连接上实现全双工通信的网络协议,旨在解决传统 HTTP 协议在实时通信场景中的局限性。
Websockt与 HTTP协议的核心区别
HTTP 是单向、无状态的请求 - 响应协议:
- 客户端必须主动发起请求,服务端才能响应,服务端无法主动向客户端推送数据;
- 每次请求都需要建立新的 TCP 连接(HTTP/1.1 虽支持长连接,但仍需客户端主动发起请求)。
而 WebSocket 实现了双向、持久的实时通信:
- 一旦连接建立,客户端和服务端可随时互相发送数据,无需频繁发起请求;
- 连接建立后保持持久,直到某一方主动关闭,大幅降低了连接开销。
二、后端代码实现
编写websocket配置类。
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
编写websocket实现类。
@Component
@ServerEndpoint("/ws/{id}")
public class WebSocket {
private static Map<String, Session> sessionMap = new HashMap<>();
@OnOpen
public void onOpen(Session session){
Map<String, List<String>> parameters = session.getRequestParameterMap();
String token = parameters.get("token").get(0);
String id = TokenUtil.webSocketGetUser(token).getId().toString();
sessionMap.put(id,session);
System.err.println(id);
}
@OnMessage
public void onMessage(String message,@PathParam("id") String id,Session session){
Map<String, List<String>> parameters = session.getRequestParameterMap(); //获取用户连接集合
String token = parameters.get("token").get(0); //通过路径携带参数获取接收者id
Integer id1 = TokenUtil.webSocketGetUser(token).getId(); //通过token获取用户id
System.out.println("收到来自客户端"+"的信息"+message+"发给"+id);
sendToOneClient(id,message);
}
@OnClose
public void onClose(Session session){
Map<String, List<String>> parameters = session.getRequestParameterMap();
String token = parameters.get("token").get(0);
String id = TokenUtil.webSocketGetUser(token).getId().toString();
sessionMap.remove(id);
}
public void sendToOneClient(String id,String message) {
Session session1 = sessionMap.get(id);
try {
session1.getBasicRemote().sendText(message);
} catch (Exception e){
e.printStackTrace();
}
}
public static void sendToAllClient(String message) {
Collection<Session> sessions = sessionMap.values();
for (Session session : sessions) {
try {
session.getBasicRemote().sendText(message);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
该实现类中接口地址:ws://xxx/ws/{id},xxx是服务(后端)的地址加上端口号,前端连接时url 参数带上 token,如:ws://127.0.0.1:8080/ws/接收方id?token=xxx。其中,id可以是任何用于区分接收方的值。
接下来介绍该实现类中的主要部分:
首先,sessionMap是静态 Map,该实例全局共享。其中,key = 用户 id 字符串,value = 当前用户的 webSocket 会话 session。它的作用是保存所有在线用户,并用来定向发消息。
接下来是几个方法的详细讲解:
@OnOpen注解的函数在客户端建立连接时触发。当客户端和该服务建立连接时,先获取客户端带过来的用户token,通过token解析用户信息(这里获取用户id,在用户登录时生成token需要使用用户id生成),随后把可以识别用户唯一标识的信息存入sessionMap。即表示该用户在线。
@OnMessage注解的函数在收到客户端消息时触发。形参中的 message 为消息内容,因此可以获取到发送人id、接收人id以及发送消息内容三样东西,可以形成一个两人聊天的闭环。其中,@PathParam("id") String id 用来获取路径中所传递的接收方id。
@OnClose注解的函数在客户端断开连接时触发。当客户端关闭 ws 连接时,解析当前用户会话的session和对应的token,并拿到用户 id,从 sessionMap 移除该 session,表示该用户下线。
最后,就是两个发送消息的函数:
第一个是 sendToOneClient,接收的参数分别为接收方id和消息内容。使用接收方id便可以在 sessionMap 中找到接收方的会话 session。调用该session的getBasicRemote().sendText() 方法就可以实现把消息发送给接收方。但是在这一步,如果接收方不在线,即 sessionMap 中没有该用户的 session,那么消息将无法送达。因此,可以在这一步之前添加其它业务的代码,如将对应的消息内容、发送方id、接收方id以及发送时间保存至数据库,实现接收方用户登录时可以查看到所收到的所有消息。
第二个是 sendToAllClient,接收的参数为消息内容。该函数会先遍历 sessionMap,随后对sessionMap 中所有的 session (所有在线用户)发送对应的消息内容。
以上是websocket的后端实现,更多的玩法,如群聊等等都可以在这些基础功能函数上进行拓展。
三、前端代码实现
代码如下:
// 替换成你的后端地址,200是接收方id
const ws = new WebSocket('ws://127.0.0.1:8080/ws/200?token=xxx');
//连接创建时调用的函数
ws.onopen = function() {
console.log('连接成功');
}
//收到消息时调用的函数
ws.onmessage = function(e) {
console.log('收到消息:', e.data);
}
//连接关闭时调用的函数
ws.onclose = function() {
console.log('连接关闭');
}
// 捕获连接过程中的异常
ws.onerror = function(err) {
console.error('错误', err);
}
//向接收方发送消息时调用的函数
function send() {
const val = document.getElementById('msg').value;
ws.send(val);
}
这段 JS 代码创建 WebSocket 实例,连接地址中指定接收方 id与身份 token。ws.onopen在 WebSocket 成功建立连接时触发,打印连接成功日志;ws.onmessage用于监听后端推送过来的消息;ws.onclose在连接关闭时执行,输出关闭日志;ws.onerror捕获连接过程中的异常并打印错误信息;自定义 send 函数读取输入框内容,通过 ws.send 把消息内容发送给后端。
总结
本文实现了前后端的 websocket 通信。希望对未来的架构师们有帮助~
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/lwj123456789123/article/details/155895068



