SpringBoot整合WebSocket实现实时通信功能
作者:fking86
什么是WebSocket?
WebSocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP请求-响应模式不同,WebSocket允许服务器主动向客户端推送数据,实现了实时通信的功能。WebSocket协议基于HTTP协议,通过在握手阶段升级协议,使得服务器和客户端可以直接进行数据交换,而无需频繁的HTTP请求。
Spring Boot中的WebSocket支持
Spring Boot提供了对WebSocket的支持,通过集成Spring WebSocket模块,我们可以轻松地实现WebSocket功能。在Spring Boot中,我们可以使用注解来定义WebSocket的处理器和消息处理方法,从而实现实时通信。
WebSocket和HTTP优劣势
WebSocket的优势:
1.实时性:
WebSocket是一种全双工通信协议,可以实现服务器主动向客户端推送数据,实现实时通信。相比之下,HTTP是一种请求-响应模式 的协议,需要客户端主动发起请求才能获取数据。
2.较低的延迟:
由于WebSocket使用单个TCP连接进行通信,避免了HTTP的握手和头部信息的重复传输,因此具有较低的延迟。
3.较小的数据传输量:
WebSocket使用二进制数据帧进行传输,相比于HTTP的文本数据传输,可以减少数据传输量,提高传输效率。
4.更好的兼容性:
WebSocket协议可以在多种浏览器和平台上使用,具有较好的兼容性。
HTTP的优势:
1.简单易用:
HTTP是一种简单的请求-响应协议,易于理解和使用。相比之下,WebSocket需要进行握手和协议升级等复杂操作。
2.更广泛的应用:
HTTP协议广泛应用于Web开发中,支持各种类型的请求和响应,可以用于传输文本、图片、视频等多种数据格式。
3.更好的安全性:
HTTP协议支持HTTPS加密传输,可以保证数据的安全性。
综上,WebSocket适用于需要实时通信和较低延迟的场景,而HTTP适用于传输各种类型的数据和简单的请求-响应模式。在实际应用中,可以根据具体需求选择合适的协议。
示例
版本依赖
模块 | 版本 |
---|---|
SpringBoot | 3.1.0 |
JDK | 17 |
代码
WebSocketConfig
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
WebSocketServer
@Component @ServerEndpoint("/server/{uid}") @Slf4j public class WebSocketServer { /** * 记录当前在线连接数 */ private static int onlineCount = 0; /** * 使用线程安全的ConcurrentHashMap来存放每个客户端对应的WebSocket对象 */ private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>(); /** * 与某个客户端的连接会话,需要通过它来给客户端发送数据 */ private Session session; /** * 接收客户端消息的uid */ private String uid = ""; /** * 连接建立成功调用的方法 * @param session * @param uid */ @OnOpen public void onOpen(Session session, @PathParam("uid") String uid) { this.session = session; this.uid = uid; if (webSocketMap.containsKey(uid)) { webSocketMap.remove(uid); //加入到set中 webSocketMap.put(uid, this); } else { //加入set中 webSocketMap.put(uid, this); //在线数加1 addOnlineCount(); } log.info("用户【" + uid + "】连接成功,当前在线人数为:" + getOnlineCount()); try { sendMsg("连接成功"); } catch (IOException e) { log.error("用户【" + uid + "】网络异常!", e); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if (webSocketMap.containsKey(uid)) { webSocketMap.remove(uid); //从set中删除 subOnlineCount(); } log.info("用户【" + uid + "】退出,当前在线人数为:" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 * @param session 会话 */ @OnMessage public void onMessage(String message, Session session) { log.info("用户【" + uid + "】发送报文:" + message); //群发消息 //消息保存到数据库或者redis if (StringUtils.isNotBlank(message)) { try { //解析发送的报文 ObjectMapper objectMapper = new ObjectMapper(); Map<String, String> map = objectMapper.readValue(message, new TypeReference<Map<String, String>>(){}); //追加发送人(防止串改) map.put("fromUID", this.uid); String toUID = map.get("toUID"); //传送给对应的toUserId用户的WebSocket if (StringUtils.isNotBlank(toUID) && webSocketMap.containsKey(toUID)) { webSocketMap.get(toUID).sendMsg(objectMapper.writeValueAsString(map)); } else { //若果不在这个服务器上,可以考虑发送到mysql或者redis log.error("请求目标用户【" + toUID + "】不在该服务器上"); } } catch (Exception e) { log.error("用户【" + uid + "】发送消息异常!", e); } } } /** * 处理错误 * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error("用户【" + this.uid + "】处理消息错误,原因:" + error.getMessage()); error.printStackTrace(); } /** * 实现服务器主动推送 * @param msg * @throws IOException */ private void sendMsg(String msg) throws IOException { this.session.getBasicRemote().sendText(msg); } /** * 发送自定义消息 * @param message * @param uid * @throws IOException */ public static void sendInfo(String message, @PathParam("uid") String uid) throws IOException { log.info("发送消息到用户【" + uid + "】发送的报文:" + message); if (!StringUtils.isEmpty(uid) && webSocketMap.containsKey(uid)) { webSocketMap.get(uid).sendMsg(message); } else { log.error("用户【" + uid + "】不在线!"); } } private static synchronized int getOnlineCount() { return onlineCount; } private static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } private static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }
WebSocketController
@RestController public class WebSocketController { @GetMapping("/page") public ModelAndView page() { return new ModelAndView("webSocket"); } @RequestMapping("/push/{toUID}") public ResponseEntity<String> pushToClient(String message, @PathVariable String toUID) throws Exception { WebSocketServer.sendInfo(message, toUID); return ResponseEntity.ok("Send Success!"); } }
webSocket.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>WebSocket消息通知</title> </head> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script> <script> var socket; //打开WebSocket function openSocket() { if (typeof (WebSocket) === "undefined") { console.log("您的浏览器不支持WebSocket"); } else { console.log("您的浏览器支持WebSocket"); //实现化WebSocket对象,指定要连接的服务器地址与端口,建立连接. var socketUrl = "http://localhost:8080/socket/server/" + $("#uid").val(); //将https与http协议替换为ws协议 socketUrl = socketUrl.replace("https", "ws").replace("http", "ws"); console.log(socketUrl); if (socket != null) { socket.close(); socket = null; } socket = new WebSocket(socketUrl); //打开事件 socket.onopen = function () { console.log("WebSocket已打开"); //socket.send("这是来自客户端的消息" + location.href + new Date()); }; //获得消息事件 socket.onmessage = function (msg) { console.log(msg.data); //发现消息进入,开始处理前端触发逻辑 }; //关闭事件 socket.onclose = function () { console.log("WebSocket已关闭"); }; //发生了错误事件 socket.onerror = function () { console.log("WebSocket发生了错误"); } } } //发送消息 function sendMessage() { if (typeof (WebSocket) === "undefined") { console.log("您的浏览器不支持WebSocket"); } else { console.log("您的浏览器支持WebSocket"); console.log('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}'); socket.send('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}'); } } </script> <body> <p>【uid】: <div><input id="uid" name="uid" type="text" value="1"></div> <p>【toUID】: <div><input id="toUID" name="toUID" type="text" value="2"></div> <p>【Msg】: <div><input id="msg" name="msg" type="text" value="hello WebSocket2"></div> <p>【第一步操作:】: <div> <button onclick="openSocket()">开启socket</button> </div> <p>【第二步操作:】: <div> <button onclick="sendMessage()">发送消息</button> </div> </body> </html>
测试
打开2个页面
第一个:
http://localhost:8080/socket/page
第二个:
http://localhost:8080/socket/page
都点击开启socket
都点击发送
至此示例发送完成
总结
通过本文的介绍,我们了解了Spring Boot中如何集成WebSocket,实现实时通信的功能。
WebSocket作为一种高效的实时通信协议,为开发者提供了更好的用户体验和交互性。
希望本文能够帮助快速掌握Spring Boot整合WebSocket的方法,为应用程序添加实时通信功能。
以上就是SpringBoot整合WebSocket实现实时通信功能的详细内容,更多关于SpringBoot WebSocket通信的资料请关注脚本之家其它相关文章!