SpringBoot整合WebSocket实现聊天室流程全解
作者:欲无缘
WebSocket协议是基于TCP的一种新的网络协议。本文将通过SpringBoot集成WebSocket实现简易聊天室,对大家的学习或者工作具有一定的参考学习价值,感兴趣的可以了解一下
什么是WebSocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebSocket通信模型
为什么需要WebSocket
http 通信是单向的,发送请求获取响应,没有请求也就没有响应。
简单理解:
- HTTP 打电话:客户端问一句服务端答一句
- WebSocket 打电话:双向对话
Websocket与http的关系
相同点:
- 都是基于tcp的,都是可靠性传输协议
- 都是应用层协议
不同点:
- WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息
- HTTP是单向的
- WebSocket是需要浏览器和服务器握手进行建立连接的而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接。
SpringBoot集成WebSocket
maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
WebSocketConfig
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
WebSocketService
@Slf4j @Service @ServerEndpoint(value = "/myService/{userId}") public class WebSocketService { /** * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 */ private static AtomicInteger onlineCount = new AtomicInteger(0);; /** * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 */ private static ConcurrentHashMap<String,WebSocketService> webSocketMap = new ConcurrentHashMap<>(); /** * concurrent包的线程安全Set,用来存放每个客户端对应的session对象。 */ private static ConcurrentHashMap<String,Session> sessionMap = new ConcurrentHashMap<>(); /** * 与某个客户端的连接会话,需要通过它来给客户端发送数据 */ private Session session; private String userId = ""; /** * 连接建立成功调用的方法 */ @OnOpen public void onOpen(Session session,@PathParam("userId") String userId) { this.session = session; this.userId = userId; if(webSocketMap.containsKey(userId) && sessionMap.containsKey(userId)){ webSocketMap.remove(userId); sessionMap.remove(userId); sessionMap.put(userId,session); webSocketMap.put(userId,this); }else{ webSocketMap.put(userId,this); sessionMap.put(userId,session); addOnlineCount(); } log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount()); } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if(webSocketMap.containsKey(userId)){ webSocketMap.remove(userId); subOnlineCount(); } log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 */ @OnMessage public void onMessage(String message, Session session) { this.session = session; log.info("收到客户端消息 -> {}",message); //服务端收到客户端的消息并推送给客户端 sendMessage(message); } /** * 发生错误时调用 */ @OnError public void onError(Session session, Throwable error) { log.error(error.getMessage()); } /** * 实现服务器主动推送 可以通过controller调用此方法实现主动推送 */ public void sendMessage(String message){ try { Set<Map.Entry<String, Session>> entries = sessionMap.entrySet(); for (Map.Entry<String, Session> next : entries) { Session session = next.getValue(); session.getBasicRemote().sendText(this.userId + "说" + message); } } catch (IOException e) { log.error(e.getMessage()); } } public static synchronized int getOnlineCount() { return onlineCount.get(); } public static synchronized void addOnlineCount() { WebSocketService.onlineCount.getAndIncrement(); } public static synchronized void subOnlineCount() { WebSocketService.onlineCount.getAndDecrement(); } }
WebSocket.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>websocket通讯</title> </head> <body> <p>userId:<input id="userId" name="userId" type="text" value="10"></p> <p>msg:<input id="contentText" name="contentText" type="text" value="hello websocket"></p> <p>操作:<button onclick="openSocket()">开启socket</button></p> <p>操作:<button onclick="sendMessage()">发送消息</button></p> </body> <script type="application/javascript"> let socket; function openSocket() { if(socket != null){ socket.close(); socket = null; } let userId = document.getElementById('userId').value socket = new WebSocket("ws://localhost:9000/myService/"+userId); //打开事件 socket.onopen = function() { console.log("websocket已打开"); }; //获得消息事件 socket.onmessage = function(msg) { console.log(msg.data); }; //关闭事件 socket.onclose = function() { console.log("websocket已关闭"); }; //发生了错误事件 socket.onerror = function() { console.log("websocket发生了错误"); } } function sendMessage() { let contentText = document.getElementById('contentText').value socket.send(contentText); } </script> </html>
测试
到此这篇关于SpringBoot整合WebSocket实现聊天室流程全解的文章就介绍到这了,更多相关SpringBoot WebSocket聊天室内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!