SpringBoot整合WebSocket实现实时通信功能
什么是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
1 2 3 4 5 6 7 | @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } |
WebSocketServer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | @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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | <!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通信的资料请关注脚本之家其它相关文章!
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
Java 必知必会的 URL 和 URLConnection使用
这篇文章主要介绍了Java 必知必会的 URL 和 URLConnection使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2019-10-10Mybatis-Plus的saveOrUpdateBatch(null)问题及解决
这篇文章主要介绍了Mybatis-Plus的saveOrUpdateBatch(null)问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2023-07-07多个springboot项目如何使用一个外部共同的application.yml
这篇文章主要介绍了多个springboot项目如何使用一个外部共同的application.yml问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-05-05
最新评论